Live data from Hacker News

Confessions of a Ruby Developer Whose Heart was Stolen by Scala

speakerdeck.com

51–60 of 74 posts

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#51

Earlier quoted context omitted.

I've been using Scala on Android + Intellij IDEA for about the past month after wanting to try something new[1]. Other than having to run it through proguard first, the compile process in Intellij is comparable to how it is with just Java. Scala plays nicely with Android and I have loved using it so far. Makes Android development a bit more fun than with just plain old Java. [1] https://github.com/yareally/android-sc…

ah - "Using proguard lets you build Scala without any extra plugins and sbt fiddling". Seems like the tooling is still one of the more painful aspects of Scala. Kudos to Intellij, -1 to Scala.

Yeah, if I had to manually fiddle around with the SBT build process and manually adding dependencies instead of letting Intellij handle it all, I would be less motivated to want to switch away from Java on Android for sure :).

Excessive configuration to get a new project up in a running is a major demotivator sometimes when you have a new idea and want to just start coding right away.

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#52
post #47
post #26

Earlier quoted context omitted.

As a Python programmer, I agree. Here's a Ruby snippet. I don't want to pick on this particular project [1], rather, I've found that this is typical of Ruby code: state_machine :state, initial: :active do after_transition any => :blocked do |user, transition| # Remove user from all projects and user.users_projects.find_each do |membership| return false unless membership.destroy end end My conclusion? Ruby's syntax is…

I'm a professional ruby programmer and your comments opened my eyes. If you don't know what's going on, then that does look like really icky code. First off, parenthesis in ruby are optional. So calling a method can be done without parenthesis. The following two lines are the same: print() print As are these: print(1, 2, 3) print 1, 2, 3 Here's some bits that might explain better what stuff does: :state If you prefix…

This may be the clearest explanation of Ruby syntax I've ever read!

My attempt to parse the above example comes to something like this:

    state_machine(STATE, {"initial" : ACTIVE}, function()
    {
        after_transition({"any" : BLOCKED}, function(user, transition)
        {
            user.users_projects.find_each(function(membership)
            {
                return (membership.destroy ? true : false);
            });
        });
    });
I'm writing in JavaScript because its function notation is way better than Python's lambda syntax. From the parent's explanation, I'm pretty sure this is a valid translation, even though I don't know Ruby. But having three levels of nested anonymous functions really makes the code hard to understand. I'm guessing that this is idiomatic Ruby though, and if you program with the pattern long enough, it gets easier.

OTOH it's still a barrier to entry entirely separate from the syntax -- if the semantics of Ruby code you see "in the wild" is typically this complicated, it's almost as bad as Haskell and its monads! (I have much stronger math chops than most programmers, I've tried to read introductions to monads twice, had them explained to me three separate times on HN, and still don't understand them at all!)

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#53
post #52
post #47

Earlier quoted context omitted.

I'm a professional ruby programmer and your comments opened my eyes. If you don't know what's going on, then that does look like really icky code. First off, parenthesis in ruby are optional. So calling a method can be done without parenthesis. The following two lines are the same: print() print As are these: print(1, 2, 3) print 1, 2, 3 Here's some bits that might explain better what stuff does: :state If you prefix…

This may be the clearest explanation of Ruby syntax I've ever read! My attempt to parse the above example comes to something like this: state_machine(STATE, {"initial" : ACTIVE}, function() { after_transition({"any" : BLOCKED}, function(user, transition) { user.users_projects.find_each(function(membership) { return (membership.destroy ? true : false); }); }); }); I'm writing in JavaScript because its function notatio…

Yep, just about, although if you look closely, the `any` in the original code is not a symbol, but is actually a variable or a method (could be either, we can't know from the sample).

Also, the return in that block would cause an exception, because it doesn't do what the original programmer thinks it does. I guess he never tried out what happens if destroy returns false (which would happen if destroy fails, e.g. because a validation failed).

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#54
post #47
post #26

Earlier quoted context omitted.

As a Python programmer, I agree. Here's a Ruby snippet. I don't want to pick on this particular project [1], rather, I've found that this is typical of Ruby code: state_machine :state, initial: :active do after_transition any => :blocked do |user, transition| # Remove user from all projects and user.users_projects.find_each do |membership| return false unless membership.destroy end end My conclusion? Ruby's syntax is…

I'm a professional ruby programmer and your comments opened my eyes. If you don't know what's going on, then that does look like really icky code. First off, parenthesis in ruby are optional. So calling a method can be done without parenthesis. The following two lines are the same: print() print As are these: print(1, 2, 3) print 1, 2, 3 Here's some bits that might explain better what stuff does: :state If you prefix…

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 Scala

#55
Ruby and Scala are for two different kinds of environments. One is an environment where having less code to maintain (that can also be highly legible) matters and where you have a lot of options. The other is an environment where an edge in performance is more important, but not important enough to write it in an even faster language/not run in the JVM at all.

I noticed a lack of a link to a 1:1 comparison of application code with realistic examples. I think such comparisons and related discussion are often the best way to convince someone to use a language.

And some slides were just blatantly wrong, like Mixin Abuse: apparently that is just a long list of module includes? I have never seen so many module includes in a single class in application code. But, assuming you did have that, you should show what it would look like side-by-side in Scala. In Ruby, there are a lot of options when it comes to including other code or defining code in a class, instance, etc. Those options can lead to much less and more legible code if used correctly.

I remember when people said Java was slow; they made it seem like it was a fad, and no reputable company would use it. And... we see where that went.

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#56
post #35

Earlier quoted context omitted.

I've been thinking about private fields lately. In Python, a private field starts with an underscore, and someone who knows the culture of Python knows that the initial underscore encodes the notion "This field is not considered to be part of this library's public API, and it may go away or change behavior at any time, not necessarily a major version bump of this library, and if you look at it or change it, you'll be…

Java does not allow using reflection to access private fields !? Dude, just use C#.

You can access them, it will just throw exceptions you have to catch[1].

[1]http://stackoverflow.com/questions/1196192/how-do-i-read-a-p...

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#57
post #54
post #47

Earlier quoted context omitted.

I'm a professional ruby programmer and your comments opened my eyes. If you don't know what's going on, then that does look like really icky code. First off, parenthesis in ruby are optional. So calling a method can be done without parenthesis. The following two lines are the same: print() print As are these: print(1, 2, 3) print 1, 2, 3 Here's some bits that might explain better what stuff does: :state If you prefix…

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_…

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 Scala

#58

Scala is a fantastic language, but my heart seems to resist due to things like this (slide 27/42): implicit class RichSeq[A, C[A]

That's not the sort of thing you'll commonly see in real world Scala code. It's the sort of thing that might be used internally by a library, but not likely something you will come across day-to-day in Scala code. Every language has examples of code where the syntax is hard to follow, but you need to look at common code rather than "ooh let's try some tricks" kind of code.

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#59

Earlier quoted context omitted.

ah - "Using proguard lets you build Scala without any extra plugins and sbt fiddling". Seems like the tooling is still one of the more painful aspects of Scala. Kudos to Intellij, -1 to Scala.

Yeah, if I had to manually fiddle around with the SBT build process and manually adding dependencies instead of letting Intellij handle it all, I would be less motivated to want to switch away from Java on Android for sure :). Excessive configuration to get a new project up in a running is a major demotivator sometimes when you have a new idea and want to just start coding right away.

Do not forget, however, that (for development) you can easily skip the Proguard step if you install the scala libraries on your device directly. Also, setting SBT up is pretty much a one-time thing. Afterwards, you only need to do a few tweaks when starting a new project.

I've used Scala for a couple Android apps in the past... it was great fun to do so! Still, AndroidAnnotations not working with Scala code requires you to rewrite some of their functionality... but you can do that rather easily with Scala's traits etc.

Re: Confessions of a Ruby Developer Whose Heart was Stolen by Scala

#60
post #59

Earlier quoted context omitted.

Yeah, if I had to manually fiddle around with the SBT build process and manually adding dependencies instead of letting Intellij handle it all, I would be less motivated to want to switch away from Java on Android for sure :). Excessive configuration to get a new project up in a running is a major demotivator sometimes when you have a new idea and want to just start coding right away.

Do not forget, however, that (for development) you can easily skip the Proguard step if you install the scala libraries on your device directly. Also, setting SBT up is pretty much a one-time thing. Afterwards, you only need to do a few tweaks when starting a new project. I've used Scala for a couple Android apps in the past... it was great fun to do so! Still, AndroidAnnotations not working with Scala code requires…

Thanks, I forgot about loading the libraries directly onto my phone for testing. When you say Android Annotations, are you referring to the ones built into java/android (like @TargetApi) or your own custom ones? Just wondering, since I'm about to add ActionBarSherlock to a Scala project and it includes quite a few I'll have to rewrite.

Edit: seems it doesn't like ActionBarSherlock most likely due to that. I get "Error com.actionbarsherlock.R and com.actionbarsherlock.R$xml disgree on InnerClasses attribute"[1].

[1] https://issues.scala-lang.org/browse/SI-1167

Post reply on HN