6 ms·
Ruby is not a callable orientated language
- blasdel 17y agoThis 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.
- jameskilton 17y agoWrong. Ruby code blocks can be Methods, Procs or Lambdas. Methods are the hard-coded blocks of code on a Class or a Module (or in the global space, which actually is in the Kernel module). A "block" is simply a contained/scoped bit of code. Procs and Lambdas exist because they exhibit different scoping rules. If you want local scoping only, use a lamdba. If you want access to information outside the block, use a proc. Of course, your rant sure sounds like you didn't actually read Katz's blog post, or you wouldn't be using terms like "callable types." The post explains exactly WHY Ruby doesn't have an equivalent __call__ structure...
- blubb 17y ago>> lambda {} == proc {} => true Can you shed some light on the difference? I always thought that lambda is simply a synonym for proc - has this changed in more recent versions?
- carbon8 17y agoSee here: http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ http://www.robertsosinski.com/2008/12/21/understanding-ruby-... Proc objects created with lambda check arguments and have "diminutive return" so they behave as anonymous methods. Also, Kernel#proc is an alias to Kernel#lambda, so the only way you get the bare Proc behavior is by calling Proc.new directly.
- blubb 17y agoAh, I didn't know that Proc.new != proc/lambda :) They both return Proc objects though, so I wonder if it is possible to "convert" them.
- carbon8 17y agoOne small note, as pointed out in http://innig.net/software/ruby/closures-in-ruby.rb http://innig.net/software/ruby/closures-in-ruby.rb posted by arohner above: although in 1.8 proc is an alias for lambda, in 1.9 it's now an alias for Proc.new.
- FooBarWidget 17y agoThe empty lambda or empty proc is a special object that always points to the same instance. Probably some kind of optimization.
- cubicle67 17y agoIt's probably just because it's late here, and I'm over tired, but I'm having a real hard time understanding your complaint. Are you able to provide some examples please?
- FooBarWidget 17y agoWhat exactly is your complaint about Ruby? Yeah they are different types but they all respond to #call. How is this less structured than Python? Can't pas around non-anonymous callables directly? method(:function_name)?
- viraptor 17y ago[self-delete] - seems I was thinking about something different than OP.
- FooBarWidget 17y agoWhy does the type matter? Ruby apps extensively use duck typing, they only care that #call is implemented irregardless of the actual type. Even blasdel is duck typing by implementing __call__ in his own classes. > In most situations if you saw 4 classes in the system doing virtually the same thing, but you need to use a specific one depending on context You don't need to use a specific one. You never directly instantiate a Method/Proc/etc. Instead of you just focus on the goal you want to achieve (e.g. passing an object's method, or maybe some kind of callable object that you received via an argument) and then Ruby gives you an object of some type that works. > You just expect to call .get_address(), but suddenly find out that one of them handles only .get_customer_address(). This does not apply to Ruby. Method and Proc (actually I think there are only Method and Proc, not 4 classes as the grandparent suggested) both respond to #call. They are not two distinct types that behave completely different, they behave the same from the point of view of the caller and just have different names. Given a function that expects a Method or a Proc, you can pass either a Method or a Proc and it always works.
- natrius 17y agoDon't delete comments. Just edit them and note that you were wrong, or reply to the comment that corrected you.
- dazmax 17y agoYou didn't address the point of the article: Ruby is optimized for the common case. Yes, I too like the idea of how pure Python's approach is, but look at your code; you are mostly writing methods. They should be primitive. Ruby gets a little messy, but it does it for you, so you can write cleaner code. As for those four types, methods are one of the central pillars of Ruby, they are more than functions and they deserve their own type. Blocks are not a type, that's a common confusion. Lambdas are just what you'd expect, and more powerful than Python lambdas. Procs are there to support block syntax, again for convenience in the common use case, because if you used lambdas for blocks you wouldn't be able to return out of a method while inside a block such as a loop.
- blubb 17y agoThere is no special block or lambda type in Ruby, AFAIK there is just proc and method. The difference is simple, a method is a proc that will be evaluated in the context of its object. I don't know why you're having a problem passing around foo = lambda {|x,y,z| x+y+z }. I admit that having to explicitly call a proc using .call or .[] is less pretty than the python equivalent, but it's hardly a big problem. Having used both Python and Ruby extensively I've concluded that both languages are very nice and usable. They both have their warts and shortcomings, but after Python added closures I really haven't had many "darn, I hate [Ruby|Python] because of shortcoming X". Edit: As noted elsewhere, there IS in fact a difference between Proc.new and lambda/proc, Though I've personally never used Proc.new.
- deleted 17y ago[deleted]
- deleted 17y ago[deleted]
- carbon8 17y ago"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 17y ago"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 http://innig.net/software/ruby/closures-in-ruby.rb
- carbon8 17y agoThey 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 17y agoMy 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.
- alextgordon 17y agotl;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!
- labria 17y agoIf we were to make () call blocks, then we would have to make ()'s in function calls mandatory, so that we would get something like foo()() to call the function _and_ the block.
- viraptor 17y agoI'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 17y agofoo()() doesn't seem better than foo.call
- hvs 17y agoHmm, 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.
- richcollins 17y agoIo 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.html#Objects http://www.iolanguage.com/scm/git/checkout/Io/docs/IoGuide.h...
- gfodor 17y agoWhoa. So much for the principle of least surprise!
- richcollins 17y agoIn practice, Io does follow the principle of least surprise. By default, blocks aren't activatable and methods are.
- gfodor 17y agoI'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 17y agoThis 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)
- awt 17y agoIo rocks :)