ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: "shioyama (Chris Salzberg)" <noreply@ruby-lang.org>
To: ruby-core@ruby-lang.org
Subject: [ruby-core:109979] [Ruby master Feature#10320] require into module
Date: Wed, 21 Sep 2022 12:39:04 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-99228.20220921123904.7501@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-10320.20141002224417.7501@ruby-lang.org

Issue #10320 has been updated by shioyama (Chris Salzberg).


@mame 

> This approach looks not very robust. If there is a constant Foo defined in the top-level, I think it does not work.

Yes absolutely, this is the problem with `const_missing`. So this would ultimately need something at the language level.

To be clear, my goal is that Ruby implements the parts of this problem which are not implementable in gem code, and lets a gem like Im do the rest (similar to Zeitwerk's relationship to `autoload`).

@byroot

> IMHO it uses too many fragile monkey patches and Tracepoint hooks to approximate the desired result. I think such a feature would need to be baked in Ruby itself with probably a keyword etc. But in the meantime "Im" is an interesting experimentation ground.

Yes, I'm using whatever I can without changing Ruby too much to make things work. Also, it's of course a WIP.

But ultimately, my idea is for the gem to motivate the changes that are needed at the language level. I find the Tracepoint hook actually works ok (and Zeitwerk also uses Tracepoint), but the `const_missing` is definitely a temporary hack.

@shyouhei

> May I ask someone the problem this ticket is currently trying to address? I’m confused.

Matz talked about the problem ("better packages") in his [2021 Euruko talk](https://youtu.be/Dp12a3KGNFw?t=2956).

From my point of view, there are two major problems the proposal here would solve.

The first, namespace pollution, is the problem that gems can park themselves anywhere they like in the global namespace. Of course most gems are good citizens and limit themselves to a single module constant, but the fact that as a consumer of code (_any_ code) you have to _trust_ third parties not to pollute the shared namespace is, IMO, a huge problem.

The proposal here would make the consumer ("importer") of such code have full control over its position in the global namespace. As a user of a gem, you could name it whatever you want, or even pick and choose parts of the gem and put them wherever you want in your namespace (e.g. `AS = mod::ActiveSupport`). Of course this control is not _absolute_, since core top-level constants would be shared (so e.g. activesupport would still be able to patch shared classes) -- so this is not entirely without side-effects -- but nonetheless it would be a huge improvement over what we currently have.

Note this also would open the door to things Ruby has never been able to do, e.g. load two versions of the same gem in the same namespace. Useful? I don't know, but if it's not hard to do, I think Ruby should make it _possible_.

The second problem is the one that Jean mentioned. [Packwerk](https://github.com/Shopify/packwerk) has become quite popular among companies with large Rails monoliths as a way to isolate parts of the application by "enforcing" boundaries. But Packwerk adds yet another level of organization ("packages") on top of many others we already have ("gems", "modules", in the case of Rails also "engines", etc.)

What is to me so special about the idea here is that it would allow you to isolate parts of an application, while also sharing code as necessary.

e.g. `Shop` is a class that is used in many places in the Shopify monolith. We can "share" that class without sharing _all_ shop-related code like this:

```ruby
platform = import "components/platform"
shop_identity = import "components/shop_identity"

platform::Shop = shop_identity::Shop
```

To me, this is a very elegant way of representing dependencies between components of an application. Rather than just give a part of the code _full_ access to another part of the code (and vice versa), you just share whatever parts are needed, and not the rest.

----------------------------------------
Feature #10320: require into module
https://bugs.ruby-lang.org/issues/10320#change-99228

* Author: sowieso (So Wieso)
* Status: Open
* Priority: Normal
----------------------------------------
When requiring a library, global namespace always gets polluted, at least with one module name. So when requiring a gem with many dependencies, at least one constant enters global namespace per dependency, which can easily get out of hand (especially when gems are not enclosed in a module).

Would it be possible to extend require (and load, require_relative) to put all content into a custom module and not into global namespace?

Syntax ideas:

~~~ruby
require 'libfile', into: :Lib   # keyword-argument
require 'libfile' in Lib   # with keyword, also defining a module Lib at current binding (unless defined? Lib)
require_qualified 'libfile', :Lib
~~~

This would also make including code into libraries much easier, as it is well scoped.

~~~ruby
module MyGem
  require 'needed' in Need

  def do_something
    Need::important.process!
  end
end
 # library user is never concerned over needed's content
~~~

Some problems to discuss:

* requiring into two different modules means loading the file twice?
* monkeypatching libraries should only affect the module ­→ auto refinements?
* maybe also allow a binding as argument, not only a module?
* privately require, so that required constants and methods are not accessible from the outside of a module (seems to difficult)
* what about $global constants, read them from global scope but copy-write them only to local scope?

Similar issue:
https://bugs.ruby-lang.org/issues/5643



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

  parent reply	other threads:[~2022-09-21 12:39 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <redmine.issue-10320.20141002224417.7501@ruby-lang.org>
2021-06-10  5:51 ` [ruby-core:104226] [Ruby master Feature#10320] require into module j.ruby-lang
2021-06-10  6:18 ` [ruby-core:104227] " branzeanu.aurel
2021-06-10  8:15 ` [ruby-core:104228] " j.ruby-lang
2022-09-15  3:19 ` [ruby-core:109898] " shioyama (Chris Salzberg)
2022-09-16  6:52 ` [ruby-core:109915] " Eregon (Benoit Daloze)
2022-09-16  7:34 ` [ruby-core:109916] " shyouhei (Shyouhei Urabe)
2022-09-16 10:52 ` [ruby-core:109918] " nobu (Nobuyoshi Nakada)
2022-09-16 21:45 ` [ruby-core:109923] " byroot (Jean Boussier)
2022-09-17  1:53 ` [ruby-core:109925] " shioyama (Chris Salzberg)
2022-09-17  2:00 ` [ruby-core:109926] " shioyama (Chris Salzberg)
2022-09-17  2:32 ` [ruby-core:109927] " shioyama (Chris Salzberg)
2022-09-18 10:43 ` [ruby-core:109946] " shyouhei (Shyouhei Urabe)
2022-09-19  8:25 ` [ruby-core:109955] " duerst
2022-09-19  8:32 ` [ruby-core:109956] " byroot (Jean Boussier)
2022-09-19 17:23 ` [ruby-core:109959] " vo.x (Vit Ondruch)
2022-09-20 10:58 ` [ruby-core:109960] " retro
2022-09-21  9:46 ` [ruby-core:109973] " mame (Yusuke Endoh)
2022-09-21 10:26 ` [ruby-core:109974] " byroot (Jean Boussier)
2022-09-21 12:39 ` shioyama (Chris Salzberg) [this message]
2022-09-21 17:08 ` [ruby-core:109981] " mame (Yusuke Endoh)
2022-09-21 18:11 ` [ruby-core:109982] " jeremyevans0 (Jeremy Evans)
2022-09-25 12:54 ` [ruby-core:110071] " shioyama (Chris Salzberg)
2022-09-27  0:54 ` [ruby-core:110098] " shioyama (Chris Salzberg)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-99228.20220921123904.7501@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).