News for hackers. Stuff that matters.
Re:Confessions of a Ruby Developer Whose Heart was Stolen by... by csense on Thursday June 13, 2013 @07:28AM (#5873438)
What you're telling me sounds reasonable, but I thought about it some more, and these rules are so syntactically ambiguous, writing a Ruby parser should be just plain impossible!

If you can call 0-ary functions (functions which take zero arguments) without parentheses, how does Ruby know what a statement as simple as "a = b" does? It must expand internally to something like this (in Python notation):

   a = b() if b.is_function else b
But then if the b() call itself returns a function, then is that function auto-called as well? So we'd have something like this as the Python translation:

   a = b
   while a.is_function:
      a = a()
This can't be right.

And then you get syntactic ambiguities. For example, is the Python translation of the expression x = h-3 (in Ruby) equivalent to (in Python):

(A) x = h-3

(B) x = h(-3)

(C) x = h()-3

(D) x = h()()-3

(E) x = (h-3)()

(F) x = (h()-3)()

Maybe different whitespace, different compile-time definitions, or different run-time values will change the answer! And since the talk says you can monkey-patch Ruby's integer data type, you could even presumably make integers callable so things like "x = (h()-3())()" would be possible!

And then the overloading of the colon and question mark.

Is the expression "k:v" in Ruby a dictionary containing a single key, "k", which is mapped to the value "v"? Or is it a function call of a function called "k" with a single argument, ":v"?

And the ternary operator uses colons too! "a?b:c" could translate as a function called "a?b" being called with a single argument, ":c". Or a dictionary with a key "a?b" which maps to value "c". Or of course the ternary operator! And that's assuming none of the sub-expressions involved are 0-ary functions which are automagically called!

And then what if you want to disable the automagic calling and pass a function object around? Do you have to decorate it with an initial ampersand or something every time you use it? What if you have code like this that puts either a function object or an integer into a variable:

  h = flag ? (&my_function) : 5
Then you want to copy h to the variable y. If you say "y = h" then it does the wrong thing when h is a function, because then h would be auto-called. But if you use the ampersand, you do the wrong thing when h is an integer, because then you would be taking &5 and (in C notation) this would change y from being of type "int" to type "int*". Good grief!

Which all reinforces my original point: Ruby syntax is aggravating! This language is impossible to deal with!

(Sorry for the double reply, but I feel like this comment is different enough from my other reply to merit its own space.)

Re:Confessions of a Ruby Developer Whose Heart was Stolen by... by relix on Thursday June 13, 2013 @07:51AM (#5873519)
It's a common joke that Ruby is designed to make it as hard as possible for parsers.

For the code samples going forward, keep in mind that in ruby you don't need a literal return statement to return a value from a method. Just whatever value is last, is returned:

    def val
      5
    end
That method would always return 5.

> But then if the b() call itself returns a function, then is that function auto-called as well?

No, the only way to pass a method is by using method(method_name_here), which returns a Method object. To execute a Method object, you need to call call on it:

     def a
     end
     method(:a).call
So if you have a method that returns a method, it should not be automatically called, so there's no loop necessary:

     def b
       method(:a)
     end

     z = b
Then z is a Method object, namely a.

Some experiments to answer your questions (I admit I wasn't sure for all of them what the outcome would be). IRB is Ruby's repl:

    irb(main):001:0> def a
    irb(main):002:1> 5
    irb(main):003:1> end
    
    irb(main):019:0> {a: 1}
    => {:a=>1}
    irb(main):020:0> {a(): 1}
    SyntaxError: (irb):20: syntax error, unexpected ':', expecting tASSOC



    irb(main):009:0> def h(num = 10)
    irb(main):010:1> num
    irb(main):011:1> end

    irb(main):012:0> h
    => 10
    irb(main):013:0> h-3
    => 7
    irb(main):014:0> h -3
    => -3
    irb(main):015:0> h - 3
    => 7

    irb(main):001:0> a?b:c
    NameError: undefined local variable or method `c' for main:Object
Re:Confessions of a Ruby Developer Whose Heart was Stolen by... by csense on Thursday June 13, 2013 @06:30PM (#5877017)
This is really interesting. I guess some of my examples were relying on using a similar lexer as C -- which you probably couldn't in Ruby. I'll have to think some more about what a Ruby lexer would look like...

But again, it steepens the learning curve -- it's so different from other languages that it's actually kind of hard to immediately see all the implications of "well Ruby's lexer is different than C's lexer".