Try to figure out how to unfuck module terminology

Unless our packages are actually identical to ML modules, "modules" and "packages" aren't gonna be the same thing. And our packages can contain types, so they can't be identical to our modules unless we let structs contain types and imports. Hmmmm.

Either way, calling ML modules "modules" is gonna confuse a hell of a lot of people, and calling them "ML modules" is not much better, so maybe try to come up with a better term for them.

Assigned to
1 year, 1 month ago
6 months ago

~icefox 11 months ago

The simple local minimum is to call a "ML module" a "module", and call a "namespace within a single distribution unit" a "package" or such, and then you can call "a distribution unit" a "crate". Unfortunately, that gives "module" the meaning that 99% of people will be unfamiliar with.

Maybe just call an "ML module" a "platypus". It makes about as much sense.

~akavel 7 months ago

Brainstorming: a "stencil"? a "meta-package"? a "type-package"? I briefly tried to learn OCaml some years ago, so I only vaguely started understending the difference vs. modules as "commonly understood" outside MLs. Could you try describing how you understand what a "ML module" is/represents? Sometimes dwelling on that, and then grabbing thesaurus.com, can help come up with some platypus-like but still somewhat evocative name. (Also, all names were initially weird and unfamiliar when invented, until they became familiar and "obvious" through repeated use.)

~icefox 7 months ago

Ok, coming back to this and explaining it because it's a good exercise... An "ML module" is, at its root, a generic struct that contains functions. At least, that is the direction I approach them from. They fulfill a role similar to Rust traits in a different way. Like traits, they are a way to specify an interface, ie a collection of methods and types that all go together, and multiple implementations, which is a particular collection of methods and types that fit the interface.

Unlike traits, they are perfectly normal values in Garnet like any other that are created, passed to functions, etc. If they're const, then you can inline them into nothingness like traits are, if not then they act like vtable's, and so you don't need the dyn special case of Rust traits. Also unlike traits you have to create/instantiate modules explicitly; with traits if you want to use Eq<List<i32> you just say let x: List<i32> = ...; let y: List<i32> = ...; x.eq(y); and it automatically figures out what implementation of Eq to call for you. This is trait coherence and is a double-edged sword, more discussion on it is in issue #8. With modules you have a different double-edged sword, so if you want to call let x: List<i32> = ...; let y: List<i32> = ...; x.eq(y); you have to tell explicitly what implementation of eq() to use, something like let EqListThing: Eq<List<i32>> = ...; EqListThing.eq(x, y). There's some syntactic sugar to make that less terrible called "modular implicits" but that's not implemented yet.

Plus, in OCaml, pretty much every file is actually a module under the hood and gets treated like it. I was originally going to do the same in Garnet, just make every file define a struct and importing a file creates a new constant in the current file with that struct defined. However I am currently leaning towards not doing that for reasons I don't quite remember, so modules and "the things that let you group files together with separate namespaces" are separate constructs. (Discussion on that in issue #52.)

~icefox 6 months ago*

A suggestion one person had was to just call ML modules classes, since they're like 75% the same as OO classes. I don't like anything that smells like OO, but it's honestly not a terrible idea.

But THEN it also conflates a lot with Haskell typeclasses too, goddammit!

Register here or Log in to comment, or comment via email.