Project

General

Profile

Actions

Feature #19006

closed

Inconsistent behaviour of autoload in wrapped script

Added by shioyama (Chris Salzberg) over 1 year ago. Updated over 1 year ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:109924]

Description

Suppose I have two files, foo.rb and bar.rb:

# foo.rb

puts "loading Foo..."

module Foo
  autoload :Bar, "foo/bar"
end

and

# foo/bar.rb

puts "loading Foo::Bar..."

module Foo
  module Bar
  end
end

I can require "foo" and access both Foo and Foo::Bar:

require "foo"
# loading Foo...
#=> true
Foo::Bar
# loading Foo::Bar...
#=> Foo::Bar

However, if I load foo under a wrap module with load:

MyModule = Module.new
load "./foo.rb", MyModule
# loading Foo...
#=> true

... I'm now unable to access Foo::Bar anywhere, because whereas the constant is autoloaded from MyModule::Foo::Bar, it is required from the top-level as Foo::Bar:

MyModule::Foo::Bar
# loading Foo::Bar
#=> uninitialized constant MyModule::Foo::Bar (NameError)

This means that autoload is basically useless inside anything loaded with the wrap argument to load, because the file being autoloaded can't know in advance what the base namespace will be.

I would argue that it makes much more sense to apply the wrap module (top_wrapper) to any autoloaded file loaded when top_wrapper is set. In the example above, this would mean that accessing MyModule::Foo::Bar would work, since MyModule would apply when the autoload triggers to load foo/bar.

Updated by jeremyevans0 (Jeremy Evans) over 1 year ago

When loading foo.rb with the MyModule wrapper, you are loading the equivalent of:

module MyModule
  module Foo
    autoload :Bar, "foo/bar"
  end
end

foo/bar.rb defines ::Foo::Bar, not ::MyModule::Foo::Bar, so I think the error you receive when you attempt to load MyModule::Foo::Bar is expected.

load's wrapped module is not transitive to load/require/autoload calls inside the loaded file. It was never designed to be transitive, nor documented as being transitive, so I don't think the current behavior is a bug. Making the behavior transitive would be a feature request, IMO.

FWIW, I agree that the lack of transitivity makes load's wrapped module not very useful in practice. However, I don't see that as a problem.

Updated by shioyama (Chris Salzberg) over 1 year ago

  • Tracker changed from Bug to Feature
  • Backport deleted (2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN)

It was never designed to be transitive, nor documented as being transitive, so I don't think the current behavior is a bug. Making the behavior transitive would be a feature request, IMO.

Agree, I've changed the tracker to "feature" to reflect this.

FWIW, I agree that the lack of transitivity makes load's wrapped module not very useful in practice. However, I don't see that as a problem.

Agree with the first part, not sure though if I agree with the last part. This is really a larger discussion, but making load's wrapped module transitive to require, autoload, etc would open the door to a lot of interesting things (https://bugs.ruby-lang.org/issues/10320#note-13 etc.)

My goal is to leave Ruby itself as much unchanged as possible, but without transitivity at the language level it's virtually impossible to implement true namespace isolation at the gem level, which is my original goal. I also think there is a strong argument to be made that transitivity is at least as "natural" as the current implementation. e.g. require currently has to reset top_wrapper before doing its requiring; making require transitive actually entails removing code, not adding it.

Not suggesting we just suddenly change require to remove that line (obviously backwards compatibility is a thing), but providing something that would allow that to happen — maybe a flag? — would unlock a lot of latent potential in Ruby.

Updated by shioyama (Chris Salzberg) over 1 year ago

Rethinking this, autoload can fairly easily be patched at the gem level to make this work, without changes at the language level, so this isn't strictly necessary. In terms of transitivity, require is the more important one.

I'm happy to close this, thanks for the feedback!

Actions #5

Updated by jeremyevans0 (Jeremy Evans) over 1 year ago

  • Status changed from Open to Closed
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0