Hacker News new | ask | show | jobs
by zverok 981 days ago
> I don't find the hypothetical Ruby syntax ["hello","goodbye"].map(&reverse) to be offensive or wildly inconsistent.

This syntax wouldn't work in Ruby, because bare `reverse` is already a method call, not a reference to a method by name. Allowing method calls without parentheses is crucial to Ruby's design, where all objects are fully opaque, and every `obj.attr` looking like a getter, is just a call to an instance method `attr`. (This is, as far as I understand, the opposite to similar languages like Python/JS, where the object is a dictionary of attributes, and `obj.method` reference the attribute of type "method", while `obj.method()` is an invokation.)

This design became a huge drawback in the age of functional(ish) programming, because the simplest way for refer to a method in Ruby is `method(:its_name)` (which is also inefficient, because it creates wrapping object of class Method on the fly, there is no pre-existing first-class object), and any attempt of passing/combining methods would be cumbersome due to it.

FWIW, you can do that in Ruby:

  (JSON.method(:parse) >> method(:puts)).call("[1, 2, 3]")
...which is semantically cool, but looks ridiculous.

Another important trait of Ruby's design is that most of the important methods belong to their first argument, so it is not `reverse(string)` but `string.reverse`, so even to obtain a reference to a method, you need to have an object it belongs to! So you can't do that:

   method(:>).call(a, b)
...because all operators are called on their first operands, so you need this this:

   a.method(:>).call(b)
...which will require to refer to at least a first argument of the operator, so you can't produce "argument-less comparison operation to call later".
2 comments

This is the sort of thing I meant by "essentially immiscible". At a 30,000 foot view, yeah, it looks like lots of languages could "just" add currying.

But when you get down into the weeds of what it means, it turns out to be something you can't "just" drop in. You really need to build the syntax for it from day one.

> you can't produce "argument-less comparison operation to call later".

You absolutely can, if you know the specific one (that is, type) you need.

E.g.,

  gt = Integer.instance_method(:>).method(:bind_call)
  # gt is a two arg callable functionally equivalent to ->(a,b) { a < b } for Integer a, Any b
Of course, doing this instead of just doing:

  gt = -> { _1 > _2 }
loses Ruby duck-typing and dynamism with regard to the first parameter; which may be acceptable in some cases, but not others. Can you do the general form without an explicit lambda? Probably there is a way, but its not easy.