From: "fxn (Xavier Noria) via ruby-core" <ruby-core@...>
Date: 2023-11-06T16:05:36+00:00
Subject: [ruby-core:115279] [Ruby master Bug#19990] Could we reconsider the second argument to Kernel#load?

Issue #19990 has been updated by fxn (Xavier Noria).





Let me add that example with `::A` is just _one_ way to illustrate lack of transparency.



There are many others, for example:



```ruby

class String # expected to reopen ::String

  def foo

  end

end



"".foo # expected to work

```



That program works normally, but raises `NoMethodError` if loaded with `load program, true`.



Bottom line is, the moment you unilaterally change the nesting to the loaded file, all kind of unexpected things may happen because the assumptions of the programmer of that file do not hold anymore (unless there is coordination).



This cannot be transparent. It is just a matter of looking for the consequences of loosing your control over the nesting.



----------------------------------------

Bug #19990: Could we reconsider the second argument to Kernel#load?

https://bugs.ruby-lang.org/issues/19990#change-105195



* Author: fxn (Xavier Noria)

* Status: Open

* Priority: Normal

* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN

----------------------------------------

The documentation of `Kernel#load` says:



> If the optional wrap parameter is true, the loaded script will be executed under an anonymous module, protecting the calling program���s global namespace. If the optional wrap parameter is a module, the loaded script will be executed under the given module. In no circumstance will any local variables in the loaded file be propagated to the loading environment.



I'd like to ask you to reconsider this feature.



First of all, "protecting the calling program" is not really accomplished because the loaded file may still do this



```ruby

class ::C # defines ::C regardless of the second argument

end

```



Another example, if the caller defines a module `M`, then the loaded program can also define things in `M`:



```ruby

class M::C # defines ::M::C regardless of the second argument

end

```



It does not even need a leading `::`.



So, the "protection" is not really there.



In addition to that, this is not transparent for the code being loaded either. For example, let's take this program:



```ruby

class A

end



module X

  ::A # could be needed if your own lookup had an A somewhere you want to skip

end

```



the Ruby programmer expects that to work. But with this feature, on paper, nobody knows if it wil work. How can you ship code confidently?



So, the documentation should say:



> It kind of protects, but not really. Also, the loaded file may not work as expected, or may not even be loadable at all.



That hypothetical documentation suggests to me it would be worth revisiting this feature.



In Ruby, as it is today, things are global. The language does not have features to really isolate code as containers do, for example.



I believe the 2nd argument to `Kernel#load` steers the API in a direction that is not consistent with the language, and provides a feature that is only partial and cannot satisfy what it promises.



I'd be in favor of deprecating and eventually removing this API.







-- 

https://bugs.ruby-lang.org/

 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/