For the usual doomsdaysayers saying "ruby can't X so I left it for Y", when X is typing, RBS is becoming the accepted standard (now that sorbet supports it),and RBS inline notation next to signature/code too (for peeps complaining about separate files); when X is LSP, ruby-lsp is the standard and already supports "go to definition" (its major hole for a long time), and its plugin architecture allows other other features to reuse the same code AST/index (So that each linter/formatter/type checker doesn't have to parse their own); when X is parallelism, ractors are have actually become performant in a lot of common cases, and it's only missing some GC improvements to be truly non-experimental.
There are new shiny things like ZJIT or Box, but even the core team recommends against using them in production for now. But they'll get better, as its been happening with the things listed above.
No wildly new syntax changes is also a good thing. Should help alternative implementations catch up.
Fairly hardcore rubyist here. Ruby-lsp is excellent. But in no way is RBS becoming standard. Maybe it will, I don’t know. But adoption is very, very low as of today. Rbs-inline is just someone’s pet project and has very little activity (though it does appear that the person who wrote it is trying to implement it directly into Rbs now, which would be great)
Personally I can’t see any comment based typing system gaining real traction.
As long as Matz is firmly against, inline typing should never be a part of Ruby. I started working on a large Rails codebase that adopted Sorbet and it is nothing but an impediment to progress.
Maybe I wasn't clear, but until now there were 2 types of type notations being debated, RBS and sorbet/RBI. Sorbet adopting RBS means that's the lowest common denominator. Typing is definitely not a standard, not yet. rbs-inline is definitely not a pet project, it's the RBS creator response to the main complaint about RbS , its the reason sorbet finally adopted it, and will be part of mainline rbs gem.
It’s just inferior to Python, nobody is making a more complex argument than that. Why ever use Ruby when there’s a virtually identical system that’s faster with a bigger community.
Because Ruby is just a better thought out language than Python is. It had a sane package management story 15 years before Python. It doesn't rely on weird hacks like exception throwing for iterator control flow. It doesn't have nearly as many warts and footguns on basic operations (for example, in Python csv.writer(file).writerows(rows) is broken unless you remembered to set the newline mode on the file; in Ruby file.write(rows.to_csv) just works). Thanks to a sane VM design it's mainline JIT can actually run code faster than interpreted code (something that CPython's JIT can't do [1])
Many Pythonistas are woefully ignorant of what's going on outside their siloed community.
In what ways is it inferior? Neither Ruby or Python are 'fast', so if that is one of your qualifiers you've already made a suboptimal choice.
As for a bigger community, what does that serve? The large python community adds misdirection and more voices to a language that lacks some basic features still. Async/sync code models are still being finalized whereas Ruby has been stable in this regard for 10+ years. Same with tooling - the Ruby side is more consistent and stable: Sidekiq for background jobs (Celery is barely coming to maturity), Bundler for dependencies (pip? poetry? uv?). Mature auth + other frameworks like Devise.
Having worked in both languages professionally, I strongly disagree with your take.
Ruby is a lot less awful than Python in my opinion. That is of course a very subjective opinion. The only reason I write more Python than Ruby is that ruby lacks the libraries I need.
Somewhere along the line Python got all the momentum, and ruby got none and now python is better if you just want to get shit done.
But man. I wish it was the other way around. I have one code snippet that summarises what I dislike about python:
if input() == "dynamic scope?":
defined = "happyhappy"
print(defined)
Seeing that I understand why I see yuck in just about every corner of python.
Edit: in ruby it also works, but the variable is at least always defined.
Blanket statements like this are unhelpfully tribal. Ruby has its uses, and underpins one of the most successful (and cloned) MVC frameworks of all time. But yeah, Python received the attention of data scientists early on and now it's a lingua franca of sorts in that domain. Since AI is so hot right now that makes Python seem superior, but really that's just contingency.
> Why ever use Ruby when there’s a virtually identical system [...] with a bigger community.
There was a time in the history of Python when people who chose Python did so primarily because they found it beautiful or pleasant to work with. These are reasonable factors in choosing a language, and they continue to be popular reasons for choosing relatively unpopular languages today.
Ruby/rails has always felt fragile to
me. Like you have to write the same tests over and over to make up for the looseness of it, not to mention the culture of breaking changes adds insult to injury. Just seems like a mess and the nice syntax (subjectively) isn't nearly enough to win when better options exist.
The ruby::box thing looks pretty interesting, from a cursory glance you can run two simultaneous versions of something like a feature or rollout much more conveniently.
Also being able to do
if condition1
&& condition2
...
end
on multiple lines rather than one - this is pretty nifty too!
I'm kinda hoping that eventually each ractor will run in it's own ruby::box and that each box will get garbage collected individually, so that you could have separate GCs per ractor, BEAM-style. That would allow them to truly run in parallel. One benefit should be to cut down p99 latency, since much fewer requests would be interrupted by garbage collection.
I'm not actually in need of this feature at the moment, but it would be cool and I think it fits very well with the idea of ractors as being completely separated from each other. The downside is of course that sharing objects between ractors would get slower as you'd need to copy the objects instead of just sharing the pointer, but I bet that for most applications that would be negligible. We could even make it so that on ractor creation you have to pass in a box for it to live in, with the default being either a new box or the box of the parent ractor.
They already truly run in parallel in Ruby 4.0. The overwhelming majority of contention points have been removed in the last yet.
Ruby::Box wouldn't help reducing contention further, they actually make it worse because with Ruby::Box classes and modules and an extra indirection to go though.
The one remaining contention point is indeed garbage collection. There is a plan for Ractor local GC, but it wasn''t sufficiently ready for Ruby 4.0.
In languages where placement don't matter, like c/js, I prefer leading booleans. It makes it much easier to see the logic, especially with layers of booleans.
Personally && in the new line seems to be much better readability. Can’t wait to use some smart cop to convert all existing multiline ifs in my codebase.
For folks who scan code bases based on the front of lines, it makes it easier to grok. Also helps with deleting and inserting lines (similar to leading or trailing commas in lists).
It's funny how I have been doing this way of writing the conditions in languages, where one can, like Python (if you use a pair of parentheses) and linters have yelled at me for ages to put the binary operator on the previous line. People herald these quite subjective things like truths, just because there is some tool, that they can delegate responsibility to.
I'm happy to see v4.0, but 2025 was the year I switched from Ruby to Python after gradually drifting back to it more and more. The tipping point was when I had Claude Code automatically convert one of my Ruby projects to 100% Python - and after that, I just had no Ruby left.
I spent over a decade enjoying Ruby and even wrote a book about it. At this point, though, Python has won for me: fastapi, pytorch, langchain, streamlit, and so on and on.
It's a bit sad, but I'll always remember the Christmas gifts, and the syntax that is always so much better than Python.
> fastapi, pytorch, langchain, streamlit, and so on and on
It's telling that your reasons for switching are all features of Python's ecosystem, not of the language itself. A lot of developers are moving to Python because of its libraries, and in many cases they don't care for the language at all.
That's causing a problem for Python: many of these developers who'd rather be using different languages seem to want to morph Python into their language of choice. The result is that the Python language is pulled in many different directions, and with each release gets increasingly bloated and strays further from its foundations.
Ruby, on the other hand, has a community that's mostly made up of people who actually like the language. That allows it to do a much better job of staying true to its core philosophy.
> It's telling that your reasons for switching are all features of Python's ecosystem, not of the language itself.
Right, because ecosystem beats syntax any day of the week. Plus many of us also think the Python language is nicer anyway. For me I can't get past Ruby's free wheeling approach to import scoping and tolerance for magic.
That core philosophy is a focus on aesthetics which means that API design in Ruby is much more driven by developer taste than practical considerations (for better or worse)
None of what you say about Python is true. It’s not even plausible. The Python language hasn’t even had any significant syntax changes for four versions now; versions 3.11-3.14 are basically all internals optimizations.
This year I also switched from Ruby to Kotlin on my hobby/light commercial backends. I just can't stand the way Ruby is not statically typed, and the resulting insecurity around if everything is actually doing what it should do. Kotlin gives me joy, and performance is actually better (trading memory requirements ofcourse, but that's not a big problem anymore). I still love Ruby, but only use it for simple scripts now.
This has sort of been my issue with Elixir. I've been doing Scala for years but I think Phoenix is really the best web story at the moment for how I want to be building web apps. And while I believe that the benefits of static typing somewhat decrease in the web arena, it's still frustrating to have to manage type relationships in my head.
I'm hopeful that the incoming type system work makes me happier there, though I'd also prefer a nicer editor experience than is currently available.
Langchain? I tried using/learning langchain then I found out that it was evolving so fast that even the latest ai models didn't have even remotely up to date information on it! Not to mention the hundreds of Google search results for ---- why do langchain docs suck?
I finally switched to haystack and I have been really happy. (Don't work on corporate ai software this is just for personal use)
Used Ruby for a decade, knew about it for more than that. I still sometimes use ruby syntax to communicate ideas with friends and colleagues.
For me, the killer feature of Python was the typing module and the intellij pycharm community edition being free and RubyMine having a subscription fee.
Ruby is amazing. I recently built a layer on top of Rails that can generate an API from a single markdown file. I did the same thing in python but it was much harder and JavaScript would have been a beast. Ruby can meta program like nothing else.
We created an Abstract controller that handles all of the typical behavior for a resource, auth, filtering, pagination, tenancy, import/export, serialization etc.
Then we expanded rails generators to cover ALL typical behavior. And the markdown file calls the generators.
It was a bit complicated to model polymorphic behavior but we got it working thanks to Ruby/Rails.
But the basic premise that made this work is: Use only restful actions; don’t turn it into RPC.
Recognize that most RPC/graphql functions are state changes that could have been a patch request. So instead of /clients/activate its /clients with a status attribute for “activate” or “archive”. Then most nested routes aren’t needed, use accepts nested attributes for and return child ids in the show action. There’s more to it that this but by strictly following conventions and modeling the data for rest, the api ends up
Super simple.
Our standard controller only whitelists strong params. All other behavior is automatic.
It's not overstating it to say I owe my entire SE career to Ruby.
Without it's accessible syntax, I don't know that I would have ever managed to overcome the initial "I have no idea what's going on" barrier. For whatever reason when I started out I found excess boilerplate & ceremony very overwhelming, and Ruby was the first language where I felt the joy of discovery more often than the frustration of cluelessness.
Although I've found myself gravitating away from object-orientation and towards languages that lean into functional principles, I will always hold a lot of fondness and respect for Ruby. For my brain and learning style, it's hard to imagine a better first language.
It's very cool to see how far it's come since 2.x!
For someone wanting to learn Ruby in 2025/26, what are some good up-to-date references, outside of the official documentation? Are there any recently-published books which stand-out?
For the usual doomsdaysayers saying "ruby can't X so I left it for Y", when X is typing, RBS is becoming the accepted standard (now that sorbet supports it),and RBS inline notation next to signature/code too (for peeps complaining about separate files); when X is LSP, ruby-lsp is the standard and already supports "go to definition" (its major hole for a long time), and its plugin architecture allows other other features to reuse the same code AST/index (So that each linter/formatter/type checker doesn't have to parse their own); when X is parallelism, ractors are have actually become performant in a lot of common cases, and it's only missing some GC improvements to be truly non-experimental.
There are new shiny things like ZJIT or Box, but even the core team recommends against using them in production for now. But they'll get better, as its been happening with the things listed above.
No wildly new syntax changes is also a good thing. Should help alternative implementations catch up.
Personally I can’t see any comment based typing system gaining real traction.
Many Pythonistas are woefully ignorant of what's going on outside their siloed community.
[1] https://fidget-spinner.github.io/posts/jit-reflections.html
As for a bigger community, what does that serve? The large python community adds misdirection and more voices to a language that lacks some basic features still. Async/sync code models are still being finalized whereas Ruby has been stable in this regard for 10+ years. Same with tooling - the Ruby side is more consistent and stable: Sidekiq for background jobs (Celery is barely coming to maturity), Bundler for dependencies (pip? poetry? uv?). Mature auth + other frameworks like Devise.
Having worked in both languages professionally, I strongly disagree with your take.
Somewhere along the line Python got all the momentum, and ruby got none and now python is better if you just want to get shit done.
But man. I wish it was the other way around. I have one code snippet that summarises what I dislike about python:
Seeing that I understand why I see yuck in just about every corner of python.Edit: in ruby it also works, but the variable is at least always defined.
If you're going to make claims, support them.
In every test I've done, Ruby has been faster than Python. In my experience that's been the case since Ruby 1.9, with the move to YARV.
There was a time in the history of Python when people who chose Python did so primarily because they found it beautiful or pleasant to work with. These are reasonable factors in choosing a language, and they continue to be popular reasons for choosing relatively unpopular languages today.
A related essay has made the rounds on HN before. It might be worth revisiting if this question is on your mind: https://www.johndcook.com/blog/2011/10/26/python-is-a-volunt...
The ruby::box thing looks pretty interesting, from a cursory glance you can run two simultaneous versions of something like a feature or rollout much more conveniently.
Also being able to do
on multiple lines rather than one - this is pretty nifty too!I'm not actually in need of this feature at the moment, but it would be cool and I think it fits very well with the idea of ractors as being completely separated from each other. The downside is of course that sharing objects between ractors would get slower as you'd need to copy the objects instead of just sharing the pointer, but I bet that for most applications that would be negligible. We could even make it so that on ractor creation you have to pass in a box for it to live in, with the default being either a new box or the box of the parent ractor.
Ruby::Box wouldn't help reducing contention further, they actually make it worse because with Ruby::Box classes and modules and an extra indirection to go though.
The one remaining contention point is indeed garbage collection. There is a plan for Ractor local GC, but it wasn''t sufficiently ready for Ruby 4.0.
I spent over a decade enjoying Ruby and even wrote a book about it. At this point, though, Python has won for me: fastapi, pytorch, langchain, streamlit, and so on and on.
It's a bit sad, but I'll always remember the Christmas gifts, and the syntax that is always so much better than Python.
It's telling that your reasons for switching are all features of Python's ecosystem, not of the language itself. A lot of developers are moving to Python because of its libraries, and in many cases they don't care for the language at all.
That's causing a problem for Python: many of these developers who'd rather be using different languages seem to want to morph Python into their language of choice. The result is that the Python language is pulled in many different directions, and with each release gets increasingly bloated and strays further from its foundations.
Ruby, on the other hand, has a community that's mostly made up of people who actually like the language. That allows it to do a much better job of staying true to its core philosophy.
Right, because ecosystem beats syntax any day of the week. Plus many of us also think the Python language is nicer anyway. For me I can't get past Ruby's free wheeling approach to import scoping and tolerance for magic.
Why would you write something so clearly false?
I'm hopeful that the incoming type system work makes me happier there, though I'd also prefer a nicer editor experience than is currently available.
I just can’t stand the excessive dynamism of Ruby. I understand some people prefer/enjoy it, it’s just not for me.
For me, the killer feature of Python was the typing module and the intellij pycharm community edition being free and RubyMine having a subscription fee.
but I still love writing full stack webapp using rails so yeah
thats why I really love pyCall
We created an Abstract controller that handles all of the typical behavior for a resource, auth, filtering, pagination, tenancy, import/export, serialization etc.
Then we expanded rails generators to cover ALL typical behavior. And the markdown file calls the generators.
It was a bit complicated to model polymorphic behavior but we got it working thanks to Ruby/Rails.
But the basic premise that made this work is: Use only restful actions; don’t turn it into RPC. Recognize that most RPC/graphql functions are state changes that could have been a patch request. So instead of /clients/activate its /clients with a status attribute for “activate” or “archive”. Then most nested routes aren’t needed, use accepts nested attributes for and return child ids in the show action. There’s more to it that this but by strictly following conventions and modeling the data for rest, the api ends up Super simple.
Our standard controller only whitelists strong params. All other behavior is automatic.
Have you heard about Lisp?
I might have forgotten a (
Ruby is clean. Which I love.
Dead Comment
Without it's accessible syntax, I don't know that I would have ever managed to overcome the initial "I have no idea what's going on" barrier. For whatever reason when I started out I found excess boilerplate & ceremony very overwhelming, and Ruby was the first language where I felt the joy of discovery more often than the frustration of cluelessness.
Although I've found myself gravitating away from object-orientation and towards languages that lean into functional principles, I will always hold a lot of fondness and respect for Ruby. For my brain and learning style, it's hard to imagine a better first language.
It's very cool to see how far it's come since 2.x!
5th: https://pragprog.com/titles/ruby5/programming-ruby-3-3-5th-e...
6th: https://pragprog.com/titles/ruby6/programming-ruby-4-6th-edi...
For a timeline-oriented reference of changes, check out https://rubyreferences.github.io/rubychanges/ and its individual pages.
[1]: https://pragmaticstudio.com/rails