Modules first or second class (Re: I noted some open issues on "Classes with Trait Composition")

Claus Reinke claus.reinke at talk21.com
Sun May 22 02:04:33 PDT 2011


> I think "modules are a construct that evaluates to an object"
> is the wrong way to think about them. Syntactic modules
> are a second-class construct that is not an expression. You
> can reflect on modules at runtime, and that reflection is
> provided as an object, but that's because almost all
> compound data structures in JS are objects. But I would
> advise against describing modules as a kind of object.

>> Just a note on this: for me, that means Harmony modules
>> are a step back from what I can implement in JS/now.
>
> How is it a step back, if you can already implement it? We're
> not taking objects away from JavaScript.

If I implement a module loader[1] in JS/now, my modules
are first-class functions from export objects to export object.
Normally, that is just used to model import dependencies,
but fully instantiated modules are (export) objects, and
first-class modules fit right into the pattern.

You're advising that thinking about Harmony modules
as first-class objects is not the best way to think about them.

Yes, I can continue to use first-class modules inside Harmony
modules, but that makes two separate concepts where there
used to be one.

>> Not
>> having first-class modules has been a major drawback in
>> Haskell (which has a strictly 1980s-style module system),
>> leading to all kinds of work-arounds.
>
> Usually when people deride the Haskell module system,
> they are comparing it to the ML module system, which...
> is also a second-class module system.

A hobby horse of mine [2, especially chapter 4 and sections
8.2/8.3]:-)

The proponents of Haskell's module system were explicitly
looking for something simple (just namespacing), so it is
not so much deriding as knowing that there are better
solutions. I added a first-class module system to a dynamically
typed functional language back in the 1990s, and from the
literature then, it seemed that some ML implementations
already had first-class modules (some had only higher-order
functors, first-class in the separate module language).

Naturally, since I spent a lot of time thinking about the
advantages of first-class modules, it is great to be able
to implement them, including loaders, so easily in
Javascript;-)

Modulo loaders, they are also easy in Haskell (I worked
in Mark Jones' group for a while - he did some nice work
in that area), but since most of the infrastructure is geared
towards the second-class modules, first-class modules
aren't used as much as their advantages would suggest.

>> One of these workarounds, which I expect to see and
>> use a lot in Harmony, is to have first-class modules-
>> as-records (or objects) inside second-class built-in-
>> modules.
>>
>> Is this an intended outcome of the Harmony module design?
>
> That's kind of a loaded question, given the word "workaround"

No loading intended. I realize that the majority view might
not yet call for first-class modules, might therefore find them
counter-intuitive. Those developers might think of first-class
modules as an abstract complication, rather than a simplifying
and practical tool. It is just those who have grown used to their
advantages who need workarounds in second-class modules.

> but yes, it's definitely an intended outcome of the design to
> have second-class modules. Modules that are second-class
> have many benefits over first-class modules:
>
> - they are extremely lightweight, which is really important for ergonomics

I find modules-as-objects/records lightweight, but given the
discussions I've seen on the CommonJS list regarding module
formats, you're probably right for the majority of users.

> - they make it possible to do compile-time linking and variable resolution

For Javascript and other dynamic languages, compile-time
for one piece of code is often runtime for its host code.
Having a phase separation, after which all variables are
resolved, is great but is that not addressed by destructuring?

> - they can share static information, such as sets of bindings
> (note that import * would not work with first-class modules),
> macros, or types (both of which are, IMO, worth considering
> in the future for ECMAScript)

Import * is useful, but isn't it based on the fixed shape
of the module we import from? In a typed language, if there
is a static type that includes the property names of an object,
import * from that object becomes possible. And, in Javascript,
wouldn't a restricted 'with', working only on frozen objects,
serve the same purpose?

Btw, can I do 'import *' on a dynamically loaded module?

Types and modules are tricky, because of the various design
options (some of which are mentioned in section 8.2 of [2]).

> Moreover, loaders make it possible to do dynamic linking.
> It's just a little harder than in e.g. SML. I say that's the right
> trade-off: writing simple modules is trivial, and writing
> modules with pluggable dependencies is still possible.

And reflection represents module instances as objects. I
was just surprised that you insisted on the second-class
view as central (rather than it being a simplified view on
first-class modules).

Thanks for the clarification,
Claus

[1] 
http://libraryinstitute.wordpress.com/2010/12/01/loading-javascript-modules/
[2] Functions, Frames, and Interactions - completing a
    lambda-calculus-based purely functional language with
    respect to programming-in-the-large and interactions
    with runtime environments, Claus Reinke, 1998
    http://community.haskell.org/~claus/publications/phd.html

 



More information about the es-discuss mailing list