During my first Introduction to Programming course at university, I was taught Java. One thing that I found very troubling is that it wasn't easy, or possible in many cases, to change the programming language. Sure, you can write new functions or methods or classes, but I can't change the keyword for an if-statement. I also remember the TA saying "why would you want that?" I caught myself thinking "if we can program a computer, then why can't we program a language?"
15 years later, I still have this issue a bit, except I made my peace with it. It is what it is. There are some exceptions though! Such as: Lisp, Smalltalk and similar languages. It's in part why I have worked for a company that professionally programmed in Pharo (a Smalltalk descendant [2]). I remember hacking a very crude way for runtime type checking in Pharo [1], just for fun.
I'm not a Ruby programmer, all I know is that Ruby has some things that are identical to Smalltalk. But my question to the author would be: if you long for things like keyword arguments, type hints and namespaces why don't you program it in the Ruby language yourself?
Or is that really hard, like most other languages?
I fully agree to the points here, even as a full time ruby lover. Jumping around different languages over the past 10 years really shows staleness in Ruby as a language, even if the ecosystem tries to keep up.
The ergonomics of ruby still have me very much liking the language as it fits how I think, but there are a lot of good developments in the usual neighbors, and I see myself picking up both Python and JS ever more for small projects.
I still like Ruby. 15+ years in, I find myself in the camp of not wanting it to change. 25 year old me would have been totally jazzed about the addition of namespaces in Ruby 3.5/4.0. 40 year old me wants namespaces to get off my Ruby lawn.
I'm sort of the inverse of this author: I have always liked Python and disliked Ruby. It's true though that python has changed a lot, and it's a mixed bag IMHO. I think every language feature python has added can have a reasonable argument made for its existence, however collectively it kind of makes the language burgeon under the weight of its own complexity. "one way to do it" really hasn't been a hard goal for the language for a while.
I'm really charmed by ML style languages nowadays. I think python has built a lot of kludges to compensate for the fact that functions, assignments, loops, and conditionals are not expressions. You get comprehensions, lambdas, conditional expressions, the walrus operator... most statements have an expression equivalent now.
it seems like, initially, Guido was of the opinion that in most cases you should just write the statement and not try "to cram everything in-line," so to speak. However it can't be denied that there are cases where the in-line version just looks nice. On the other hand now you have a statement and an expression that is slightly different syntactically but equivalent semantically, and you have to learn both. Rust avoids this nicely by just making everything an expression, but you do get some semicolon-related awkwardness as a result.
Back when autocompletion and stuff were only available in Visual Studio/Xcode/Other bug IDEs, I was forced to use Ruby and fell in love with it. It didn't matter what I used as my editor was Sublime. But when VSCode came and language features became democratized, I never touched a type-less language again. Why should someone opt for a language with absolutely no features where one can have autocompletion, typechecking, deep data type exploration, jumping to definitions and implementations? I really think it's a bad choice of Ruby not to care for types. And well we now have Crystal which again makes me question why Ruby? And it’s a shame no language is as beautiful as Ruby, not in features choices, design elegance, balance, beauty of the syntax, joy of programming mindset, not even in the name and logo. I wished Matz rethinked this part.
Typing not being a natively ruby thing makes all efforts to type the language in place seem second class. Ruby needs a typed variant that compiles down to type less Ruby.
It's the never ending "end"s that bother me about Ruby.
class Mess
def chaos(x)
if x > 0
[1,2,3].each do |i|
case i
when 1
if i.odd?
puts "odd"
else
puts "even"
end
when 2
begin
puts "trying"
rescue
puts "failed"
end
else
puts "other"
end
end
else
puts "negative"
end
end
end
Clear away all those ends and the program logic pops out. Much fresher!
class Mess:
def chaos(self, x):
if x > 0:
for i in [1, 2, 3]:
match i:
case 1:
if i % 2 == 1:
print("odd")
else:
print("even")
case 2:
try:
print("trying")
except:
print("failed")
case _:
print("other")
else:
print("negative")
I was a full-time Rubyist for a long time. I started the UK's first dedicated Ruby on Rails consultancy in 2006 before Rails was even v1.0 (IIRC the first apps I shipped back then were 0.8.6). I stuck around through the hype chain, and then started to help one employer break up a RoR monolith into micro services and adopt Java and Go (this was a mistake - we should have crafted the monolith better). I've built 4 startups as hands-on CTO with Ruby and Rails. It fed and housed me for many years.
In the last 5-7 years I've had to go in other directions. Clojure, Python, Java, even back to C and taking a look at Rust and Zig. I'm now in a role where I don't code so much, but I can see Ruby's problems - performance, the surprises, the fact it allows idiots to do idiotic things (nobody under the age of 40 should be legally allowed to monkey patch a base class or engage in meta programming).
And yet when I want to do something for me, for fun, perhaps advent of code, or a quick mock-up of something that's rolling around in my head, I reach for Ruby. Not elixir which has better runtimes, or C or Zig or Rust which has better performance, not something statically typed which leads to fewer bugs, not Python which has a huge data science community to it...
A few weeks ago I was listening to the DHH episode of the Lex Fridman podcast [0], where DHH talks about Ruby as a "luxury programming language". This matches my own experience.
When I need something to be fast, it's either because I'm dealing with a low-latency problem (and some of my side projects are very latency sensitive - 5ms can make the difference between success and failure), or because I can't afford the luxury of Ruby and Rails and the developer ergonomics.
Ruby makes things fun for the programmer. That's the point. It's beautiful to work with, even if it doesn't do all the things that all the coding books and blogs insist I should be ashamed to not have in my language.
I was slightly embarrassed to be a Ruby and RoR advocate for a while because of the brogrammer BS that emerged around both ecosystems in the 2010s. I then became very embarrassed because it wasn't as cool as a systems language like Rust or Go, or as intellectually deep as Haskell, or as hot on the ML bandwagon as Python.
But I think I don't care anymore. I'm just going to accept it for what it is, and lean into. Life's too short for "shoulds" - I'm just going to like what I like. And I like Ruby.
What looks like stagnation to Steen is actually [1] Matz’s remarkable foresight that provided stability and developer happiness.
Steen’s not wrong that Python evolved and Ruby moved slower, but he’s wrong to call Ruby stagnant or irrelevant. Just think what we've enjoyed in recent times: YJIT and MJIT massively improved runtime performance, ractors, the various type system efforts (RBS/Sorbet etc) that give gradual typing without cluttering the language etc.
Ruby’s priorities (ergonomics, DSLs, stability) are different[2] from Python’s (standardisation, academia/data). It’s a matter of taste and domain, not superiority.
I'm a python developer, and a big fan of the features with gradual typing etc. This article really highlights for me though, how python has very much changed from the language it was even 5 years ago.
Initially, the celebrated feature of python was that it allowed easy and fast development for newcomers. There was a joke a long the lines, "I learned python, it was a great weekend".
As much as I like python's type system (and wouldn't want to see them ever go way!), part of me wonders if moving into a world where hello-world can look like this, is a world where python is no longer the "lean in a weekend" language:
from typing import Annotated
import typer
app = typer.Typer()
@app.command()
def main(
name: Annotated[str, typer.Option("--name", "-n")],
) -> None:
"""Prints out 'HELLO {name}!!' (name upper cased) to the console"""
print(f"HELLO {name:upper}!!")
if __name__ == "__name__":
app()
(obviously the example is silly, and I know this is a lot more than you need to do, hopefully you get my point though!)
I'm confused by this post because I think Sorbet satisfies basically all the things the author wants, and my experience with Sorbet has been really good!
Typescript is a workaround.
It exists because web apps got more complex and browsers only support JavaScript.
So developers need to stick to JavaScript, but they need typing, therefore TypeScript has been implemented.
It’s an exception where it made sense to do so. For all other languages: if you use some dynamic language and you need typing, either wait until the language supports types natively (PHP‘s approach) or „just“ change the language.
The additional complexity of an additional typing layer is huge. The complexity of TypeScript - and in general JavaScript‘s ecosystem - is incredibly huge.
The biggest issue we have in software development is not that a language isn’t elegant, or you can’t write some some in 3 instead of 15 lines… the biggest problem is complexity. Developers too often forget about that. They focus on things that don’t matter. Ruby vs Python? It doesn’t make a real difference for web apps.
If you want a language and ecosystem with low complexity try Go. It’s not perfect. It’s not elegant. Or PHP, which has a lot of drawbacks, but overall less complexity. I don’t say Go or PHP are the best languages out there, but you should try them to get a picture - to decide for yourself what’s important and what not.
Ruby has a unified interface for select/map/reduce over all containers. They do lazy calculations if specified. You can chain expressions simply by appending them at the end without scrolling to the back of the expression. That is objectively better than lisp and python.
Sure, you can always rewrite to match that style with macros in lisp and generators in python, but they weren't meant to be used that way.
Sad thing about ruby is how they failed to do typing. I love python's typing module. I think it is the single best thing about python and I wouldn't touch python with a pole if it didn't have that module.
> Python is not my favorite programming language. In fact, allow me to drop the euphemism and express my pure, unadulterated thoughts about it: I never liked Python, I see it as a huge red flag and I think the world would be a better place if we all decided to finally move on from it.
Why do people make hating a tool their entire personality? I have noticed this same thing with languages like Go ("oh no Go still bad") and C++. I don't like C++ myself but I don't hate it. It would be like hating a screwdriver.
If you don't like a language simply don't use it, there are hundreds of alternatives. If your employer is making you write in that language you should hate your employer, not the language.
Ruby is such an elegant language, but the strong and ongoing hostility to any sort of sensible gradual typing is a real mistake.
I know that the Ruby community loves its clever runtime metaprogramming, but even the most metaprogrammed codebase is still going to consist mostly of plain old in-out methods. And as anyone who's ever typed a dynamic codebase knows, you pick up so much low-hanging fruit, in terms of edge cases and errors, when you slap some types on those. You don't need to type everything, but there is real hostility in Ruby circles to gradual typing, even where it would make sense and wouldn't impose any major costs.
Personally, I've stopped writing Ruby. Short of any pathway to sensible gradual typing, I just can't shake the feeling that every new line of Ruby is instant tech debt. Which is such a shame, since I find real beauty in the language.
This reads like a love letter to programming languages. You can never truly talk
about the quirks of a language without dabbling in it. And without experience with other languages - I doubt some of these quirks might even be seen as such.
Error handling for instance has always been my pet peeve. With dynamic languages like python, errors were all "exceptions". But then golang came along and decided
they'd be values and that only the truly exceptional errors should be "panicked".
But the if err != nil syntax became super verbose only after I learned about the
Result<Ok, Err> from Rust and the matching syntax associated with it.
A lot of people are shocked when they learn about ruby's monkey patching. I for one never truly groked the packaging of python applications until uv came along
to deliver an experience similar to npm.
And I agree, Typescript is the state of the art as far as static typing on top of a dynamic language is concerned. But I never considered it a programming language.
More like a tool to assist developers write/manage large javascript code.
In the end, I think the true reason for returning to pythong probably had more to do with getting a python gig. I live in the part of the world where my tech stack
ended up being influenced early on by the places I worked. I didn't mind learning Typescript for my first gig or improving my skills with nodejs.
In the end, every language can really get things done. And Typescript helps me pay
my bills and I couldn't be more grateful. Learn to love the quirks of your language and stop comparing it unfavorably with others. To date, I've never seen a language as elegant as ruby. Nor do I find an ecosystem better than python's at data science.
I'm going through the same processes as the author, after about a decade of Ruby I'm writing Typescript, Go and type-hinted Python, and I don't think I want to go back to the lack of namespaces/packages and the lack of typing.
And I've actually used Sorbet with Ruby for 2 years, but that seems like a really bad solution to this problem.
"I consider TypeScript to be the gold standard when it comes to type systems on top of dynamic languages."
Doubly weird, considering that TypeScript work was inspired by typed/racket, and TypeScript doesn't have a sound type system afaik and the OP's first love was Scheme.
As someone who loves Scheme (author of a Scheme exenstion for computer music, Scheme for Max), and who has done lots of Python and little Ruby, I find this odd. To me, Ruby is a much further departure from Scheme. At least in Python I can do something close to functional programming with primitives, though I don't get symbols. Ruby's "everything is an object" has always seemed to me to be even a further departure.
But then I really don't know Ruby, so happy to be told why this is wrong...
I started my programming journey with VB6. Ruby reminds me of Visual Basic. But its never evolved past that. Python became popular because it was a scripting language that had classes and a nice built out framework of features. But it has a god awful syntax and should never be used for a large project. Also their package management is a dumpster fire.
This brings me to C#. At .NET 10 there will be another option then python. .NET 10 brings the ability to run C# script files without the need for a proj file or a main method. This will bring the full .NET Framework and NUGET eco system with it. I can't wait to replace all my python scripts with this.
31 comments
[ 3.9 ms ] story [ 49.0 ms ] threadDuring my first Introduction to Programming course at university, I was taught Java. One thing that I found very troubling is that it wasn't easy, or possible in many cases, to change the programming language. Sure, you can write new functions or methods or classes, but I can't change the keyword for an if-statement. I also remember the TA saying "why would you want that?" I caught myself thinking "if we can program a computer, then why can't we program a language?"
15 years later, I still have this issue a bit, except I made my peace with it. It is what it is. There are some exceptions though! Such as: Lisp, Smalltalk and similar languages. It's in part why I have worked for a company that professionally programmed in Pharo (a Smalltalk descendant [2]). I remember hacking a very crude way for runtime type checking in Pharo [1], just for fun.
I'm not a Ruby programmer, all I know is that Ruby has some things that are identical to Smalltalk. But my question to the author would be: if you long for things like keyword arguments, type hints and namespaces why don't you program it in the Ruby language yourself?
Or is that really hard, like most other languages?
[1] https://youtu.be/FeFrt-kdvms?si=vlFPIkGuVceztVuW&t=2678
[2] Fun fact, I learned about Lisp, Smalltalk and Pharo through HN! So I know most of you know but I suspect some don't.
The ergonomics of ruby still have me very much liking the language as it fits how I think, but there are a lot of good developments in the usual neighbors, and I see myself picking up both Python and JS ever more for small projects.
I'm really charmed by ML style languages nowadays. I think python has built a lot of kludges to compensate for the fact that functions, assignments, loops, and conditionals are not expressions. You get comprehensions, lambdas, conditional expressions, the walrus operator... most statements have an expression equivalent now.
it seems like, initially, Guido was of the opinion that in most cases you should just write the statement and not try "to cram everything in-line," so to speak. However it can't be denied that there are cases where the in-line version just looks nice. On the other hand now you have a statement and an expression that is slightly different syntactically but equivalent semantically, and you have to learn both. Rust avoids this nicely by just making everything an expression, but you do get some semicolon-related awkwardness as a result.
In the last 5-7 years I've had to go in other directions. Clojure, Python, Java, even back to C and taking a look at Rust and Zig. I'm now in a role where I don't code so much, but I can see Ruby's problems - performance, the surprises, the fact it allows idiots to do idiotic things (nobody under the age of 40 should be legally allowed to monkey patch a base class or engage in meta programming).
And yet when I want to do something for me, for fun, perhaps advent of code, or a quick mock-up of something that's rolling around in my head, I reach for Ruby. Not elixir which has better runtimes, or C or Zig or Rust which has better performance, not something statically typed which leads to fewer bugs, not Python which has a huge data science community to it...
A few weeks ago I was listening to the DHH episode of the Lex Fridman podcast [0], where DHH talks about Ruby as a "luxury programming language". This matches my own experience.
When I need something to be fast, it's either because I'm dealing with a low-latency problem (and some of my side projects are very latency sensitive - 5ms can make the difference between success and failure), or because I can't afford the luxury of Ruby and Rails and the developer ergonomics.
Ruby makes things fun for the programmer. That's the point. It's beautiful to work with, even if it doesn't do all the things that all the coding books and blogs insist I should be ashamed to not have in my language.
I was slightly embarrassed to be a Ruby and RoR advocate for a while because of the brogrammer BS that emerged around both ecosystems in the 2010s. I then became very embarrassed because it wasn't as cool as a systems language like Rust or Go, or as intellectually deep as Haskell, or as hot on the ML bandwagon as Python.
But I think I don't care anymore. I'm just going to accept it for what it is, and lean into. Life's too short for "shoulds" - I'm just going to like what I like. And I like Ruby.
[0] https://www.youtube.com/watch?v=vagyIcmIGOQ
Steen’s not wrong that Python evolved and Ruby moved slower, but he’s wrong to call Ruby stagnant or irrelevant. Just think what we've enjoyed in recent times: YJIT and MJIT massively improved runtime performance, ractors, the various type system efforts (RBS/Sorbet etc) that give gradual typing without cluttering the language etc.
Ruby’s priorities (ergonomics, DSLs, stability) are different[2] from Python’s (standardisation, academia/data). It’s a matter of taste and domain, not superiority.
[1] I'm stealing a point DHH made on Lex's podcast. https://www.youtube.com/watch?v=vagyIcmIGOQ
[2] I'm once again parroting DHH/Matz
Initially, the celebrated feature of python was that it allowed easy and fast development for newcomers. There was a joke a long the lines, "I learned python, it was a great weekend".
As much as I like python's type system (and wouldn't want to see them ever go way!), part of me wonders if moving into a world where hello-world can look like this, is a world where python is no longer the "lean in a weekend" language:
(obviously the example is silly, and I know this is a lot more than you need to do, hopefully you get my point though!)Sure, you can always rewrite to match that style with macros in lisp and generators in python, but they weren't meant to be used that way.
Sad thing about ruby is how they failed to do typing. I love python's typing module. I think it is the single best thing about python and I wouldn't touch python with a pole if it didn't have that module.
Why do people make hating a tool their entire personality? I have noticed this same thing with languages like Go ("oh no Go still bad") and C++. I don't like C++ myself but I don't hate it. It would be like hating a screwdriver.
If you don't like a language simply don't use it, there are hundreds of alternatives. If your employer is making you write in that language you should hate your employer, not the language.
I know that the Ruby community loves its clever runtime metaprogramming, but even the most metaprogrammed codebase is still going to consist mostly of plain old in-out methods. And as anyone who's ever typed a dynamic codebase knows, you pick up so much low-hanging fruit, in terms of edge cases and errors, when you slap some types on those. You don't need to type everything, but there is real hostility in Ruby circles to gradual typing, even where it would make sense and wouldn't impose any major costs.
Personally, I've stopped writing Ruby. Short of any pathway to sensible gradual typing, I just can't shake the feeling that every new line of Ruby is instant tech debt. Which is such a shame, since I find real beauty in the language.
Error handling for instance has always been my pet peeve. With dynamic languages like python, errors were all "exceptions". But then golang came along and decided they'd be values and that only the truly exceptional errors should be "panicked". But the if err != nil syntax became super verbose only after I learned about the Result<Ok, Err> from Rust and the matching syntax associated with it.
A lot of people are shocked when they learn about ruby's monkey patching. I for one never truly groked the packaging of python applications until uv came along to deliver an experience similar to npm.
And I agree, Typescript is the state of the art as far as static typing on top of a dynamic language is concerned. But I never considered it a programming language. More like a tool to assist developers write/manage large javascript code.
In the end, I think the true reason for returning to pythong probably had more to do with getting a python gig. I live in the part of the world where my tech stack ended up being influenced early on by the places I worked. I didn't mind learning Typescript for my first gig or improving my skills with nodejs.
In the end, every language can really get things done. And Typescript helps me pay my bills and I couldn't be more grateful. Learn to love the quirks of your language and stop comparing it unfavorably with others. To date, I've never seen a language as elegant as ruby. Nor do I find an ecosystem better than python's at data science.
And I've actually used Sorbet with Ruby for 2 years, but that seems like a really bad solution to this problem.
Doubly weird, considering that TypeScript work was inspired by typed/racket, and TypeScript doesn't have a sound type system afaik and the OP's first love was Scheme.
But then I really don't know Ruby, so happy to be told why this is wrong...
I work in Python and PHP every day though.
This brings me to C#. At .NET 10 there will be another option then python. .NET 10 brings the ability to run C# script files without the need for a proj file or a main method. This will bring the full .NET Framework and NUGET eco system with it. I can't wait to replace all my python scripts with this.