Alternative syntax for Methods with No Arguments

19 views
Skip to first unread message

Philipp Pirozhkov

unread,
May 14, 2012, 1:55:11 PM5/14/12
to javascript-...@googlegroups.com
Hi all,

As per https://github.com/cowboyd/therubyracer/wiki/Accessing-Ruby-Objects-From-JavaScript to distinct property accessor from a method, the method code should be wrapped by proc do :

class Mouth
  def sayHello()
    proc do
      "Hello"
    end
  end
end

There's another syntax that's not documented, but also works (therubyracer 0.10) for the same purpose:

class Mouth
  def sayHello *unused_args
    "Hello"
  end
end

cxt = V8::Context.new
cxt['mth'] = Mouth.new
cxt.eval('mth.sayHello()') # => Hello

It's a bit shorter, and doesn't restrict the use of return statement.

BR, Phil

Charles Lowell

unread,
May 14, 2012, 4:42:44 PM5/14/12
to javascript-...@googlegroups.com
I should note that ruby invocation semantics can be configured on a per-context basis, so this discussion is mainly about what the default behavior should be. Even so, this has been an issue on which I have gone back and forth on several times.

As the documentation reflects, the first pass of therubyracer and therubyrhino made you explicitly return a proc or a lambda when implementing a method in javascript.

This is the approach which keeps most strictly to the actual JavaScript mechanics in which a method is merely a property which happens to be a function. That's why this way is probably the least surprising at first, and why I chose it as a starting point.

The reason that I added the alternate syntax was because I grew tired of uglifying my Ruby code merely to accomodate JavaScript. Logically, if not structurally, a block generated in a  method is itself a method; it shares the very same binding, so why go through the ceremony of explicitly declaring it as a proc or lambda when really all you're doing is giving a hint to the JavaScript runtime about how it should be treated?

Of course there is no way to escape giving this hint in some form or another, It's just about shape it takes.

Thus far I've been pretty pleased with declaring a function property as a method that takes unused arguments. It is a little more magical that explicitly returning a proc, and it does crop up and bite you from time o time, but the behavior is predictable and the errors easy spot once you're used it, so overall I feel that it's been a good tradeoff. That said, it does seem to catch people by suprise, and indeed, some folks seem to really and truly dislike it.

Another potential solution would be to annotate the method, like:

class Mouth
  Include JS::Embedded
  function #behaves as a function no matter how many arguments
  def sayHello
"Hello"
  end
end

This is the strategy employed in Java and in Johnson (if I recall correctly). It's explicit and Ruby-esque, but feels heavy. I can still see the appeal though.

In any case, I think it's important enough that there should be some consensus about what the default behavior should be.



BR, Phil


cheers,
Charles

Charles Lowell 
thefrontside.net | twitter: @cowboyd | github: cowboyd




Karol Bucek

unread,
May 15, 2012, 7:06:33 AM5/15/12
to javascript-...@googlegroups.com

 Hey, I've polished support for this into therubyrhino and I must say I got really confused, not knowing the context, at first I've seen a method returning the result wrapped in a proc call.

The wiki page explains things deeply on this but I think it's worth a recap why such compromises exist.

In JavaScript you can distinguish a function (method) and a property easily ... if obj['foo'] is an instanceof Function (or has a typeof === 'function') than it's most likely treated as an instance method. In Ruby however when you declare an attribute the convention is to wrap it with accessor methods, thus you can't distinguish if a method is simply an attribute reader or a regular method with no arguments.

The closest I got when deciding if a given property name 'foo' resolving a no argument method should be treated as a JS attribute is the following:
- if there's 'foo=' (handles the most used attr_accessor :foo case and hand declared similars)
- no 'foo=' method but there's a @foo instance variable defined (handles attr_reader :foo cases but only if @foo has been "touched")

I personally fancy the *unused_args version and had been using it almost exclusively ever since I learned why I have to :)

I'd like Charlie's idea to declare a method as a function no matter the arguments but I'd prefer the possibility of doing it without "polluting" my Ruby, although I did not figure out a simple way yet, this comes to my mind: context['mouth'].function!(:sayHello)
Than this might introduce more issues than it solves, doing it on a class level would make more sense of course: context['Mouth'].instance_function!(:sayHello, :sayGoodbye)

K.

Charles Lowell

unread,
May 15, 2012, 11:29:17 AM5/15/12
to javascript-...@googlegroups.com
On May 15, 2012, at 6:06 AM, Karol Bucek wrote:


 Hey, I've polished support for this into therubyrhino and I must say I got really confused, not knowing the context, at first I've seen a method returning the result wrapped in a proc call.

The wiki page explains things deeply on this but I think it's worth a recap why such compromises exist.

In JavaScript you can distinguish a function (method) and a property easily ... if obj['foo'] is an instanceof Function (or has a typeof === 'function') than it's most likely treated as an instance method. In Ruby however when you declare an attribute the convention is to wrap it with accessor methods, thus you can't distinguish if a method is simply an attribute reader or a regular method with no arguments.

The closest I got when deciding if a given property name 'foo' resolving a no argument method should be treated as a JS attribute is the following:
- if there's 'foo=' (handles the most used attr_accessor :foo case and hand declared similars)
- no 'foo=' method but there's a @foo instance variable defined (handles attr_reader :foo cases but only if @foo has been "touched")

I personally fancy the *unused_args version and had been using it almost exclusively ever since I learned why I have to :)


That's my preference too, so perhaps that's what the default should should be. Perhaps what is need is a way to prepare users via good documentation.



I'd like Charlie's idea to declare a method as a function no matter the arguments but I'd prefer the possibility of doing it without "polluting" my Ruby, although I did not figure out a simple way yet, this comes to my mind: context['mouth'].function!(:sayHello)
Than this might introduce more issues than it solves, doing it on a class level would make more sense of course: context['Mouth'].instance_function!(:sayHello, :sayGoodbye)

maybe we can have it behave similarly to the public, private and module_function methods, so you only need to say it once.

class Mouth
  attr_reader :height

  javascript_function

  def chew()
    "nom. nom. "
                  end

  def sayHello()
    "hello"
  end
end

It could also be invoked either inside or outside the class like:  Mouth.javascript_function :chew, :sayHello

Is this too much effort in order to avoid declaring some unused arguments?

cheers,
Charles
Reply all
Reply to author
Forward
0 new messages