
Ruby is not a callable orientated language - adam-_-
http://yehudakatz.com/2010/02/21/ruby-is-not-a-callable-oriented-language/
======
blasdel
This is something that pisses me off about Ruby -- it has _four_ goddamn
callable types [Methods, Procs, Blocks, Lambdas] that all turn into one
another at different points, but you still can't pass around non-anonymous
callables directly!

I really love how Python's approach is structured: Methods are just Functions
accessed as properties of an instance Object. Lambda expressions just return a
normal Function. Functions are just Objects with a __call__ method,
metacircularly. It's turtles all the way down!

In Python I implement __call__ methods in Classes and add instance properties
as metadata on function objects _all the time_. In Ruby it seems like I always
have to wrap a callable in another callable to be able to pass it around
without accidentally calling it -- goddamn no-paren calling! At least lisps
have quote operators to solve this problem transparently.

Ruby's block syntax is rather nice, it just solves a completely different
problem: you don't actually use it to make functions to pass around as objects
-- you're really using it to make control structures directly.

~~~
carbon8
_"it has four goddamn callable types [Methods, Procs, Blocks, Lambdas] that
all turn into one another at different points, but you still can't pass around
non-anonymous callables directly!"_

Aside from the errors in this sentence (blocks, procs and lambdas are all just
Proc objects, and you can pass around methods using method(:method_name)),
assuming that passing around methods is supposedly common really betrays a
python-centric point of view.

In Ruby, passing around methods by name is very uncommon. Running ack through
407 gems I see 116 instances of it, period. That's 116 times in some huge
number of lines of ruby code that someone typed method(:some_method).

It's clear why this wouldn't be a common thing in Ruby: all of the Proc types
are flexible enough that it's rarely necessary to pass around methods. I find
it incredibly hard to believe that people who complain about this are actually
encountering this while using Ruby as Ruby.

~~~
arohner
"Aside from the errors in this sentence (blocks, procs and lambdas are all
just Proc objects"

No, they're different: <http://innig.net/software/ruby/closures-in-ruby.rb>

~~~
carbon8
They are indeed all Proc objects:

    
    
        Proc.new {}.class
        => Proc
        lambda {}.class
        => Proc
        proc {}.class
        => Proc
        def block_class(&block) block.class end
        block_class {}
        => Proc
    

That write-up does have some great info in it, though.

Edit: there's an interesting comment on wycats' post that suggests the &block
creates a Proc, and that blocks themselves are neither objects nor callable,
ie, they can only be used directly with yield. That makes sense.

Even in that case, the original point still stands; we're still only dealing
with Methods and Procs.

~~~
arohner
My link empirically demonstrates that all 7(!) constructs behave differently,
regardless of what foo.class says. I personally have been burned by the
differences between them, so I'll continue to support people differentiating
between them, even if the interpret lies.

~~~
carbon8
_"My link empirically demonstrates that all 7(!) constructs behave
differently"_

It explicitly doesn't. Read it again. Immediately after listing his 7
constructs he points out that a number of them are actually the same thing,
and in the summary he clearly explains that there are only 4 different
behaviors. His 7 constructs (which include methods and bare blocks) are
actually only 3 or, arguably, 3.5/4 (his numbers in parens):

blocks, which aren't callable without being wrapped in a Proc in CRuby (1, 2)

Procs (two types: Proc.new/&block and lambda) (3, 4, 5, 6)

methods (7)

There two types of Procs, plain procs and lambda, with lambda's differences
being how it checks arguments and its return behavior, as I noted yesterday in
another comment in this discussion
(<http://news.ycombinator.com/item?id=1141030>).

So, again, the original comment, "four goddamn callable types [Methods, Procs,
Blocks, Lambdas]," neglects the fact that #call on the last three is actually
just Proc#call.

------
alextgordon
tl;dr: The problem is that if () were to call blocks, then this

    
    
        def foo
          proc {}
        end
        
        foo()
    

...would be ambiguous. Is it a call of foo returning a block, or a call of foo
returning a block and calling that block?

To "fix" this you'd have to require parens when calling all functions, since
you have no way of knowing whether the function returns a block or not. The
other option is only allowing parens to call blocks at certain times and not
at others - certainly confusing!

~~~
viraptor
I'm not sure why people say that. It seems obvious. What optional '()' needs
to achieve is:

    
    
        def a
          42
        end
    
        a => 42
        a() => 42
    

So the grammar could use something like:

    
    
        call = expression '(' ... ')'
        call_or_variable = expression
    

it cannot be reversed really, because then it would match `call_or_variable`
'(' ')' - which would make `a()` fail to run, because 42 is not callable (or
you'd have to use backtracking and guessing... evil).

It cannot be the case of "no way of knowing", because at parsing time in
dynamic language you don't know what the result of a function is - you only
look at grammar. So in the simplest possible way, if the '()' is optional,
then... I'm not sure how to call it, but let's say - '()' binds stronger than
'possible application':

    
    
        foo => call foo
        foo() => call foo
        foo()() => call proc

~~~
wycats
foo()() doesn't seem better than foo.call

------
richcollins
Io presents an interesting alternative. There are only Blocks (functions with
assignable scope). Blocks have an activatable slot. If you set it to true, the
block is activated when an object receives a message that looks up the slot
with the block. If false, it returns the block.

    
    
        sayHello := block(“hello” println)
        sayHello //returns the block
        sayHello setIsActivatable(true)
        sayHello //prints “hello”
        getSlot(“sayHello”) //returns the block
    

[http://www.iolanguage.com/scm/git/checkout/Io/docs/IoGuide.h...](http://www.iolanguage.com/scm/git/checkout/Io/docs/IoGuide.html#Objects)

~~~
gfodor
Whoa. So much for the principle of least surprise!

~~~
richcollins
In practice, Io does follow the principle of least surprise. By default,
blocks aren't activatable and methods are.

~~~
gfodor
I'm talking about a higher meta-level: to me, it's surprising that the
language semantics of what it means to simply type an identifier of a function
change based upon the runtime state of the program. This seems crazy to me,
it's like A New Kind of Side Effect I'd never seen before.

~~~
richcollins
This is called late binding, and it allows you more flexibility and
productivity if you're willing to accept fewer constraints.

Its actually quite powerful and allows some things that make Io a joy to work
with. Memoization for instance:

    
    
        foo := method(foo = performSomeBigCalculation)

------
hvs
Hmm, I was unaware that Ruby worked that way. I'm not one to say that this is
"bad" or "good" -- since I haven't used Ruby much -- but it seems
unnecessarily confusing, even if it is consistent.

