4 ms·
This is good stuff, except that he seems to misunderstand the ()-less method call in Ruby. There's no "function" or "object" being "called" with that syntax, as
by wrs 16y ago
This is good stuff, except that he seems to misunderstand the ()-less method call in Ruby. There's no "function" or "object" being "called" with that syntax, as in Pascal or Visual Basic (his chosen analogies). There are no functions in Ruby in that sense, and callable objects are explicitly called (with a "call" method). The expression "foo" in Ruby evaluates to the value of the local variable "foo" if any, or else sends the message "foo" to self and evaluates to the result. So yes, the parentheses are optional, but the ambiguity is with local variables, not with any other form of function call--so the ambiguity is hardly noticeable.
Also, the parentheses are always optional, not just for zero-argument calls, so he also missed the opportunity to discuss "poetry mode Ruby": a bunch of method calls with no parentheses. Stylistically, "poetry mode" enables the pseudo-DSL style that Ruby frameworks use frequently, but can't really be done in Python.
- cameldrv 16y agoYes, there is a semantic difference here. In Python, you can do things like this: if baz>10: func = self.foo else: func = self.bar result = func() Here func gets assigned something called a "bound method", which has a reference to the object and the method, which you can then apply the () operator and call. I am not a rubyist, but my understanding is that you would use a symbol to do a similar thing.
- rlivsey 16y agoYep, the equivalent would probably be something along the lines of: if baz > 10 func = :foo else func = :bar end result = self.send(func)
- sandal 16y agoThat may accomplish the same thing, but the direct translation would be: if baz > 10 func = method(:foo) else func = method(:bar) end result = func.call Here, we actually deal with the Method objects, rather than just sending a dynamic message. Although the send() approach would be closer to idiomatic Ruby, I wanted to emphasize that dealing with methods as first class objects in Ruby is indeed possible.
- mcantor 16y agoI HATE dealing with first class functions in Ruby. I understand that it was a design choice, but man, in Python you can pass a function or a lambda and you just don't have to worry about which one you're calling. In Ruby, () will explode on a Proc object. What is with that?!!?
- epochwolf 16y agoYou can call a proc with [] p = Proc.new {|str| puts "Hello #{str}" } p["World"] # prints "Hello World" :)
- mcantor 16y agoI'm aware of this, but it's still not (). You still must be aware that you are dealing with an unbound proc object, and it must be handled differently than usual!
- Twisol 16y agoBecause () doesn't call a method, it's simply used where a method call occurs. To call a callable object, you use #call or (as mentioned by epochwolf) #[], the latter of which I personally detest. It's fun to contrast this with Lua, by the way.
- aarongough 16y agoLua is a great little language... I only really 'discovered' it a few weeks ago and have really enjoyed what I've seen so far. I don't think it will replace Ruby for me, but I like it's minimal feel for comparison...
- mcantor 16y agoIt's the inconsistency that bothers me. In Python, you can make anything callable by providing a __call__() method, and the parentheses will work as expected. This makes functions fungible with anything, including any object or anonymous function. In Ruby, only methods are callable, and everything else must be called with the call() method, which means you can't use one in a place where the other might be expected. They're two concepts with the same verb--call--that require different syntax. It's inconsistent.
- msbarnett 16y agoYou certainly could solve that with a symbol, I suppose, but that's a bit like doing a word-for-word translation of 'it's raining cats and dogs' into a foreign language. Better to translate to the local idiom than to try to blindly write Fortran in any language, as the saying goes. So, for instance, you might solve it with: result = case when baz>10 then foo else bar end This is synthetic, of course. If the goal is to pass around methods, there are lambdas and codeblocks that can be passed around and may fit the problem more naturally than sending yourself a symbol as a message.
- spicyj 16y agoOr a slightly more direct translation is: result = if baz > 10 foo else bar end
- Dylan16807 16y agoresult = case when baz>10 then foo else bar end is a translation of if baz>10: result = self.foo() else: result = self.bar() while result = if baz > 10 foo else bar end is a translation of result = self.foo() if baz>10 else self.bar() It's true that some things have to be changed when translating, but you can't ignore the deliberate structure of the original. Let's say I want to look at how inter-sentence objects work in two languages. I give you the phrase: "Raining cats and dogs. This is what the weather is like." You can't translate it as if it said "It's raining cats and dogs" without losing the basis of comparison entirely.
- ionrock 16y agoI like your perspective on this design decision as it seems to make clear what the intent could be. Alex reveals that the difference in Python is not so much the syntax as much as it hints at Python's treatment of functions as first class objects. This is really similar to Javascript where you can pass functions around for later evaluation. It adds a different level of complexity, of course, but it is something that I have appreciated in Python a great deal.