MacRuby


#1

Hi,

I am honored to announce the beginning of the MacRuby project!

MacRuby is a version of Ruby that runs on top of Objective-C. More
precisely, MacRuby is currently a port of the Ruby 1.9 implementation
for the Objective-C runtime and garbage collector.

You can learn more about the project on its homepage:

http://trac.macosforge.org/projects/ruby/wiki/MacRuby

MacRuby is still extremely experimental, but a first release is
expected very soon.

Enjoy,
Laurent


#2

MacRuby is a version of Ruby that runs on top of Objective-C. More
precisely, MacRuby is currently a port of the Ruby 1.9 implementation
for the Objective-C runtime and garbage collector.

http://trac.macosforge.org/projects/ruby/wiki/MacRuby

MacRuby is still extremely experimental, but a first release is
expected very soon.

Thanks for this job

I am very excited to test it with my new MBP.

Best Regards,

Stephane


#3

Laurent S. wrote:

Hi,

I am honored to announce the beginning of the MacRuby project!

MacRuby is a version of Ruby that runs on top of Objective-C. More
precisely, MacRuby is currently a port of the Ruby 1.9 implementation
for the Objective-C runtime and garbage collector.

How are you able to implement ObjectSpace without any impact at runtime?
Do you disable the GC while ObjectSpace is walking? If not, how do you
avoid the possibility that objects may be collected while you are
walking the heap?

  • Charlie

#4

Laurent S. wrote:

Hi,

I am honored to announce the beginning of the MacRuby project!

Can you talk about about expected performance? I imagine it’s still
early days for the project, but being based on 1.9 I’d expect
performance to be somewhat similar. However on a few quick benchmarks
I’ve run it seems there’s some degradation in MacRuby over Ruby 1.9.
Have you started to look at execution performance much yet?

  • Charlie

#5

On 2/27/08, Laurent S. removed_email_address@domain.invalid wrote:

http://trac.macosforge.org/projects/ruby/wiki/MacRuby

MacRuby is still extremely experimental, but a first release is
expected very soon.

Interesting stuff.

After reading some of the material on the macosforge wiki, I’m curious
about the keyed arguments design.

It sounds like if I invoke a method like this:

x.foo(1, bar: 2)

Then what happens is that this gets turned into an
Objective-C/Smalltalk syntax message selector of foo:bar:, but if I
use
x.foo(1, 2, bar: 3)

then it effectively uses a different selector and uses Ruby parameter
semantics with bar: 3 getting mapped into {:bar => 3} the way Ruby 1.9
does it.

So what happens if I write a ruby class like this:

class C
def foo(*a)
keywords = a.pop if Hash === a.last

end
end

And then, possibly in a separate file, write

def quack(duck) # duck might be an instance of C, but is it?
duck.foo(1, 2, bar: 3) # I guess this would work in any case.
duck.foo(1, bar: 2) # mapped to foo:bar: what does an
instance of C do with this?
end

This also seems to be treading on some of the territory which Matz has
indicated he plans to be defining in Ruby 2.0. I’m worried that
there’s a fork down the road here.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#6

On Thu, Feb 28, 2008 at 2:34 AM, Charles Oliver N.
removed_email_address@domain.invalid wrote:

Laurent S. wrote:

Hi,

I am honored to announce the beginning of the MacRuby project!

MacRuby is a version of Ruby that runs on top of Objective-C. More
precisely, MacRuby is currently a port of the Ruby 1.9 implementation
for the Objective-C runtime and garbage collector.

How are you able to implement ObjectSpace without any impact at runtime?

Because all objects are being allocated from the same memory zone, so
I just have to walk through the zone.

(See /usr/include/malloc/malloc.h for more details.)

Do you disable the GC while ObjectSpace is walking? If not, how do you
avoid the possibility that objects may be collected while you are
walking the heap?

I have been thinking of this too, it appears that the current code
path works well even if a collection occurs right in the middle.

I could nevertheless lock the GC during #each_object if there is a
problem. It doesn’t change the fact that there is no runtime penalty
by default (you can use ObjectSpace if you want). Obviously, MacRuby’s
#each_object is slower, definitely because it returns all objects from
the zone, including Objective-C objects too.

$ ruby -ve “p ObjectSpace.each_object {}”
ruby 1.8.6 (2007-09-24 patchlevel 111) [universal-darwin9.0]
310
$ /usr/local/bin/ruby -ve “p ObjectSpace.each_object {}”
MacRuby version 0.1 (ruby 1.9.0 2008-02-18 revision 0)
[i686-darwin9.2.0]
8759
$ /usr/local/bin/ruby -ve “framework ‘cocoa’; p ObjectSpace.each_object
{}”
MacRuby version 0.1 (ruby 1.9.0 2008-02-18 revision 0)
[i686-darwin9.2.0]
48425

Laurent


#7

On Thu, Feb 28, 2008 at 2:49 AM, Charles Oliver N.
removed_email_address@domain.invalid wrote:

Laurent S. wrote:

Hi,

I am honored to announce the beginning of the MacRuby project!

Can you talk about about expected performance? I imagine it’s still
early days for the project, but being based on 1.9 I’d expect
performance to be somewhat similar. However on a few quick benchmarks
I’ve run it seems there’s some degradation in MacRuby over Ruby 1.9.
Have you started to look at execution performance much yet?

Yes I have been looking at some benchmarks, a few weeks ago. In
benchmarks measuring object creation, MacRuby is slower because
allocating an object in vanilla Ruby is cheap. On the other side, GC
cycles seem to be faster.

But it’s definitely early to compare performances yet. And there are a
few things we can do in MacRuby to improve allocations, and more.

Laurent


#8

On Thu, Feb 28, 2008 at 6:33 AM, Rick DeNatale removed_email_address@domain.invalid
wrote:

You can learn more about the project on its homepage:

semantics with bar: 3 getting mapped into {:bar => 3} the way Ruby 1.9

And then, possibly in a separate file, write

def quack(duck) # duck might be an instance of C, but is it?
duck.foo(1, 2, bar: 3) # I guess this would work in any case.

True.

duck.foo(1, bar: 2)      #  mapped to foo:bar: what does an

instance of C do with this?

Here, MacRuby will check if duck responds to foo:bar:. If true, this
message is sent with 1 and 2 as arguments. If not true, the foo
message is sent instead with 1 and {:bar => 2} as arguments.

If you’re working with pure Ruby objects, the second code path should
always be taken. Unless you define foo:bar: in your Ruby class.

Note that the key:value syntax to describe a hash pair is available in
vanilla 1.9.

This also seems to be treading on some of the territory which Matz has
indicated he plans to be defining in Ruby 2.0. I’m worried that
there’s a fork down the road here.

I don’t really see this as a fork, but more as a port. Most of MacRuby
is based on 1.9, because we want to use all the upstream code base. We
just use Objective-C when it’s necessary to provide a tighter
integration with Mac OS X APIs. Because we want people to use Ruby to
write complete full Mac OS X applications, without paying the bridging
cost.

Laurent


#9

On Feb 28, 2008, at 3:40 PM, Laurent S. wrote:

I’ve run it seems there’s some degradation in MacRuby over Ruby 1.9.
Laurent

The most important thing for me re: performance in MacRuby is how
well the Ruby code performs for OS X applications, and since MacRuby
has no bridging costs the performance is exceedingly better than the
performance of bridged runtimes (like RubyCocoa).

What’s nice is you can still drop into C or Objective-C trivially with
MacRuby if performance is critical but for most application logic
MacRuby will be quick enough I think.

For server based applications that are mostly pure Ruby (like
Rails) the raw Ruby performance numbers are important, but it is early
and I think performance will pick up.

One cool thing Apple did with the MacRuby GC was have it execute
in a background native thread so garbage collection does not lock
up the program execution flow.

Rich


#10

Hi,

In message “Re: [ANN] MacRuby”
on Fri, 29 Feb 2008 05:56:41 +0900, “Laurent S.”
removed_email_address@domain.invalid writes:

|> duck.foo(1, bar: 2) # mapped to foo:bar: what does an
|> instance of C do with this?
|
|Here, MacRuby will check if duck responds to foo:bar:. If true, this
|message is sent with 1 and 2 as arguments. If not true, the foo
|message is sent instead with 1 and {:bar => 2} as arguments.
|
|If you’re working with pure Ruby objects, the second code path should
|always be taken. Unless you define foo:bar: in your Ruby class.
|
|Note that the key:value syntax to describe a hash pair is available in
|vanilla 1.9.

I still think having dedicated syntax for Objective-C call is better
than overriding normal call.

duck.foo: 1 bar: 2

or

duck.foo: 1, bar: 2

maybe? I am not sure if the parser allows this or not yet.

          matz.

#11

On 2/28/08, Laurent S. removed_email_address@domain.invalid wrote:

Note that the key:value syntax to describe a hash pair is available in
vanilla 1.9.

Yes I know, and that’s my concern about the possibility of a fork.

This also seems to be treading on some of the territory which Matz has
indicated he plans to be defining in Ruby 2.0. I’m worried that
there’s a fork down the road here.

In 1.9 Matz has basically set the caller side of keyword parameters.
What’s left for 2.0 is how to write methods that take them as a
substitute for manipulating hash parameters in the input. My concern
is that MacRuby might be going down a road which is incompatible with
the way Matz eventually goes on the receiving side.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#12

On 2/28/08, Yukihiro M. removed_email_address@domain.invalid wrote:

|always be taken. Unless you define foo:bar: in your Ruby class.

or

duck.foo: 1, bar: 2

or

duck.dispatch("foo:bar:", 1, 2)

or any other acceptable name for dispatch, which is an objective-c
flavor of send. Of course the problem with this is that MacRuby
is trying to build ruby on top of Objective-C mechanisms, rather than
the other way around.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#13

Hi,

In message “Re: [ANN] MacRuby”
on Fri, 29 Feb 2008 08:04:38 +0900, “Laurent S.”
removed_email_address@domain.invalid writes:

|> I still think having dedicated syntax for Objective-C call is better
|> than overriding normal call.
|>
|>
|> duck.foo: 1 bar: 2
|>
|> or
|>
|>
|> duck.foo: 1, bar: 2
|>
|> maybe? I am not sure if the parser allows this or not yet.
|>
|
|I have been thinking about this too, but I personally believe that it
|doesn’t reveal very pretty when messaging Objective-C methods with
|only one argument.
|
| duck.foo: 1

You can still map one-argument method to duck.foo(1) as it does now.

|But maybe we will switch to it soon, because it’s more consistent with
|Objective-C (no potential ambiguities). But it doesn’t feel very Ruby.

That is very important design decision. Objective-C-ish calling or
Ruby-ish calling. The latter makes program consistent, but the former
makes program obvious. Hmm.

          matz.

#14

On Thu, Feb 28, 2008 at 1:51 PM, Yukihiro M. removed_email_address@domain.invalid
wrote:

|message is sent with 1 and 2 as arguments. If not true, the foo

duck.foo: 1 bar: 2

or

duck.foo: 1, bar: 2

maybe? I am not sure if the parser allows this or not yet.

I have been thinking about this too, but I personally believe that it
doesn’t reveal very pretty when messaging Objective-C methods with
only one argument.

duck.foo: 1

But maybe we will switch to it soon, because it’s more consistent with
Objective-C (no potential ambiguities). But it doesn’t feel very Ruby.

Laurent


#15

On Thu, Feb 28, 2008 at 3:15 PM, Yukihiro M. removed_email_address@domain.invalid
wrote:

|> duck.foo: 1 bar: 2
|doesn’t reveal very pretty when messaging Objective-C methods with
|only one argument.
|
| duck.foo: 1

You can still map one-argument method to duck.foo(1) as it does now.

Yes, but it won’t be consistent with multiple-argument calls then.

|But maybe we will switch to it soon, because it’s more consistent with
|Objective-C (no potential ambiguities). But it doesn’t feel very Ruby.

That is very important design decision. Objective-C-ish calling or
Ruby-ish calling. The latter makes program consistent, but the former
makes program obvious. Hmm.

Definitely! I have been thinking about this a lot, but I couldn’t come
with something better than what’s currently in MacRuby.

duck.foo # may call foo
duck.foo(1) # may call foo:
duck.foo(1, key:2) # may call foo:key:

There is also the problem of defining methods with keyed arguments.
Currently:

def foo(x, key:y); end # will register foo:key:

Laurent


#16

On Feb 28, 2008, at 3:04 PM, Laurent S. wrote:

|> instance of C do with this?
available in

duck.foo: 1, bar: 2

maybe? I am not sure if the parser allows this or not yet.

I thought about working up for Objective-C calling support via this
syntax:

O[duck :foo => 1, :bar => 2]

At one point, I had a small parser change that allowed this to be
written as:

O[duck foo: 1, bar: 2]

The idea was that the rubinius compiler would detect this special form
and emit the ‘right thing’.

I think a bit part of this is whether you expect users (and other
code) to know they’re calling out to Objective-C, or if you want tight
integration. This is essential what matz says.

By making special Objective-C syntax, then you can’t pass in an
Objective-C object and expect it to be duck-typed like normal ruby
objects. But the trade off is that the syntax is less elegant. I think
it’s a trade off, and my 2 cents is you should opt for the more
elegant syntax. This is because there are only a few tiny edge cases
where the Objective-C selector matches the ruby selector, where you’d
want to allow the ObjC object to be duck typed as something else.

Thus, since the method names are so radically different, it’s better
that the user know “ok, I’m calling this other kind of method, so I
need to use this syntax.”

If they want to duck-type it, then let them write a wrapper for the
ObjC method/syntax:

def call_objc(a, b)
O[duck foo: a, bar: b]
end

Something else that has not been brought up (that I saw) is whether
ruby methods are available as Objective-C methods. Can ruby methods be
called directly via the ObjC runtime?

  • Evan

#17

On Feb 28, 2008, at 7:44 PM, Evan P. wrote:

writes:
should
duck.foo: 1 bar: 2
I thought about working up for Objective-C calling support via this
form and emit the ‘right thing’.
cases where the Objective-C selector matches the ruby selector,
where you’d want to allow the ObjC object to be duck typed as
something else.

So in your view:

O[duck foo:1, bar:2]

is elegant? Elegant Ruby? no. I agree to opt for the elegant syntax
and that’s:

duck foo:1, bar:2

Thus, since the method names are so radically different, it’s better
that the user know “ok, I’m calling this other kind of method, so I
need to use this syntax.”

The method names are not radically different all the time:

window.frame #=> NSRect

In addition, what happens when you subclass?

class MyView < NSView
def do_something_wonderful
end
end

Now I have an instance:

view = MyView.alloc.init

call a Ruby method and then an objc method

view.do_something_wonderful
frame = O[view frame]

I find that visually scary.

I think the point here is to actually unify things if possible in a
Ruby friendly way and that would be:

view.do_something_wonderful
frame = view.frame

ruby methods are available as Objective-C methods. Can ruby methods
be called directly via the ObjC runtime?

Yes, you can go the other way.


#18

On Thu, Feb 28, 2008 at 2:58 PM, Rick DeNatale removed_email_address@domain.invalid
wrote:

|If you’re working with pure Ruby objects, the second code path should
duck.foo: 1 bar: 2

You can do that right now with MacRuby.

$ /usr/local/bin/irb --simple-prompt

d = NSMutableDictionary.new
=> #NSCFDictionary:0x1641800

k = NSString.new
=> #NSCFString:0xa001b318

d.send(‘setObject:forKey:’, ‘foo’, k)
=> nil

d.objectForKey(k)
=> “foo”

(This is just an example.)

or any other acceptable name for dispatch, which is an objective-c
flavor of send.

You can also use NSObject#performSelector and its variants.

d.performSelector(:‘objectForKey:’, withObject:k)
=> “foo”

Of course the problem with this is that MacRuby
is trying to build ruby on top of Objective-C mechanisms, rather than
the other way around.

MacRuby is only trying to make the better compromise between both
languages. We could use a completely new syntax which looks like
Objective-C, but Ruby developers won’t like it, I think.

Laurent


#19

On Thu, Feb 28, 2008 at 4:44 PM, Evan P. removed_email_address@domain.invalid
wrote:

writes:
|always be taken. Unless you define foo:bar: in your Ruby class.

syntax:

Your idea is surprising, but how would you do to override an Objective-C
method?

I think a bit part of this is whether you expect users (and other
code) to know they’re calling out to Objective-C, or if you want tight
integration. This is essential what matz says.

Yes I do agree with that.

ruby methods are available as Objective-C methods. Can ruby methods be
called directly via the ObjC runtime?

In MacRuby, Ruby methods are in fact Objective-C methods, by default.
Everything is registered to the Objective-C runtime.

Calling them from Objective-C might be tricky sometimes, because Ruby
allows some characters in method names that Objective-C doesn’t. But
using the runtime API (ex. objc_msgSend) should just work.

My point is, there should not be any special syntax to call
Objective-C methods because all methods are Objective-C methods. Or at
least, no extremely special syntax.

I do like the current implemented one, as many people so far.

duck.foo 1, bar:2

A few people also like Matz’s first suggestion, which is to specify
the ‘:’ in the first part of the method call, because it’s more
consistent with the selector that will be sent.

duck.foo:1, bar:2

But so far, most of these people are Objective-C developers and not
Ruby developers.

Laurent


#20

On Thu, Feb 28, 2008 at 5:50 PM, Richard K. removed_email_address@domain.invalid
wrote:

On Feb 28, 2008, at 8:46 PM, Laurent S. wrote:

I do like the current implemented one, as many people so far.

duck.foo 1, bar:2

Oh right, duck.foo 1, bar: 2 … not duck foo:1, bar:2 :slight_smile:

Yes you can put or remove spaces, parenthesis, etc…

Alternatively, key:value can be replaced by :key => value

duck.foo 1, :bar => 2

Which is apparently more Rails’ish. (I personally prefer the first one
though.)

Laurent