1

Ruby does not have first class functions; although it has procs and lambdas, these notoriously require significant overhead. (Python has first class functions, apparently without the overhead.) It occurred me to that first class functions can be simulated with a little more work by using anonymous classes, as follows:

f = Class.new { def self.f; puts 'hi'; end }

def g(fun); fun; end

g(f.f)
# => "hi"

Does anyone know a better way?

Jordan Running
  • 102,619
  • 17
  • 182
  • 182
user5699217
  • 111
  • 1
  • 3
  • 1
    What do you mean by "better"? What are you trying to achieve? More speed, or some additional functionality? – Tom Lord Jul 13 '16 at 22:49
  • 4
    When you call `g(f.f)` in the above code, the argument you're passing to `g` is not a function. You're calling the method `f.f` and passing the result, the string `"hi"`, to `g`, which simply returns its argument. – Jordan Running Jul 13 '16 at 22:51
  • 2
    @Jordan Actually `puts` returns `nil`, so `g(f.f)` takes `nil` as the argument. – Aetherus Jul 13 '16 at 23:27
  • @Aetherus Good eye. You are correct, of course. – Jordan Running Jul 13 '16 at 23:30
  • @Jordan, you were tricked by `# => "hi"`, which normally refers to the return value. Maybe SO needs something like `#-> "hi"` for printed values. – Cary Swoveland Jul 14 '16 at 03:03
  • @muistooshort would be disappointed to learn that procs are "notorious", as he uses them for everything. – Cary Swoveland Jul 14 '16 at 03:23
  • @Jordan is of course correct. The code should read: – user5699217 Jul 16 '16 at 19:56
  • @Jordan is of course correct. The code should read: def g(fun); fun.f();end In other words, wrapping a function as a class method of an anonymous class avoids the overhead of capturing the current closure in a proc or lambda, at the cost of creating a new closure for the anonymous class, which is presumably less complex and computationally-expensive than the global closure. – user5699217 Jul 16 '16 at 20:17

2 Answers2

7

In fact, Ruby doesn't have functions at all, only methods. So if you want pass a method to another method, you can

def g(f)
  f.call
end

g('123'.method(:to_i))

This is less concise than Python, but it's the price that Ruby has to pay for the ability to omit parentheses in method calls. I think omitting parentheses is one of the things that makes Ruby shine, because this makes implementing DSL in pure Ruby a lot easier.

Aetherus
  • 8,720
  • 1
  • 22
  • 36
  • I don't understand your remark about the implemention of DSLs, but it sounds interesting--something I'll have to look into. It's perhaps worth noting that if the method is first converted to a proc, the proc can be passed to `g`: `proc = '123'.method(:to_i).to_proc #=> #; g(proc) #=> 123`. – Cary Swoveland Jul 14 '16 at 03:16
1

Ruby has procs and lambdas (both instances of the Proc class), and Methods, all of which approximate first-class functions. Lambdas are the closest to a true first-class function: they check the number of arguments when called and create a new call context such that return just returns from the lambda. In contrast, procs are just reified blocks of code; they don't check their number of arguments, and a return causes the enclosing method to return, not just the proc.

Method objects allow you to store an uncalled method in a variable, complete with implied invocant. There's no syntax for creating an anonymous Method, but you said first-class functions, not anonymous ones. Other than the invocant, they are basically lambdas whose body is that of the referenced method.

I'm not sure what an anonymous class gets you that is better than the above solutions, but it is certainly further away from a true first-class function. It's more like the way we had to approximate them in Java before closures were added to the language.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175