-
Notifications
You must be signed in to change notification settings - Fork 4
-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple files, modules, require, etc. #17
Comments
Notes from conversation with @ryngonzalez:
The importing system of ES6 is however way too confusing, especially with regard to the "defaults" concept and the multi-part In pseudo-code these two use cases look like:
|
+1 for static modules. The Wren programming language has thought about this a lot, for what it's worth. |
👍 Thanks for the heads up! Had forgotten about Wren, although it's implementation is one of my (if not my) favorite small VMs. |
After some reading and thoughts, I'd like to make a proposal for the design of this. Modules are a compiler featureIf you want a piece of code to talk to another piece of code through the standard language features, then it's going to have to go through the compiler. This will be a core principle that guides further design. If you want to have dynamic code loading then you'll have to go through an external platform "API" (eg. Modules interact through linkagesEach module, through its exports, defines a static set of linkages which are exposed to other modules. This paradigm—I believe—will work well with both dynamic (JavaScript) and static targets. No cyclic dependenciesWe may figure this out later, but this is not a headache we need right now. No load-path trickerySince modules are a compiler feature you control the load-path through the compiler. End of story. (nb. This is not to say the load-path will be obtuse/unaccessible. The load-path should be a controllable/pluggable feature that allows anyone to write their own package manager.) In the language# Importing entire module
import other
# Import entire module with rename
import other as something
# Import specific linkage from module
import linkage from other
# Import renamed linkage and another linkage from module
import linkage as something, another from other
# Exporting
let a = 1
export a
class B { }
export B
var c = 2
export c # Error! Cannot export non-statically-bound variables |
I like that the package manager is decoupled from the language in code, but I'd love there to be an officially-recommended (and perhaps officially-maintained) package manager. |
I like the overall approach to the proposal, and I like the given syntax: there's a nice symmetry to having both It's nice that if you were to want to use HB primarily in a Node environment, and you wanted to intermingle with JavaScript packages, you could still write |
I think for Node compatibility we'd just expose that in some platform-specific API/module; possibly something like: let require = Platform.Node.require
let blah = require("blah") |
Ah ok, that makes sense. There'd be a higher (but worth it) barrier to entry w/r/t porting over code, but the solution above is more elegant and flexible for adding other platform's module-loading in the future. |
After discussions with @ryngonzalez, we will be revising the # Importing entire modules
import <foo/bar>
import <something> as other # other.baz()
# Importing specific linkages from modules
import <something> using * # baz()
import <something> using baz # baz()
|
We eventually need to get to the issue of how we want to handle multiple files. There are, as I see it, a few approaches to this:
1. Copy Node.js
This is the most brittle approach, however it also ties in easiest with our JavaScript target since all source files can be compiled directly to corresponding JavaScript files.
The big downside to this approach is that
require
andmodule.exports
provide zero type information, so any uses of values from arequired(...)
module (internal or external) would have no type information (just a ton ofAny
types).We could perhaps develop a hybrid system on top of this. Where Hummingbird files would be loaded with a different keyword/syntax and those files would expose their exported values via a complementary interface. For example:
2. Roll our own with different design
Node enforces strict boundaries between files, but we don't necessarily need to follow the same path. I'm very open to a "unifying" system that compiles files together into a unified space instead of the deep tree of modules that Node builds.
The disadvantage of this approach is that we don't always get the same file-to-file compilation path as the former. The latter is that we can decide exactly how we want to design our system free from any bounds imposed by Node.js or any other JavaScript runtime environment. Although this means more work for us and less closely hewing to the JavaScript target, I'm in favor of it for the freedom that it gives us to design our system, APIs, and ability to target other runtimes (PyPy, native, etc.).
A trivial, contrived example off the top of my head:
Final note:
import()
vsexport
In these examples I use
import()
with parentheses andexport
without. The reasoning for this is that, in my mind, importing is an imperative action: you are telling the compiler to do something right now. In contrast, exporting is a declarative action: you are telling the compiler something about this file. This is just a thought and I am in no way attached to these designs.The text was updated successfully, but these errors were encountered: