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.
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.
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.)
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 useEq<List<i32>
you just saylet x: List<i32> = ...; let y: List<i32> = ...; x.eq(y);
and it automatically figures out what implementation ofEq
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 calllet x: List<i32> = ...; let y: List<i32> = ...; x.eq(y);
you have to tell explicitly what implementation ofeq()
to use, something likelet 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.)
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!
After some rambling on the PLTDI discord, people weirdly seem to not to hate "platypus". Which I suppose should be kinda expected from that crowd.
An actual good name though could be "interface" or "interface struct", which I don't hate and which is simple and literal enough to be descriptive, while distinct enough to not be confused with OO-style classes, Haskell typeclasses, or Rust traits.
Shit someone suggested "signature" and that's also a good name.
Just for the record, a "signature" has an arguable disadvantage of resulting in a name clash with a "cryptographic signature" (a term AFAIU commonly used in public-private cryptography, including various authentication/authorization schemes, HTTPS, and such). Yes, I know, naming things. But I made my proposals above ;P
Good point! That makes me feel better about not using "signature", thanks. I do like "stencil" but for simplicity I think I'll just call it an "interface", since well, that's what it does.