Feature #21311: Namespace on read (revised) – Ruby


While I believe namespaces would be a good addition to Ruby, I’m not convinced this particular implementation of
namespaces is what Ruby needs.

First, I’m not convinced by the motivations:

Avoiding name conflicts between libraries: Applications can require two different libraries safely which use the same module name.

Is this a problem that happens on a regular basis? I believe Ruby has a pretty well established convention
for libraries to expose a single module with a name that correspond to their gem name.

Actual top level module name clashes are extremely rare in my experience.

Avoiding unexpected globally shared modules/objects

Here again, from my experience this is very rare, and usually accepted as a bug, and promptly fixed.

Do we have concrete cases of this being a peristent problem?

Multiple versions of gems can be required

I remember there was discussions about this in the past. Personally this is a feature it’s quite strongly
against because it’s extremely hard to reason about.

If you have library A using the gem G in version 1, and library B using the gem G in version 2,
and end up with A being passed a G-v2 object, you may end up in a world of hurt.

I understand this feature would be useful for bundler specifically to allow them to use gems internally
without conflicting with the application (a problem they currently solve by vendoring), but outside
of that I’m not convinced it’s a desirable feature.

I get that it can happen that you end up in a sticky situation with two dependencies being essentially
incompatible because they require conflicting versions of another dependency, as it happened with the Faraday 2
transition a few years back, but I’m not convinced that working around the problem that way is a net positive.

Namespace monkey patches

This one isn’t in your ticket, but from previous public talks I understand it is one?

Here again I’d like to question how big of a problem monkey patches really are.
It is true that 15 years ago, numerous popular gems would irresponsibly monkey patch core classes,
but I believe these days are long gone. Except for ActiveSupport (that gets a pass for being a framework)
very few gems ship with monkey patch.

A notable exception being “protocol” type of methods, such as to_json, to_yaml, to_msgpack, etc.

In addition, I routinely use monkey patches to backport a fix onto a gem while waiting for a fix to be merged
and published upstream. If monkey patches became scoped to namespaces, this would make this sort of “monkey patches”
way harder. So to me it’s net negative.

Being able to namespace existing code

Again not listed in your motivations, but you explain pretty well that you want to be able to load arbitrary code
into a namespace, because you don’t want to have to modify the existing libraries.

It makes sense, but is it really that big of a need? I personally see namespaces as a feature libraries can
use to write more robust and isolated code. Not as a feature applications can use to workaround libraries.

Other issues

Deduplication

Assuming this implementation of namespaces become largely used, it means some versions of some libraries would
be loaded dozens and dozens of time in the same process. IIRC in some previous public talks you mentioned
the possibility of deduplication, what’s the status on this? Because without it, it’s a big concern to me.

With Python/Java/Node namespacing systems it’s an easily solved problem, because the file is essentially a
namespace objects, so you can just keep a map of file -> namespace_object, but here it seems way more involved.

What I think would be a positive

In order to not just be negative, I’ll try to explain what I think would be helpful.

Local namespace

A common complaint I hear from less experienced / occasional Ruby users is they are having trouble figuring out where constants are comming from,
because of the single global namespace.
They prefer the Java/Python/Node style, where each file is more or less its own namespace, and at the top
of the file you list your imports.

I think translated in Ruby, it could be emulated by only allowing to reference constants from outside the namespace
in a fully qualified way:

class SomeClass
end

namespace MyLibrary
  p SomeClass # NameError

  SomeClass = ::SomeClass # This is basically an import

  p SomeClass # works
end

In other word, I think namespaces could be somewhat similar to BasicObject but for modules.

Overly public constants

Another common issue I witnessed is publicly exposed constants, that aren’t meant to be public.

Being involved in a really big application, what people are trying to do to make that codebase more manageable
is to break it down in smaller components with the hope that a developer can more easily wrap their head around
a single component, that a component can be tested individually, etc.

This often fall appart because all constants are public by default, so other teams end up relying on APIs that
weren’t meant to be used.

I think it would be helpful if namespaces constants were private by default and you had to explictly “export” (publicize)
them.



Source link