Why Add Syntax When You Have Ruby?

A question came up this morning on the JRuby Users mailing list about a feature Jython and Groovy support: constructors that initialize bean attributes. The example given used a JLabel:

JLabel(text, bounds = bounds, foreground = color)

Which ends up being roughly equivalent to:

x = JLabel(text)
x.bound = bounds
x.foreground = color

Groovy has a similar syntax I won't illustrate here. So why doesn't Ruby support this, or perhaps why doesn't JRuby automatically support this syntax for Java types?

To answer, let's take a look at what it would take to add this to current Ruby with only existing features.

The equivalent syntax in Ruby or JRuby might look like:

SomeClass.new(text, :bounds => bounds, :foreground => foreground)

...or possibly using a block as in:

SomeClass.new(text) { @bounds = bounds, @foreground = foreground }

However there's no existing accomodation in the semantics of Ruby for these syntax to work out of the box. It would not be hard to write a short bit of code to allow constructing objects in this fashion, of course (using the block approach as an example):

class Class
def construct(*baseargs, &initializer)
x = self.new(*baseargs)
x.instance_eval(&initializer) if initializer
x
end
end

...which would allow the block example above to work fine (with "construct" in place of "new"). For proxied Java objects, which don't actually have ruby instance vars (@whatever above) it would have to be a slightly different call:

JLabel.construct(text) { self.bounds = bounds, self.foreground =
foreground }

This works fine, but it's perhaps a little less beautiful. What about this impl instead?

class Class
def construct(*baseargs)
x = self.new(*baseargs)
yield.each_pair { |k,v| x.send("#{k}=", *v) } if block_given?
x
end
end

Which would allow a variation:

JLabel.construct(text) {{ :bounds => bounds, :foreground =>
foreground }}

(the double {{}} is intentional; the block returns a hash of initializers)

The bottom line is that this kind of syntactic sugar in other languages can easily be added to Ruby through various techniques, and so features like field-initializing constructors don't need to be part of the core language or any of the implementations.

Does anyone still wonder why I love this language?
Written on September 28, 2006