

Confessions of a Ruby Developer Whose Heart was Stolen by Scala - YAFZ
https://speakerdeck.com/ryanlecompte/confessions-of-a-ruby-developer-whose-heart-was-stolen-by-scala

======
gizzlon
They way you'd build large systems in dynamic languages is to break it up into
many smaller pieces that work together. This frees you to change parts without
worrying about the rest.

To me, this type of development is much more natural and sane than the "one
big clusterfuck" type of projects I've seen in Java et.al.

Edit: Also, dynamic languages let you make the tradeof between safety and
speed. Sometimes you go slow and steady (simple code, tests..) and sometimes
you just want to test something out.

~~~
mattquiros
Hm, I don't know what you've seen but I'm pretty sure Java is about breaking
up large systems into many smaller pieces that work together, instead of one
big clusterfuck. Must be some really badly designed system, more of a
programmer's fault than the language itself

~~~
gizzlon
True, but isn't it still one big program/project? What I mean was to break it
up into many smaller programs and (possibly) projects (think unix process vs.
classes =)

------
BonoboBoner
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] <: Seq[A]](underlying: C[A]{
        def cycle: Iterator[A] = {
          lazy val circular: Stream[A] = underlying.toStream #::: circular
          circular.iterator
        }
      }

~~~
vladev
This is very dense code, and takes some getting-used-to in order to read. What
it achieves is beyond the reach of many languages.

All it does is convert a Seq (sequence) to a lazy stream that will infinitely
cycle through the values.

    
    
        Seq(1, 2, 3).cycle.take(8).toList
        res3: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2)
    

It will work for any seq-like structure (including List. Vector, Queue, etc.)

If you try to use it with anything else, like a Map, it won't compile.

Also, note from my example that it's generic and the resulting List is of the
correct type.

Just like novice JavaScript developers struggle with "Why 'this' changes
here?", it requires some experience with the language.

~~~
dons
> This is very dense code, and takes some getting-used-to in order to read.

I don't think so. It is full of syntactic noise, for what is really just
notation for building a cyclic structure.

* type annotations stated explicitly, not inferred

* type variables given multiple times

* too much non-verb, non-noun syntax e.g. `#:::`

* and the actual construction of the cycle is stated imperatively with great ceremony (despite it being an applicative)

It is the opposite of dense.

------
jitl
As a Ruby developer, I can't get through these sorts of slides. My other
languages are C, Go and JavaScript, and the Scala syntax is totally
inscrutable to me. Isn't the point of slides presenting something that can be
easily absorbed? And I can't just quickly look up these declarations either —
Scala is too complex for that given my experience level. Is there a gentle
introduction talk for Scala around so I can evaluate the language without
putting in a week of learning?

~~~
trailfox
As a Scala programmer I find Ruby syntax complex and inscrutable, almost like
Perl.

~~~
csense
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 awful. There are colons, absolute value bars,
implications, and who-knows-what-else flying everywhere! It gets worse,
elsewhere in the same file there are messy lines like this one with single-
arrow implications, question marks and ampersands [2] [3]:

    
    
      scope :not_in_project, ->(project) \
        { project.users.present? ?       \
        where("id not in (:ids)", ids: project.users.map(&:id) ) : scoped }
    

Simple, intuitive syntax? From where I sit, the syntax of Ruby is worse than
C++, and approaches Perl levels of awfulness. In most languages, I can at
least sort-of grok what's going on from the context when I see unfamiliar
operators, but not so in Ruby.

This is a copy-paste of a comment I made [4] weeks ago on another article.

[1]
[https://github.com/gitlabhq/gitlabhq/blob/4caaea824cf51670d1...](https://github.com/gitlabhq/gitlabhq/blob/4caaea824cf51670d11b409efa5701dd74614d2a/app/models/user.rb#L118)

[2]
[https://github.com/gitlabhq/gitlabhq/blob/4caaea824cf51670d1...](https://github.com/gitlabhq/gitlabhq/blob/4caaea824cf51670d11b409efa5701dd74614d2a/app/models/user.rb#L143)

[3] I split the line and inserted backslashes because HN gives me a horizontal
scrollbar when it's a single long line; apologies if this transformation isn't
legal Ruby, or changes the meaning of the code.

[4]
[https://news.ycombinator.com/item?id=5784296](https://news.ycombinator.com/item?id=5784296)

~~~
relix
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 a word with a colon that creates an object of type Symbol, with
value "state", which is a bit like the string "state". The difference is that
every mention of :state is a reference to the same object, while if you create
a string "state", and a bit further do it again, those are two different
objects. We use symbols because it runs faster for conditionals etc: to
compare two symbols the interpreter only needs to check the reference, while
to compare two strings, every character needs to be checked.

    
    
        initial: :active
    

This creates a Hash with one key-value, with key :initial, and value :active,
both symbols. This is equivalent to typing :initial => :active which you
encounter a bit further up.

    
    
        do |var1, var2| .... end
    

This creates a block, which is like a closure. The variable names between
pipes are the arguments this block takes. Any code inside the block is only
run when the block is called. In Ruby, every function can have a block passed
by adding do ... end to it. Inside this function, the block can be called
using the keyword yield, e.g. yield(1,2) to call the block with arguments 1
and 2. The find_each method will loop through every value of the Array it is
called on, and run the block once for every value.

    
    
        project.users.present?
    

The question mark is a valid character for a method name, there's nothing
special happening here, present? is just the name of a method. This could
easily have been called is_present, or just present.

    
    
        a ? b : c
    

The ternary operator, the same in any language. It translates to "if a, return
b, else return c".

    
    
        ->(arg1, arg2) { ... }
    

This creates a lambda, with arguments arg1 and arg2. A lambda is almost the
same as a block, so this is almost the same as typing do |arg1, arg2| ... end

~~~
csense
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!)

~~~
relix
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).

------
trailfox
For those interested in learning Scala I'd recommend the free chapters from
Scala for the Impatient:

[http://logic.cse.unt.edu/tarau/teaching/SCALA_DOCS/scala-
for...](http://logic.cse.unt.edu/tarau/teaching/SCALA_DOCS/scala-for-the-
impatient.pdf)

~~~
pyvek
Also, _Functional Programming Principles in Scala_ course on Coursera by
Martin Odersky (Scala's designer) is very good.

[https://www.coursera.org/course/progfun](https://www.coursera.org/course/progfun)

~~~
dhugiaskmak
I just finished the most recent session of this class and I found it
incredibly frustrating that there was no discussion of the homework
assignments after the due dates had passed. What's the point of having
homework if there's no way to get the correct answers and get feedback on your
solutions?

And take the "in Scala" part of the course title with a grain of salt. You're
only taught enough to complete the exercises.

------
hejsna
It seemed like most of his slides came down to the old typed/untyped flame
war. Yes, in Scala you can look at your objects in an IDE and be told what
type they are, in Ruby you can't. Some organizations and people need that,
some don't. And yes, it's easier to optimize typed languages. Some
applications need that extra speed, most don't.

I'm happy he found a language he enjoys working with, but I doubt this will
change anyone's mind...

~~~
coopdog
Somewhat true but I find Scala's inferred typing a surprisingly great
compromise between the two.

For example:

val i = 1;

i = "some string" // throws a compiler error, because it knows i is an integer

It's great when you haven't declared the types, you change for example an int
to a double or a class to some other class (eg swapping a data structure) and
it just flows through the code base without problems like a dynamically typed
language.

It can also be pretty useful to look up types when they get complex in the
middle of some function, like a Map[List[(String,SomeObject)]] (a map of lists
of (String,SomeObject) tuples). Allowing the types to get complex lets me
focus on the problem while giving a crutch to quickly remember where it's at
half way through (and while finding other methods/source of data) and keep
moving towards the solution.

------
garysweaver
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.

------
Stranger2013
Well, of course a classic programming language is better then a script
language for majority of tasks. Script languages like JS and Ruby just should
not be abused and should only be used as a very thin layer on top. E.g. GUI
scripting.

~~~
aaronbrethorst
I would recommend that you immediately inform Yahoo, 37 Signals, Hulu, GitHub,
Penny Arcade, and every other Node, Rails, Sinatra, and EventMachine user of
this fact!

Also, Tcl/Tk called and wants its use case back.

~~~
unono
Why do microsoft and google insist on static compiled languages?

~~~
marshray
Because they allow us to put very useful limits on the degree to which changes
in a large and evolving codebase will violate the expectations of developers.
When adding and changing code in large collaborative projects, the primary
question in every developer's mind is "OK, what else depends on this, i.e.,
what is possibly going to break?" This goes back to the old wisdom of
separating interface from implementation.

Highly dynamic languages, such as Ruby, certainly have their advantages too.
But programs in languages which enable, if not encourage, developers to add
new methods to the integer '5' can quickly become very difficult to reason
about.

Static, strongly-typed languages also provide other benefits such as much
better error checking and compile-time optimization.

~~~
alinajaf
> But programs in languages which enable, if not encourage, developers to add
> new methods to the integer '5' can quickly become very difficult to reason
> about.

Can you give me an example of a single ruby developer who thinks this is a
good idea when writing new code/a library?

~~~
marshray
I think probably for every language, every development team needs to have
agreements not to do certain things. The probability of a developer doing
something unexpected increases exponentially with the number of developers and
the amount of code.

It only takes one, but here are a few thousand to start with:
[https://github.com/search?l=Ruby&q=%22class+Integer%22&ref=a...](https://github.com/search?l=Ruby&q=%22class+Integer%22&ref=advsearch&type=Code)

Do your projects use any Gems that are pulling in any of this code?

Could they change to do so in the future?

Most importantly: how much effort is it for you to definitively answer this
question?

Our task is that of proving a negative (which as we all know is very
difficult). Namely that there is _no_ other code that is relying upon the
behavior that you are changing. When there are reasonably well-defined
interfaces between components it _dramatically_ reduces the possibility space
for implicit dependencies and interactions. So this is a slam-dunk case where
tools can make our job _much_ easier.

Without tools, we're basically reduced to "verbal lore" and "honor system".
Programmers have to rely upon the shared understanding and behavior of other
humans in order to reason about their own code.

------
playing_colours
The speaker pays a lot of attention to implicits in Scala. Well, it's a
powerful tool, elegant solutions can be built with it, but you should be
careful using them. Implicits bring its own magic and abusing them can pollute
your project, make it difficult to understand the code. Maybe the speaker is
so attracted to inplicits because they remind him of Ruby's / Rails' magic?

~~~
vladev
You are correct that implicits are a sharp tool. Thankfully, the Scala
community knows that nowadays and they are used for a fairly small number of
cases - pimp my library (add methods to Ints, Strings, etc.) and typeclasses.

------
sandGorgon
Can someone comment on the current state of tooling in the Scala world. Last I
had tried (some months back), SBT was extremely slow.

Googling about SBT came back with a lot of complaints about the state of scala
tooling back then.

~~~
yareally
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-scala-intellij-no-sbt-
pl...](https://github.com/yareally/android-scala-intellij-no-sbt-plugin)

~~~
sandGorgon
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.

~~~
yareally
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.

~~~
th0br0
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.

~~~
yareally
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](https://issues.scala-
lang.org/browse/SI-1167)

~~~
th0br0
I don't believe I've used ABS with Scala before. Shouldn't integrating ABS as
an apklib solve this issue though?

Regarding AndroidAnnotations:
[https://github.com/excilys/androidannotations/wiki](https://github.com/excilys/androidannotations/wiki)

~~~
yareally
I'll try that option. I was just building it into the project as a separate
module dependency out of habit from Java, but no real need to do that.

Ahh, I know of that project. Like it quite a bit. Was just confused over the
ambiguity of the term "annotations." Thanks for the followup though.

------
dgregd
I just wonder when someone will build a tool to annotate Ruby, Python source
code with var types gathered during run-time.

If C has Valgrind then dynamic typed languages should get something for the
types.

~~~
Erwin
PyCharm does this. In addition to doing type inference while you have your
project open, you can while debugging it run it and make it collect type
information. That's quite a bit slower than usual, but once done you will get
extra type hints of possible types passed to your functions.

[http://blog.jetbrains.com/pycharm/2013/02/dynamic-runtime-
ty...](http://blog.jetbrains.com/pycharm/2013/02/dynamic-runtime-type-
inference-in-pycharm-2-7/)

