NHacker Next
login
▲Ruby 4.0.0ruby-lang.org
667 points by FBISurveillance 20 hours ago | 149 comments
Loading comments...
chucke 11 hours ago [-]
Happy bday ruby!

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.

rco8786 9 hours ago [-]
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.

block_dagger 8 hours ago [-]
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.
__float 7 hours ago [-]
I work in a large Sorbet codebase (though it isn't a Rails one) and it's a huge boon IMO. The number of tests we don't need to write because of Sorbet is really nice.

It does occasionally require structuring your code differently, but I find the type-system-encouraged approach often gives a more elegant and harder-to-misuse interface in the end.

prh8 5 hours ago [-]
You work in a large Ruby codebase that _isn't_ Rails?! Are you hiring??
ezekg 4 hours ago [-]
I was assuming Stripe, but would love to hear of others!
zingar 4 hours ago [-]
Very curious to hear about the specific cases where types make tests unnecessary.

I spend my working life swapping between Ruby and typescript projects and the typescript project is utter garbage with poor test coverage that needs a day of human QA for every build whereas the Ruby project is well tested such that we know that CI passing means it’s good to be released.

rco8786 8 hours ago [-]
I think it will need to be a strong 3rd party that basically gives it the Typescript treatment.

Adds type annotations to the core language syntax. The compiler does type checking, strips the annotations, and outputs plain Ruby.

anamexis 4 hours ago [-]
Sorbet is backed by Stripe.

Why is it important to be a separate layer that compiles to plain untyped Ruby?

danmaz74 7 hours ago [-]
> adopted Sorbet and it is nothing but an impediment to progress

How so?

I never really missed types in Ruby, even if I like them a lot in typescript, but right now I'm doing some "vibe coding" on a personal project and I was thinking about trying Sorbet. I think that it could help Claude Code avoid some mistakes it often makes which make it waste a lot of time fixing.

zingar 4 hours ago [-]
Interesting: how is CC in your experience at writing tests and then using them to avoid mistakes?
danmaz74 3 hours ago [-]
When writing non-vibe-coded software I use CC a lot to write tests, but I have a skill to tell it not to create redundant tests, which otherwise it tends to do, and I have to check them anyway to ensure that they cover what needs to be covered, and sometimes to trim them down.

When vibe coding, what I noticed is that CC tends to make mistakes which it does catch with tests and fix on its own, but my hope is that using Sorbet this will happen much less, and thus development will go faster with less (slow) test cycles.

throwaway613745 8 hours ago [-]
DHH also doesn’t like typing in Ruby at all, and Rails is designed around what he likes.
chucke 7 hours ago [-]
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.
screenothethird 11 hours ago [-]
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.
Calavar 8 hours ago [-]
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.

[1] https://fidget-spinner.github.io/posts/jit-reflections.html

lern_too_spel 4 hours ago [-]
Everything being mutable by default, including strings, is about as big a foot gun as you can find in a high level language.
bjoli 8 hours ago [-]
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.

qezz 5 hours ago [-]
> in ruby it also works, but the variable is at least always defined.

How is this even a pro? I agree that Python scoping rules are frustrating, but tbh not sure if I would prefer Ruby's behavior in this case

bjoli 3 hours ago [-]
Well. If python is a dynamically scoped language, what they do is correct. If they are lexically scoped (which python is described as) the variable defined in the if should never have different visibility in the same scope.

In a lexically scoped language you don't define variables conditionally. What ruby does is also icky, but obviously the developers of both python and ruby wanted to save the developer an extra declaration. The ruby version is at least more correct from a lexical standpoint (it is set to nil if left "nondefined").

sinnsro 7 hours ago [-]
[dead]
meesles 8 hours ago [-]
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.

amazingman 8 hours ago [-]
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.

If you're going to make claims, support them.

thunky 45 minutes ago [-]
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.
pansa2 7 hours ago [-]
> that’s faster

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.

osigurdson 6 hours ago [-]
I don't think anyone says: "I switched from Python to Ruby" (of vice versa) for performance.
pansa2 6 hours ago [-]
True. Choosing between the two languages usually comes down to their library ecosystems - or more bluntly, to Rails on one hand vs NumPy on the other.

Nonetheless, it's still common for people to talk about the relative performance of the two languages, and to claim that Ruby is slower than Python. As someone who's actually tested this, it hasn't been true for 15 years.

voidfunc 8 hours ago [-]
Python is great and I love writing glue in it, but Ruby is just a better designed language and ecosystem overall.
block_dagger 8 hours ago [-]
Why? Because Python is generally slower, uses significant whitespace in its syntax, and lacks the metaprogramming features of Ruby.
BurningFrog 8 hours ago [-]
A lot of times 2-3 lines of Ruby needs 5-8 lines in Python.
maz1b 18 hours ago [-]
It's never Christmas without a new ruby version.

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!
WJW 15 hours ago [-]
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.

byroot 15 hours ago [-]
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.

WJW 14 hours ago [-]
I know they run truly parallel when they're doing work, but GC still stops the world, right?

Assuming you mean "because with Ruby::Box classes and modules have an extra indirection to go though." in the second paragraph, I don't understand why that would be necessary. Can't you just have completely separate boxes with their own copies of all classes etc, or does that use too much memory? (Maybe some COW scheme might work, doodling project for the holidays acquired haha)

Anyway, very cool work and I hope it keeps improving! Thanks for 4.0 byroot!

byroot 14 hours ago [-]
> GC still stops the world, right?

Yes, Ractor local GC is the one feature that didn't make it into 4.0.

> Can't you just have completely separate boxes with their own copies of all classes etc, or does that use too much memory?

Ruby::Box is kinda complicated, and still need a lot of work, so it's unclear how the final implementation will be. Right now there is no CoW or any type of sharing for most classes, except for core classes.

Core classes are the same object (pointer) across all boxes, however they have a constant and method table for each box.

But overall what I meant to say is that Box wouldn't make GC any easier for Ractors.

tebbers 17 hours ago [-]
I've been doing

  if condition1 && 
       condition2
       ...
  end
for ages and it seems to work find, what am I missing with this new syntax?!
AlecSchueler 15 hours ago [-]
I prefer the new way because if you want to remove one condition you just delete the line rather than having to edit in multiple places.
flopsamjetsam 6 hours ago [-]
I first picked up this style from the GNU C++ style guide, and it's so handy I use it in every language that accepts it.
Sammi 17 hours ago [-]
Less likely to cause git merge conflict as you don't change the original line. You only add one.
pmontra 15 hours ago [-]
What we need is a syntax aware git diff https://news.ycombinator.com/item?id=42093756
bbkane 12 hours ago [-]
I agree, but I tend to find that "git diff aware syntax" also makes things simpler for humans as well
fuzzythinker 16 hours ago [-]
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.
mathgeek 9 hours ago [-]
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).
mantas 17 hours ago [-]
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.
zelphirkalt 14 hours ago [-]
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.
RomanPushkin 17 hours ago [-]
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.

pansa2 13 hours ago [-]
> 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.

thunky 28 minutes ago [-]
> 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.

empthought 13 hours ago [-]
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.

Why would you write something so clearly false?

chucke 5 hours ago [-]
Both are true. Different camps meant that any significant change to the language was scrutinised loudly. If my memory doesn't fail me, the last significant changes from the time Guido was still in charge, and he mostly abandoned the BDFL because of backlash. Since then python has been on a constant "analysis paralysis" state, with only efforts about performance pushing through (no one complains about a faster horse).
woodruffw 3 hours ago [-]
> If my memory doesn't fail me, the last significant changes from the time Guido was still in charge, and he mostly abandoned the BDFL because of backlash

I think Guido left the BDFL role in 2018, and we’ve gotten walrus operators, structured matching, and exception groups since then (just off the top of my head). There’s also been significant language/grammar accommodations towards type annotations.

Overall, I’m of the opinion that Python’s language evolution has struck a pretty nice balance — there’s always going to be something new, but I don’t feel like the syntax has stagnated.

aobdev 6 hours ago [-]
Have you worked on different types of Python projects? (Not in different codebases, different types of codebases)

I don’t have any specific complaints about Python syntax because I can force it to get the job done…but homogeneous, it is not.

4 hours ago [-]
jurgenkesker 14 hours ago [-]
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.
blandflakes 10 hours ago [-]
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.

dmux 2 hours ago [-]
> I believe that the benefits of static typing somewhat decrease in the web arena

I’ve seen this sentiment expressed numerous times and have never found it to be true in my own work (e-comm), do you mind mentioning _what_ type of domain your web apps are in?

Edit: or if not domain, what do you mean by “web arena”

0xblinq 15 hours ago [-]
Just by how much better the editor/IDE support is with Python it is a change worth to do.

I just can’t stand the excessive dynamism of Ruby. I understand some people prefer/enjoy it, it’s just not for me.

Bayko 15 hours ago [-]
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)
firemelt 10 hours ago [-]
I get the sentiment, pandas, numpy, pytorch

but I still love writing full stack webapp using rails so yeah

thats why I really love pyCall

lcnmrn 17 hours ago [-]
You should try Falcon too.
nurettin 15 hours ago [-]
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.

nix-zarathustra 14 hours ago [-]
RubyMine is free for non-commercial usage.
nurettin 12 hours ago [-]
Ah, that must be a recent development.
michaelcampbell 5 hours ago [-]
It is; last couple months.
aaronbrethorst 19 hours ago [-]
It wouldn't be Christmas without a new version of Ruby. Thanks Matz and co!
bvan 6 hours ago [-]
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?
dueyfinster 5 hours ago [-]
I've done the pragmatic studio elixir and erlang courses and they are high quality. They do the same for Ruby and Rails[1]

[1]: https://pragmaticstudio.com/rails

digitaltrees 16 hours ago [-]
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.
mierz00 16 hours ago [-]
Curious to hear more about this, do you have any examples?
szundi 13 hours ago [-]
[dead]
matltc 16 hours ago [-]
Glad to see internal stack traces cleaned up (maybe we can get relative paths some day?) and Set finally get the respect it deserves!
Alifatisk 15 hours ago [-]
Relative path in stack trace would be so good!
mikestorrent 18 hours ago [-]
Still love Ruby deeply even though I now work somewhere where it's not in use. Thanks for the release, I hope I find a reason to use it!
__float 7 hours ago [-]
If I remember correctly, the namespaces feature (now released as Ruby::Box) had some pretty severe performance penalties (possibly even for code that doesn't use it?).

Does anyone know if that's been improved?

Bolwin 17 hours ago [-]
Have they improved tooling? I've yet to get any lsp working on windows
ornornor 16 hours ago [-]
IMO programming on windows is just asking for punishment. Unless it’s a Microsoft language, you’re so much better off on Linux or macOS.
koshersalt 7 hours ago [-]
That’s cool if you can, but the majority of business desktops/laptops runs Windows. Hard to gain enterprise traction when it’s hard to run tools on your local machine
cwyers 6 hours ago [-]
Just use WSL2 and Docker Desktop. VS Code has DevContainer support so you can standardize on a Docker image for your project.
nurettin 15 hours ago [-]
To be fair, vscode and .net core on linux is pretty much like having windows and visual studio at this point.
array_key_first 8 hours ago [-]
Without the debugger, unfortunately. You still need VS or Rider for that.
seabrookmx 5 hours ago [-]
The debugger works fine on Linux?

The only thing missing are some profiling tools.

If you really need those you're better off with Rider which is integrated with DotTrace.

nchmy 16 hours ago [-]
Or wsl2
Alifatisk 15 hours ago [-]
It’s below expectations, and even worse on Windows.

Luckily people seem to be aware of this and there was a whole talk about improving Ruby DX.

epolanski 14 hours ago [-]
Tried WSL2?
nomilk 15 hours ago [-]
What's the relevance of ractors to the average web dev? Will ractors be useful directly in controllers/models/tasks? Or is it more that ractors will be useful to those working on the ruby language (and perhaps some gems - lower level stuff, perhaps), and therefore to the average ruby(/rails) programmer things 'just work', but faster?
Exuma 9 hours ago [-]
I love ruby so much
ksec 18 hours ago [-]
It seems Ractor is still work in progress while Fiber has matured a lot in the last few releases.

I vaguely remember reading Shopify is using Fiber / Rack / Async in their codebase. I am wondering if Rails will get more Fiber usage by default.

byroot 15 hours ago [-]
> It seems Ractor is still work in progress

The Ractor experimental status could almost be removed. They no longer have known bugs, and only one noticeable performance issue left (missing Ractor local GC).

But the API was just recently changed, so I think it's better to wait another years.

> I vaguely remember reading Shopify is using Fiber / Rack / Async in their codebase.

Barely. There is indeed this management obsession for fibers even when it doesn't make sense, so there is some token usage there and there, but that's it.

There is one application that was converted from Unicorn to Falcon, but falcon isn't even configured to accept concurrent requests, the gain is basically 0.

As for Rails, there isn't much use cases for fibers there, except perhaps Active Record async queries, but since most users use Postgres and PG connections are extremely costly, few people are using AR async queries with enough concurrency for fibers to make a very noticeable difference.

ksec 14 hours ago [-]
I just search for the tweet again and it state [1] "Falcon is now serving most of Shopify storefront traffic: web and API.", or is that an out of context quote?

[1] https://x.com/igrigorik/status/1976426479333540165

byroot 14 hours ago [-]
I know that tweet, it's real, but that doesn't contradict my comment.

They indeed replaced Unicorn by Falcon in one application, but falcon is configured in "Unicorn mode" (no concurrent requests). So the gain is effectively 0.

Also note how they don't share any performance metrics, contrary to https://railsatscale.com/2023-10-23-pitchfork-impact-on-shop...

ksec 12 hours ago [-]
Thanks. That makes more sense.
shevy-java 18 hours ago [-]
To me it seems very few people use ractors. A bit more use fibers though.

It's a bit of a mess IMO. I'd much prefer everything be simplified aggressively in regards to threads + GIL; and Ractors integrated on top of Ruby::Box to provide not only namespaced container-like entities but also thread-support as a first-class citizen at all times. The API of ractors is weird and really not fun to use.

Lammy 16 hours ago [-]
I really enjoyed using them for my Ruby file-matching library where I wanted to read `shared-mime-info` XML source package files directly and on the fly as opposed to using the pre-processed secondary files that the upstream `update-mime-database` tool spits out. The problem is that a type definition can be spread out over multiple XML packages in both system and user paths, so the naïve implementation of reading them all at once wastes a massive amount of memory and a massive number of object allocations (slow) when most people use maybe 5% of the full set of supported types (the JPEGs and HTMLs and ZIPs of the world).

I wanted to read the source package files directly because I always found `shared-mime-info`'s usual two-step process for adding or editing any of the XML type data to be annoyingly difficult and fragile. One must run `update-mime-database` to decompose arbitrarily-many XML packages into a set of secondary files, one all-file-extensions, one all-magic-sequences, one all-aliases, etc. System package managers usually script that step when installing software that come with their own type data. I've accidentally nuked my entire MATE session with `update-mime-database` before when I wanted to pick up a manual addition and regenerated the secondary files while accidentally excluding the system path that had most of the data.

I ended up doing it with four Ractors:

- a Ractor matching inputs (MIME Type strings, file extensions, String or Pathname or URL paths for sniffing) against its loaded fully-formed type definition objects.

- a Ractor for parsing MIME Type strings (e.g. "application/xml") into Hash-keying Structs, a task for which the raw String is unsuitable since it may be overloaded with extra syntax like "+encoding_name" or fragment ";key=value" pairs.

- a fast XML-parser Ractor that takes in the key Structs (multiple at once to minimize necessary number of passes) and figures out whether or not any of those types are defined at all, and if so in which XML packages.

- a slow XML-parser Ractor that takes the same set of multiple key Structs and loads their full definition into a complete type object, then passes the loaded objects back to the matcher Ractor.

The cool part of doing it this way is that it frees up the matcher Ractor to continue servicing other callers off its already-loaded data when it gets a request for a novel type and needs to have its loader Ractors do their comparatively-slow work. The matcher sets the unmatched inputs aside until the loaders get back to it with either a loaded type object or `nil` for each key Struct, and it remembers `nil`s for a while to avoid having to re-run the loading process for inputs that would be a waste of time.

The last pre-Ractorized version allocated around 200k objects in 7MiB memory and retained 17k objects in 2MiB of memory for a benchmark run on a single input, with a complete data load. The Ractorized version was twice as fast in the same synthetic benchmark and allocated 20k objects in 2MiB of memory and retained 2.5k objects in 260KiB of memory for its initial minimal data load. I have it explicitly load `application/xml` and `application/zip` since those combined are the parent types for like a third of all the other types, and a few other very common types of my choosing.

I think a lot of the barrier to entry for Ractors isn't the API for the Ractors themselves but in figuring out how to interact with Ractorized code from code that hasn't been explicitly Ractorized (i.e. is running in the invisible “main” Ractor). To that end I found it easiest to emulate my traditional library API by providing synchronous entry-point methods that make it feel no different to use than any other library despite all the stuff that goes on behind the scenes. The entry methods compose a message to the matcher Ractor then block waiting for a result or a timeout.

I also use Ractors in a more lightweight way in my UUID/GUID library where there's a Ractor serving the incrementing sequence value that serves as a disambiguator for time-based UUIDs in case multiple other Ractors (including invisible “main”) generate two UUIDs with the same timestamp. Speaking of which, I'm going to have to work on this one for Ruby 4.0, because it uses the removed `Ractor.take` method.

16 hours ago [-]
auraham 6 hours ago [-]
I gave it a try a few months ago. The first thing that I searched for was the REPL. Comparing it with Python, I prefer ipython over irb. It would be nice to see some improvement on DX on the REPL side
Lio 4 hours ago [-]
What actionable things do you think IRB is missing vs ipython?
pmdr 14 hours ago [-]
3.x has been awesome, let's hope 4 will be even better!
schneems 6 hours ago [-]
Now available on Heroku https://devcenter.heroku.com/changelog-items/3521
ekvintroj 18 hours ago [-]
My best Christmas gift <3 Love you Ruby.
zhisme 9 hours ago [-]
Am I the only one who expected something bigger in a major release? With Ruby 3 we had the whole “3x3” story and significant performance improvements. This release feels more like a minor version, something closer to 3.5.

I don’t want to downplay the work done by the maintainers on the contrary, huge thanks to them. But I do feel the version number is a bit misleading.

That said, the work on the ZJIT[1] compiler is massive. It’s serious, professional engineering, and definitely deserves respect.

[1]: https://rubykaigi.org/2025/presentations/maximecb.html

werdnapk 5 hours ago [-]
I think the major version change is more of a celebratory thing with Ruby being 30 years as of 2025.
Doctor_Fegg 6 hours ago [-]
Ruby doesn’t follow semver.
codesnik 6 hours ago [-]
eh, it's just a little celebration. Let Matz have it.
prh8 4 hours ago [-]
One issue is gems which are locked `ruby < 4.0` which will now require updating, and releasing 4.0 instead of 3.5 was only done very recently.

For a more concrete example, the grpc gem locks Ruby versions (< 3.5), and they refuse to change it. So until they support the next Ruby version, we could test ruby-next by testing with a preview release. This worked for 3.4 and 3.5, but now doesn't work with 4.0 (bundler resolves 4.0-preview2 > 3.5, whereas we are able to do 3.5-preview1).

So unless I feel like doing a lot of grunt work (which I don't), I can't even test Ruby 4 in our app until they release a new version. And while I recognize this is an issue with the gem, it is a consequence of choosing to do 4.0.

msie 5 hours ago [-]
I would like multi-line comments to make it into Ruby one day.
riffraff 3 hours ago [-]
But they have always been there? =begin/=end, perldoc style.
nish__ 19 hours ago [-]
Ruby::Box looks useful.
shevy-java 18 hours ago [-]
Right now it is just the foundation I guess. That is, more work to be put on top of it. byroot kind of pointed that out that the proposal reminds him of containers and I think this is the long-term goal eventually, e. g. namespaced isolated containers. At a later time, I think, the syntax for refinements may be simplified and also be integrated into Ruby::Box, since Ruby::Box is kind of a stronger refinement in the long run. But that's my take; ultimately one has to ask matz about the changes. What he did say on the bugtracker was that this is to be considered a low-level API e. g. a foundation work. So things will be put on top of that eventually.
desireco42 19 hours ago [-]
This really makes Christmas festive. I don't think I need new features, but sure love simplicity of 4.0.

I am installing it now. Thank you Matz and team.

magmostafa 14 hours ago [-]
Ruby 4.0's parallel execution improvements are a game-changer for the ecosystem. The ruby::Box feature addresses one of the biggest pain points - GIL limitations - while maintaining Ruby's elegance.

What's particularly exciting is how this positions Ruby for modern workloads. With proper parallelism, Ruby apps can finally compete with Go and Node.js in concurrent scenarios without sacrificing developer happiness.

The typing improvements also can't be understated. Gradual typing strikes the right balance - it helps teams scale codebases without forcing the verbosity of Java or the complexity of TypeScript's type gymnastics.

Looking forward to seeing how the Rails ecosystem adopts these features. This could spark a Ruby renaissance in 2025.

jadbox 8 hours ago [-]
> "With proper parallelism, Ruby apps can finally compete with Go and Node.js in concurrent scenarios without sacrificing developer happiness"

In theory, maybie. Parallelism support isn't a boolean though as there's a lot of additional factors at play. Just as one example, late stage Visual Basic also got parallelism support, but it really didn't help the overall positioning of the the language among its peers.

codesnik 6 hours ago [-]
from what I understand, ruby::Box has nothing to do with GIL. At least, not yet.
13 hours ago [-]
magmostafa 14 hours ago [-]
Exciting to see Ruby 4.0.0 released! The new conditional syntax improvements (if condition1 && condition2) are really elegant. The Ruby::Box feature for true parallelism looks particularly promising for CPU-bound workloads. This could significantly improve performance in scenarios where we've historically had to resort to external services or other languages. Looking forward to seeing real-world benchmarks and adoption patterns emerge.
andrewinardeer 18 hours ago [-]
It truly is Christmas.
ergocoder 18 hours ago [-]
I haven't looked at Ruby for a long time. I've moved away due to the lack of typing. Any degree of typing would be helpful. Does it support typing yet?
rsanheim 17 hours ago [-]
_low_type_ is early days still, but I think this approach is clearly the future of ruby typing. If this gets baked into the language for full “compile” time support and minimal performance impact, it will be amazing: https://github.com/low-rb/low_type
Alifatisk 15 hours ago [-]
Previously, RBS-inline was the closest answer to typed Ruby, it was the JSDoc of Ruby. Recently, when I stumbled upon low_type and tried it out in irb, it finally felt like ”this is it, this is the TS of Ruby” and with runtime validation.

I like it, it deserves attention, especially for those who are seeking for typed Ruby. With this, you can finally experience it, and the syntax feels more ergonomic than with Sorbet.

fny 9 hours ago [-]
This is so goergeous compared to the mess that's out there now.
ksec 16 hours ago [-]
It is definitely better than RBS and Sorbet. But unless Github / 37Signals or Shopify decide to use it, it is highly unlikely Ruby Core will consider it.

Out of all three I think Shopify have the highest possibilities. There may be additional usefulness interms of ZJIT.

dajonker 14 hours ago [-]
In my honest opinion, if you can't live without static typing, Ruby just isn't for you.

Adding static typing to a dynamic language mostly gives you the disadvantages of both, without a lot of benefits. It's better to stick to languages that were designed with static types from the start.

I love programming in Ruby, having to worry about type annotations and the additional constraints that come with them would take a lot of the fun out of that.

networked 12 hours ago [-]
> Adding static typing to a dynamic language mostly gives you the disadvantages of both, without a lot of benefits.

Can you elaborate? I don't share this experience, and I'm interested in bringing static typing to a language without static typing, so I'd like to understand. In new Python and JavaScript codebases, optional typing has had clear benefits for refactoring and correctness and low costs for me. Legacy codebases can be different.

dajonker 2 hours ago [-]
I don't have a great code example at hand unfortunately, but I found that people often tend to write more "nominally" typed code (expecting explicitly named classes) rather than taking advantage of duck typing (interfaces, structural types), meaning the code becomes more rigid, harder to change and more time wasted on resolving all the type checks, even if the code otherwise is perfectly reasonable and free of bugs.

In other words, I found that the resulting code often looked more like Java but with weaker guarantees about types and much worse performance.

azuanrb 11 hours ago [-]
Part of it is because Ruby imo, have a very nice syntax. With type annotation, it's becoming "ugly", a lot more verbose. It's no longer English-like. I do agree type have some advantages, but we need to get the DX right.

I've been using Ruby for more than 10 years now, and I only started using LSP recently. To me it's a nice addition but I can live without it. Type is just one of the tools, not the only one imo. Not trying to sound negative but type is becoming more like a hammer analogy nowadays.

And it's not limited to Ruby. Javascript, Python, all similar languages. Not everyone is a fan of type. We won't reach consensus imo and that's ok.

clanky 9 hours ago [-]
> With type annotation, it's becoming "ugly", a lot more verbose. It's no longer English-like.

In our codebase that uses Sorbet I find this is really only true at function boundaries. Within a function it is pretty rare that anything needs to be spelled out with inline annotations to satisfy the compiler.

codesnik 5 hours ago [-]
This is my biggest irk about Sorbet: because its signatures are wordy and because it can't infer the generic type of a private method, it slightly pushes you towards NOT extracting helper methods if they are going to be 2-5 lines. With Sorbet annotation, it'd easily become 10 lines. So it pushes towards bigger methods, and those are not always readable.

If only private methods would be allowed not having typing at all (with a promise of not being used in subclasses, for example), and Sorbet would be used mostly on the public surface of classes, it'd be much more tolerable for me.

clanky 9 hours ago [-]
> Adding static typing to a dynamic language mostly gives you the disadvantages of both, without a lot of benefits.

As an engineer at a firm doing heavy duty data pipelines and internal tooling in a Sorbet-ified codebase, I disagree pretty strongly. While Sorbet type signatures are never going to win a syntax beauty contest, they are more than worth their weight in the way I can rely on them to catch typing and nilability goofs, and often serve as helpful documentation. Meanwhile, the internal code of most functions I write still looks like straight Ruby, fluent and uncluttered.

A good CI story that leans on tapioca was crucial here for us.

vidarh 12 hours ago [-]
I mostly agree with you, but I'd say adding typing to low level core APIs is helpful in adding optimization opportunities.
ufmace 9 hours ago [-]
I've come to think that adding halfway-typing to languages designed from the start to be dynamic is mostly not worth the bother. It may help a little bit sometimes, but there's always going to be holes. If you really want strong typing, it's better IMO to bite the bullet and move to a language designed for it. Let Ruby be Ruby, ditto Python, Javascript etc. Pick up some JVM, .NET, Rust, Go, etc if you really want strong types.
vmware513 17 hours ago [-]
Unfortunately, the type support is still useless. I abandoned Ruby for the same reason, and it is still relatively slow and eats a lot of memory.
dismalaf 17 hours ago [-]
It's literally faster than Python but ok.
morcus 17 hours ago [-]
Is being faster than Python considered to be a notable feature?
gkbrk 17 hours ago [-]
Python is one the most popular programming languages. Ruby fits into a similar category as Python (high level, interpreted scripting language, very dynamic, has a rich ecosystem with tons of existing code). Being faster than Python makes it more attractive to use, or port Python codebases to.
wiseowise 14 hours ago [-]
Nobody cares about Ruby outside of RoR

Python is one of the Lingua Franca of scientific, data, and most importantly, ai communities

Has much bigger community than Ruby

Has much, much better tooling story

Has much better gradual typing story

Isn’t THAT much slower than Ruby, there are far more attractive targets than Ruby if you care about performance

dismalaf 9 hours ago [-]
> Python is one of the Lingua Franca of scientific, data, and most importantly, ai communities

You mean it's the most used frontend for all the C and C++ libraries that are used for scientific computing, data and AI.

wiseowise 9 hours ago [-]
Semantics.
dismalaf 8 hours ago [-]
Literally all those libraries are usable with Ruby. Libtorch, BLAS, LAPACK, Tensorflow, etc...
wiseowise 7 hours ago [-]
And with Java, and with Go, and with Rust, and with pretty much any language offering some form of FFI. But they're used with Python, and good luck convincing your interviewer that it should be used with Ruby.
dismalaf 6 hours ago [-]
> convincing your interviewer

Some of us don't work for others and just program what we want.

wmoxam 11 hours ago [-]
I found scrooge.

Bah, humbug!

dismalaf 16 hours ago [-]
Personally I don't care about speed for this category of language. I just bring it up because Python is one of the most used languages, is even slower, yet that's never held against it. Just seems like a lazy way to dismiss Ruby. Yeah, it's not as fast as C, Go, Rust or Java. Everyone knows and raw speed obviously isn't the point of a dynamic scripting language...
wiseowise 14 hours ago [-]
And has no ecosystem compared to Python.

Speed isn’t why people choose Python.

bl4kers 39 minutes ago [-]
There's a Ruby gem for almost anything
riffraff 17 hours ago [-]
There's an official format for defining types in separate files (RBS) and some tooling to type check them (matz doesn't like types next to the source code).

There's a pretty battle tested tool to define inline types as ruby syntax and type check both statically and at runtime[0].

It's still not a particularly nice situation imvho compared to typescript or python, but there's been some movement, and there's a newsletter that follows static typing developments [1] which may give you some insights.

0: https://sorbet.org/

1: https://newsletters.eremin.eu/posts

adamors 17 hours ago [-]
I’ve used Sorbet on a project for 2 years recently and it honestly was the final nail in the coffin for Ruby for me.

Really rough around the edges, lots of stubs have to be added because support for gems is lackluster but whatever Sorbet generates are hit or miss etc. So you end up writing a lot of hard to understand annotations and/or people get frustrated and try to skip them etc.

Overall a very bad DX, compared to even typed Python. Don’t even want to compare it to TS because then it becomes really unfair.

mrinterweb 17 hours ago [-]
There is [RBS](https://sorbet.org/) (part of ruby 3) and [sorbet](https://sorbet.org/). To be honest, these aren't widely used as far as I am aware. I don't know if it is runtime overhead, ergonomics, lack of type checking interest in the ruby community or something else. Type enforcement isn't a big part of ruby, and doesn't seem to be gaining much momentum.
vicentereig 15 hours ago [-]
I’ve been leaning hard into Sorbet runtime types for DSPy.rb[0] and finding real value. T::Struct at API boundaries, typed props for config, runtime validation where data enters the system.

For generating (with LLMs) API clients and CLIs it’s especially useful—define the shape once, get validation at ingress/egress for free.

Maybe momentum is happening in new projects rather than retrofits? [0] https://oss.vicente.services/dspy.rb

pmontra 14 hours ago [-]
> lack of type checking interest in the ruby community

IMHO if we wanted to write types in our programming language we would not have chosen Ruby for our programming tasks. We would have chosen one of the zillion of other languages. There were a lot of them when Ruby got traction about 20 years ago and many other languages have been created after then. It's not surprising that one of the main proponent of typing in Ruby is Shopify, because their path away from Ruby is very costly.

In my case one of the reasons I invested in Ruby is precisely because I did not have to write types.

Does it make Ruby slower than Java, my main language in 2005? Yes.

Is it fast enough for my customers? Yes. Most of them decided to use Ruby, then hired me.

Do I have to write unit tests to check for types? I don't.

Occasional problems that static types would have prevented to happen? Once or twice per year. Overall that's a good tradeoff because pleasing the type checker for non trivial types can be a time consuming task and some errors happen at runtime anyway, when the real world hits with its data a carefully type checked code base or a carelessly dynamic typed one. Think of an API suddenly returning a bad JSON, maybe an HTML 500 page. Static or dynamic typing, both won't help with that.

weaksauce 6 hours ago [-]
another early days project but pretty well thought out in that space: https://github.com/yippee-fun/empirical/blob/main/literally_...
jweir 17 hours ago [-]
We have been adding Sorbet typing to our Rails application and it is a positive enhancement.

It’s not like Ruby becomes Haskell. But it does provide a good deal of additional saftey, less testing, LSP integration is good, and it is gradual.

There is a performance hit but we found it to be quite small and not an issue.

But there are area of our application that use Grape and it is too meta for Sorbet so we don’t try and use it there.

vicentereig 15 hours ago [-]
Same here. T::Struct and T::Enums at API boundaries has been the sweet spot—typed request/response models, runtime validation at ingress/egress.

I’ve been using this pattern for API clients[0] and CLIs[1]: define the shape once with Sorbet, get automatic JSON Schema generation when you need it.

[0] https://github.com/vicentereig/exa-ruby [1] https://github.com/vicentereig/lf-cli

lgas 7 hours ago [-]
> It’s not like Ruby becomes Haskell.

Well, maybe next time.

Gigachad 17 hours ago [-]
There’s projects trying to implement it. But I’ve never seen a project using typed Ruby.

I think most people who cared just moved to typescript.

godd2 5 hours ago [-]
Ruby has always been typed.