racket / rhombus

Rhombus programming language
Other
333 stars 59 forks source link

Make RFC about module paths, including insane submod packing idea #24

Open jeapostrophe opened 5 years ago

jeapostrophe commented 5 years ago

In Racket 1, there are some strange rules about module paths. For example a refers to a/main, but a/b doesn't refer to a/b/main if a/b is a directory. I also find it awkward that a/b/c is different than (submod a/b c). It feels like it is exposing the "implementation" of b.

In Racket 2, I'd like a a/b/c is like a search path that refers to a/b/c/main.rkt (or index, or something similar), a/b/c.rkt, (submod a/b c), (submod (submod a b) c), whichever exists first.

lexi-lambda commented 5 years ago

Matthew responded to this idea negatively in a mailing list thread from 2015:

That would create lots of trouble, unfortunately.

Search paths are painful in general. It may seem that a search shouldn't be that bad --- implemented once and for all in the module-name resolver, say. It turns, though, out that various tools need to implement the same search with slightly different constraints, such as the module searches in raco make or raco exe or conflict detection in raco pkg. Dealing with various search dimensions is one of the least-fun parts of building those tools, so I'm especially reluctant to add more.

In contrast, module-path parsing and normalization is relatively easy to centralize. If a foo/bar:baz notation seems worthwhile to others, I'd be willing to give it a try.

jeapostrophe commented 5 years ago

My interpretation of the prophet is that he meant it would create trouble in a backwards-compatibility-respecting world.

LiberalArtist commented 5 years ago

The "insane submod packing idea" is something I've wanted sometimes. On the other hand, I can think of at least two ways in which submodules are different from modules written in different files:

  1. You have to expand the enclosing module to discover what submodules it contains. Uses of this include scribble/lp2, serializable-struct, and Typed Racket. That means a submodule has some sort of dependency on the enclosing module's compile-time phase, even if its own compile-time phase were to use a non-intersecting set of libraries. (At the extreme, imagine there were a #%some-other-kernel.)
  2. Currently, when standard-module-name-resolver checks for cyclic dependencies, it considers files as the unit of granularity, even when the (sub)modules in question actually form a DAG. The prophet seemed to say in https://github.com/racket/racket/issues/1101 that this is an implementation restriction, not a desired limitation, but that fixing it could potentially be involved.

Maybe there are other differences, too.

I'm not sure whether or not these differences mean that module paths for "top-level" modules and submodules should continue to be differentiated. At a minimum, conflating them might make the cycle-in-loading errors more confusing, but maybe that's actually a reason to remove weaknesses and restrictions.

sorawee commented 5 years ago

Not totally sure if this is relevant, but I have been wanting the ability to test submodules. In Racket 1, if I have (module foo ... (module+ test ...) ...), it seems impossible to raco test thetest submodule inside foo submodule. I instead need to create (module+ test ...) at the top-level, which breaks code structure.