function this semantics (proposal)

17 views
Skip to first unread message

Karol Bucek

unread,
Apr 24, 2012, 7:18:20 AM4/24/12
to javascript-...@googlegroups.com

 Hey, I'd like to propose a way of how JavaScript functions expose their context (this) into their Ruby implementations.

This is mostly relevant for Procs/lambdas as they in Ruby are bind to the defining context but it's fairly useful to be able to mirror JS functions with those as close as possible.

Most functions look like these:
```
function hello(name) { return 'Hello ' + name; }
```

A similar Ruby version would than look like:
```
context['hello'] = lambda { |name| "Hello #{name}" }
```

This is fine and predictable but than suppose you need to get the context passed:
```
function hello(greet) { return greet.toString() + this; }
hello.call(42, 'Hello');
```

Now for Ruby this would be possible but only if the user can guarantee there's no "surrounding" instance state accessed by the closure e.g. :
```
some = 'some'
proc = lambda { |local| "#{self}: #{some} #{local}" }
puts proc.call('another') # main: some another
puts 42.instance_exec('other', &proc) # 42: some another
```
with this case the Ruby exposed hello would look similar to the JavaScript version:
```
context['hello'] = lambda { |greet| "#{greet.to_s} #{self}" }
```

A simpler approach that would not require "instance state caution" would be to pass in this as a first argument :
```
context['hello'] = lambda { |this, greet| "#{greet} #{this}" } # self unmodified
```
but that this also comes for a price - now your lambdas do not map 1:1 with JS arguments and this is especially confusing since most of the time you do not care about the this with ("anonymous") functions ...

I'd like to propose a "choice" for users, since their in control of the context creation (or the libraries they use are), they should be able to decide which behavior they need the option name should be discussed here's a draft :

  :lambda_this_argument => :none
  :lambda_this_argument => :pass
  :lambda_this_argument => :bind

usage sample: `V8::Context.new(:lambda_this_argument => :pass) do ...`

I would expect :none ("no magic") to be the default, but than of course there's therubyracer 0.10 that already does :pass by default ...

p.s. Some bits of this discussion originally started here: https://github.com/metaskills/less-rails/pull/34

Karol Bucek

unread,
Apr 24, 2012, 8:34:18 AM4/24/12
to javascript-...@googlegroups.com

actually lamba_this_behavior  e.g. `:lamba_this_behavior => :bind` sound better

K.
Reply all
Reply to author
Forward
0 new messages