Chris Salzberg (@shioyama) on X

X (formerly Twitter) ·

3 min read Original article ↗

user avatar

I have some skin in this game: I gave a talk called "Multiverse Ruby" at RubyKaigi 2023 that inspired Satoshi to do his work. My talk was about a fork of Zeitwerk called "im" that enabled you to share code on an anonymous namespace via autoloading.

user avatar

Satoshi loved the talk but wanted to go much further than I had gone and actually change Ruby from the inside. He created a ticket on the Ruby bug tracker to propose his idea, and got some pushback initially but also support and curiosity. bugs.ruby-lang.org/issues/19744

user avatar

Satoshi now has working code that implements his proposal, which he demo'ed in his talk. The basic idea is that he would add a new subclass of the Module class, called Namespace. You can require any code under a namespace by calling `require` on the namespace.

user avatar

What happens when you do this is that the code is loaded in an isolated space, with the top of its "universe" being the namespace module. There are some fascinating things that fall out of this idea.

user avatar

The first one is that any monkeypatches in the loaded code apply only under the namespace, and not outside of it. So for example you can require all of Rails, including ActiveSupport, and have the core ext monkeypatches apply _only_ inside Rails and its dependencies.

user avatar

One very mind bending repercussion of this: if you pass a string created outside the namespace, without monkey patches like `present?`, _into_ the namespace, it suddenly "acquires" the patches when it is inside. But if it leaves again, it loses them.

user avatar

This sounds crazy, and I had my doubts that it could work. But the more I think about it, the more I realize that it is entirely consistent. It works. Not only that, but it creates the foundation for a new, better form of packaging in Ruby. This is what Matz is so excited about.

user avatar

Fundamentally, what the namespace feature does is reverse the tables in how code is shared. Up until now, code sharing in Ruby has been a lop-sided exchange where the requiree--the code you are loading--has all the control. It has access to everything, so it can change anything.

user avatar

If this is hard to visualize, the best analogy I can think of is what docker and containers did for Linux. This is similar. With namespaces, you can load multiple applications in the same Ruby process and never worry about conflicts. Or even different versions of the same gem.

user avatar

This has people worried. Currently, if you are using gem A and gem B, and A depends on an outdated version of B, then you also have to depend on that outdated version. With namespaces, you could sidestep this and upgrade _your_ dependency on B while letting A depend on the old B.

user avatar

This is the kind of thing this feature will enable. Whether we want Bundler to allow that is another question. But without a doubt this feature will reshape how Ruby code treats dependencies and packaging. In the long term, this will be for the better, I am convinced of that.

user avatar