I really like the Ruby language. I like it for its syntax and its idioms and the programming culture. Recently I’ve been thinking about the things that I don’t like about the language. It’ s a relatively short list.
Ruby: some things I don’t like about you
The slow speed. It really is bad, but we get away with it because reasons.
The symbol-string distinction. This seems to exist only to introduce silly bugs involving mismatches (and so Rails users can make jokes about HashWithIndifferentAccess
). I know that symbols are singletons and that helps with memory usage, but 1) most Ruby programmers in my experience aren’t profiling memory that much and 2) that argument is less relevant now that there is a plan to treat string literals the same way.
The poor immutability story. I’m not sure that I buy 100% into FP (in part because I don’t know yet how to integrate it with OOP, which I do buy into) but I’ve become more and more disenchanted with mutation of objects. This was an actual pain point on a recent project, where I had a deeply nested hash that was being mutated from afar and I eventually used ice_nine to freeze the whole thing just to figure out where the mutation was taking place.
The MRI codebase. The core interpreter and low-level libraries are implemented in C (also the project uses Subversion for version control). I’ve tried subscribing in my RSS reader to the new commits on master on the Github mirror, but I eventually gave up because I never understood what I was looking at. On the other hand I was able to jump in and contribute to the Crystal standard libraries with a very minor PR just by glancing around the source code. I realize this isn’t necessarily fair, since this part of MRI standard lib would be probably be equally easy to hack on but in general it’s relatively easy to understand what is happening even in the “low-level” Crystal AST parsing code. It won’t happen but I wish Ruby were implemented in a higher level and more OO language like Go, Rust, or even C++ (or Crystal!).
The poor auto-completion and static analysis. Obviously this is the cost we pay for having an untyped, dynamic, late-binding language. More generally I agree with Avdi Grimm’s point here that Ruby has bad development tools. Rubocop is a notable exception that when integrated with tools like Syntastic and more recently Neomake has dramatically improved my development experience (if only because I get instant warnings when I have a unused variable, usually meaning I have a typo).
Peering at the greener grass
So, recently I have been exploring other languages, in particular compiled languages (not for the first time, but my entire working career has been with dynamic languages so it’s most of my programming experience). Not that much; just a little puttering around here and there with Crystal, Rust, and Go. It’s a little too early for me to say anything meaningful, but here are my early reactions:
- Something I already knew: good autocompletion is really nice. Static typing really pays off when you can see at a glance all the methods and properties on the object that you’re dealing with.
- Code-compile-execute is awkward (although to be fair, in Ruby we run our tests constantly, almost like a compile step).
- I really miss REPL-style investigation with a debugger (actually I should mention Pry as another great Ruby tool). Right now I’m experiencing this lack with a Go program, where I want to know what this struct instance that I’m dealing with is and the suggestions on the web seem to be to marshall it to a JSON object and then print it? I know that there are a couple things going on here and I’m probably making noob mistakes, but my point is that REPL is a really big part of productivity for me. Right now I have the joy of knowing all the types of my objects through static analysis but I feel blind when it comes to runtime values.
- You have to think about so many low-level details, like specifying the size and element types of arrays (or the maximum size of slices in Go). There’s your big productivity tradeoff there. These low-level details might help you be more precise about performance, but they also distract from whatever domain you’re usually working in.
Enfin
This is sort of the point of this disorganized jumble of incomplete thoughts. You will sometimes see sentiments like “Ruby is dying because everyone is going to go to X because it’s faster/better”. If X is Go or Rust you’re just talking about a different kind of thing. They’re really interesting and useful languages but you can’t get away from the fact that they impose a certain style and pace of programming that departs from what makes Ruby a great language.
Actually, I thought this guy expressed things pretty well:
I’m thinking Ruby is the most depressive programming language community. Every week there’s some Ruby figure handwringing in public.
— Joseph Method (@method3000) July 6, 2015
People freak out about what Node, Go, Haskell, or Elixir can do. People write diatribes about Ruby “dying”, about things “killing” Ruby.
— Joseph Method (@method3000) July 6, 2015
The bottom line is that Ruby has the best, most expressive syntax. It is a language for writing code that looks like pseudocode.
— Joseph Method (@method3000) July 6, 2015
Ruby optimizes for rapid prototyping and inter-developer communication. It has some inherent limitations and some accidental limitations.
— Joseph Method (@method3000) July 6, 2015
The accidental limitations are lack of concurrency and the GIL. The inherent limitation is that it can’t do certain compiler optimizations.
— Joseph Method (@method3000) July 6, 2015
So these things being said, pick your poison. What are you optimizing? Code accessibility and communicability? Performance over everything?
— Joseph Method (@method3000) July 6, 2015
I’m just saying, have perspective. If you tell me that Node.js is going to take over the world okay I’ll bite. But don’t tell me Haskell is.
— Joseph Method (@method3000) July 6, 2015
Haskell will be a useful tool in some people’s infrastructures but it’s never going to be a main driver because HAVE YOU SEEN HASKELL?
— Joseph Method (@method3000) July 6, 2015
Likewise, more people will code in Go or Rust for the performance. But don’t pretend everyone is going to do it. Because it’s low-level.
— Joseph Method (@method3000) July 6, 2015
Programming language use isn’t decided just on technical merits of the interpreter or compiler but on external factors like developer pool.
— Joseph Method (@method3000) July 6, 2015
Anyway this is why Ruby isn’t “dying”. So seriously just take your angst and use it to make Ruby better.
— Joseph Method (@method3000) July 6, 2015
I would just add a couple more nuances. I’m not saying that Ruby will never go out of fashion. I’m just dubious that it is currently “dying” or that it will “die”. Apart from the fact that major programming languages never actually die, there’s also the assumption that Ruby can’t improve and overcome many of its pain points. But there is still an incredible vibrancy and degree of communal care in the Ruby world that creates tools like Rubocop and that can mount efforts like Matz’s proposal to improve Ruby’s speed 3x.
Also I’m not saying that it would be unusual for someone to prefer another language, static or dynamic, over Ruby. It sounds like Elixir is really special, and the fact that it is dynamic, has Ruby-like syntax, AND is fast makes it really intriguing. And as I’ve mentioned before I’m especially interested in Crystal’s approach that combines Ruby-like syntax with compilation and inferred types (although the project is moving toward more explicit type declarations to improve compilation times). Really what I’m saying is that we should keep innovating to make the best programming language, which includes the concomitant development experience, with the caveat that you can’t actually make one language that everyone will prefer for every occasion and use case. And that’s just fine.