AlCode AlCode - 4 months ago 15
Javascript Question

Are these 2 lines of code the same ? JS vs Ruby

In ruby:

-> { 10.times {|i| puts i} }.call


Javascript:

(function (){
for (i = 0; i<10; i++){
console.log(i);
}
})()


Im coming from a JS background and something peaked my interest when learning about lambdas and Procs where it says that those are function without names which are called. That reminded me of the anonymous functions or IIFE in javascript.

Are these 2 examples the same? if not what is the difference ?

Answer

These two lines are very different in almost every aspect.

The closest ECMAScript equivalent to this Ruby snippet:

-> { 10.times {|i| puts i} }.call

would be something like this:

(() => { 10.times(i => puts(i)) }).call()

Unfortunately, numbers can't have methods in ECMAScript, so we will have to resort to something like this:

(() => { times(10, i => puts(i)) }).call()

Obviously, in order for this to work, we need to add some Ruby library support code:

(() => { times(10, i => puts(i)) }).call()

function times(i, f) { if (i-- === 0) return; else { times(i, f); f(i) }}
function puts(s) { console.log(s) }

That's still not very much alike the original Ruby semantics, but much closer than your proposal:

  • Your proposal leaks i into the global scope, the Ruby code doesn't even leak i at all, it is local to the innermost block.
  • There is no function call operator in Ruby, instead you use the method Proc#call, which ECMAScript also has (Function.prototype.call).
  • You use a for loop, whereas the Ruby code uses a method on Integer for iteration.
  • Kernel#puts will write implicitly to whatever you have defined as the default output stream, whereas your proposed ECMAScript solution will explicitly always write to the console.
  • self is lexically bound in Ruby, but this is dynamically bound to the function object itself in ECMAScript, unless you use an arrow function literal, which binds this lexixally.

On the other hand, the closest Ruby equivalent to this:

(function (){
    for (i = 0; i<10; i++){
        console.log(i);
    }
})()

Would be something like this:

-> { $i = 0; while $i < 10 do $stdout.puts($i); $i += 1 end }.()

Again, this is not 100% equivalent:

  • Ruby doesn't have a for loop (only a for … in iterator), so the closest thing is a while loop.
  • Ruby doesn't have a call operator, .() is just syntactic sugar for the call method.
  • this in a nested function expression is dynamically bound, self in Ruby is lexical.
Comments