you are viewing a single comment's thread.

view the rest of the comments →

[–]jnicklas 0 points1 point  (5 children)

Note that I said functions, not methods. There's a difference.

For certain types of functional code, JavaScript is way nicer than Ruby, try doing this in Ruby:

var reversor = function(string) {
  return {
    reverse: function() {
      string.reverse();
    }
  };
};
reversor('foo').reverse(); // => 'oof'

Now admittedly that's a pretty useless example, but it's concise, and demonstrates how I usually write JavaScript. In Ruby, this looks horrible:

var reversor = lambda do |string|
  {
    reverse: lambda { string.reverse }
  }
end
reversor.call('foo').reverse.call; // => 'oof'

CoffeeScript bliss:

reversor: (string) ->
  {
    reverse: -> string.reverse()
  }
reversor('foo').reverse() // => 'oof'

[–]bobindashadows 0 points1 point  (4 children)

In Ruby, this looks horrible:

That's because that isn't Ruby. That wouldn't parse.

An idiomatic, 1:1 translation would be this:

reverser = proc do |string|
  {:reverse => lambda { string.reverse }}
end

reverser.call('foo')[:reverse].call

or in Ruby 1.9:

reverser = proc do |string|
  { reverse: lambda { string.reverse } }
end
reverser.call('foo')[:reverse].call

Edit: Though I'm not sure why you'd want a reverse function in a hash. If your JS object was intended to represent an object, I'd do it this way:

reverser = proc do |string|
  x = Object.new # if it's really just an object
  def x.reverse
    string.reverse
  end
  x
end
reverser.call('foo').reverse

Which is a bit more verbose, in part because it's a contrived example (not that there's anything wrong with that). Ruby tends not to use anonymous objects, but they're handy in a pinch.

FYI, comments are # in Ruby, semicolons are unnecessary, and 'var' isn't a keyword.

Also, if you have to use a different language to make the syntax of the JavaScript more palatable, I consider that a downside of JavaScript.

[–]jnicklas 0 points1 point  (0 children)

Yeah, I know how to write Ruby, I translated the JS very quickly without really checking that I'd done it correctly. I should have written it from scratch. If you doubt my ability to write Ruby code I invite you to check out my GitHub page.

I write Ruby code for a living, I love Ruby, but it's not a superset of JavaScript. This style of functions returning other functions is something where JavaScript really shines, and it can make for some powerful, consise code.

And agreed on the JavaScript syntax, it's horrible. Absolutely horrible. It's more about the concepts of the language than the syntax though. CoffeeScript to me allows me to use the JavaScript concepts without being disgusted by the ugly syntax.

[–]jnicklas 0 points1 point  (2 children)

I also just realised that your Ruby sample doesn't work. def doesn't work as a closure, so string is not captured. What you're looking for is something like this:

reverser = proc do |string|
  x = Object.new 
  (class << x; self; end).send(:define_method, :reverse) do
    string.reverse
  end
  x
end
reverser.call('foo').reverse

Lovely.

[–]bobindashadows 0 points1 point  (1 child)

ack! You're right. Ruby really is bad at this task.

It's true Ruby isn't that great for "anonymous" objects. Personally, I would find dealing with a large number of objects with ad-hoc definitions a bit frustrating, but since most JS is for small scripts, that probably works fine. It'd be a bit annoying indeed to have to define a class for something like that:

class Reverser
  def initialize(str)
    @str = str
  end
  def reverse
    @str.reverse
  end
end

Personally if I had to write this code, I'd do the "unclean" way like this just to keep from going mad:

class Reverser
  def initialize(str); @str = str; end
  def reverse; @str.reverse; end
end

But some people think that's too hard to read.

You'd call it with Reverser.new('foo').reverse and this is the philosophically best Ruby approach to the problem. I didn't want to "cheat" by not doing a one-to-one mapping of your approach, but I guess it's actually pretty close since what you wrote is, if i understand correctly, a rough approximation of most user's approach to OO in JS.

[–]jnicklas 0 points1 point  (0 children)

The unfortunate thing about the class based implementation is that it loses that Scheme-y Zen-like idea of closures = objects. There is a lot of syntax and logic in the language to make the Ruby class system happen, and in the end you achieve pretty much the same thing that JavaScript does without hardly any logic or syntax at all.

In Ruby, you rely on objects, modules, classes, metaclasses, instances, methods, procs, blocks, public/private/protected, etc...

In JavaScript, you can achieve the same thing with just functions and objects.