Hey,
I am not a zeitwerk user yet, but I am very interested about the pros and cons regarding the dry system default loader and the zeitwerk plugin?
I don’t quite understand why I should need auto loading (eager and lazy) when I have auto registration available (eager and lazy).
Thanks
I don’t use any of Zeitwerk’s eager loading directly, myself. I let Zeitwork load what I need using it’s standard block syntax. I’ve written an article that details this in case it’s of interest. I’m not sure it answers your direct question but might provide additional insight.
1 Like
The original loader was a simple mechanism to perform require
for you automatically.
Zeitwerk adds some additional, intelligent behavior that you may want.
- module namespacing
Given two different forms of nested class names
module Foo
module Bar
class Baz
end
end
end
class Foo::Bar::Baz
end
You may want to use the second, terser syntax for convenience.
Zeitwerk will traverse this namespace and generate Foo
and Bar
for you, if they do not yet exist. This avoids common pitfalls when using one-line syntax that can result in buggy constant resolution. This behavior alone makes zeitwerk worth having.
- constant reloading
Since the original Loader utilized require
, code changes that happen in development after the container key is resolved would not be loaded. The Zeitwerk loader makes this possible, so that you can have the same reloading ability you have in Rails.
- direct constant reference
This can be a double-edged sword, Rails relies too heavily on globals and constants, but Zeitwerk enables you to reference your autoloaded constants directly without requiring them first. The original loader only worked when you resolved a container key, but sometimes referencing a constant is simpler.
For example, you may need to reference an Entity or a ROM Command etc without relying on a specific instance.
2 Likes
Great question, thanks for bringing it here, @wuarmin!
@alassek provides a wonderful answer here that also goes into detail on some of the extra features that Zeitwerk offers.
If I could make my own contribution here, I’d say the difference between the default (original) loader and the autoloading loader (i.e. the one that works with Zeitwerk), it would be this:
- With the default loader, every time you want to reference another constant within your application, you must
require
the file that contains that constant. In this way, the default loader will also use require
to load any files for components for your container.
- With the autoloading loader (and a matching Zeitwerk setup, which you can now get via the
use :zeitwerk
plugin!), you no longer need to write manual requires. In the same way, the autoloading loader will not use require
when loading the components in your container; instead, it simply directly references the class constant to load the autoloader do its job to load it.
That’s it, the key difference. You can see it quite clearly via the code for the autoloading loader too:
class Autoloading < Loader
class << self
def require!(component)
constant(component)
self
end
end
end
It’s literally one overridden method that will just access the constant instead of calling require
.
Everything else that Zeitwerk offers here is just gravy on top of not needing to manually require. You can choose yourself which of those Zeitwerk features to leverage in your application, if any.
My biggest motivation for adding the autoloading loader was just to remove the burden of dry-system users having to “require what you require”. That approach is a fine way to build systems, but it’s definitely extra friction, and with the work I’m doing to bring dry-system and Hanami 2.0 together, I want to make sure we can provide as streamlined an experience as possible.
2 Likes