Comments (14)
I like #2 the best, but I am thinking, won't we have to add the ability to nest classes if we do this? I think people will want to do something like the following, especially if they are coming from ruby:
// other.wren
module Other {
class DoWork {
doTheWork {
}
}
}
// main.wren
var other = IO.import("other")
module Main {
static inMain {
var a = other.DoWork.new
a.doTheWork
}
}
Right now trying to nest classes gives a syntax error.
If the answer is, "don't nest classes," then ok, but I am curious how/whether it will be allowed to export more than one class from a module.
from wren.
Even without explicit support for nested classes, you could still do this, like so:
class A {}
class B {}
module Both {
static a { A }
static b { B }
}
It's definitely kind of ugly.
I have thought about nested classes for a while, and in fact about more directly making modules equivalent to classes. That's one of the key ideas in Gilad Bracha's Newspeak and I think it's got a lot going for it. It also lines up well with Wren's heavily class-based philosophy.
The natural endpoint of that line of thinking is that the top level of a module just is a class. I've considered that a little bit, but I haven't spent the time to sit down and think it all the way through to see if it makes sense.
One thing it implies is that "top-level" variables are properties on that outermost class, which means they're dynamically dispatched. That handles things like mutual recursion at the top level well (which currently isn't handled by Wren), but it means giving up errors on typos for top-level names.
I'll try to spend some time working through the ramifications and see if that makes sense.
from wren.
Why can't the execution model for module classes work for the Lua-style method? I personally like the Lua style better than module classes, for what it's worth.
from wren.
Lua doesn't support cyclic requires at all. You can sort of work around it, but it's pretty hacky. I'm hoping for something that works a little more gracefully than that.
from wren.
Should alternate Strawmen go here or as separate issues? I've got a header file proposal, inspired by SML modules/structures/signatures/functors.
from wren.
Should alternate Strawmen go here or as separate issues?
Yes, that would be great!
I've got a header file proposal, inspired by SML modules/structures/signatures/functors.
I'm definitely intrigued.
from wren.
Would you be able to have private methods under this proposal? Without a keyword, that is.
from wren.
The module can definitely have private variables. Variables at the top level are still lexically scoped to the module and wouldn't be exported.
Wren doesn't have any concept of private methods, though, so if you add any methods to the module class itself, they'd be private.
from wren.
What about a late binding model. Instead of a piece of code specifying what it needs, its needs are known at compile time to bytecode. It could be compiled within a 'scope' that was defined when the code was loaded from a main,
new Scope("Vector", "Matrix", "HobermanSphere");
new Scope("subproject/*")
Wren loads up all the named stuff, with wildcards since as you said, logical names work best and then runs the code in that 'scope'. Fibers can therefore have different scopes entirely or a scope can be reused across fibers if appropriate.
HobermanSphere does not need to specify how or where it gets Vector and Matrix from, it just assumes there will be classes with those names visible in its scope, otherwise it'll get a runtime error when the scope tries to do the final binding. As such, you'd know 99% of the time if you were missing a library the moment you try to run your program.
Thought it was worth offering the idea of flipping the module discussion on its head.
from wren.
I'm sorry, but I had trouble following that. Can you walk me through how you envision it loading a couple of modules?
from wren.
Consider each Scope instance like a Smalltalk 'mini image'. You define a scope and give it (several) files to load. At the end of this it will bind the globals for that scope. An example main might look like this:
// project/geometry/Vector.wren
class Vector2D {
new(x, y) {
_x = x
_y = y
}
x { return _x }
y { return _y }
to(end) {
return new LineSegment(this, end)
}
}
// project/geometry/LineSegment.wren
class LineSegment {
new(start, stop) {
_start = start
_stop = stop
}
start { return _start }
stop { return _stop }
direction { return _stop - _start }
lengthSquared { return this.direction.x * this.direction.x + this.direction.y * this.direction.y }
length { return this.lengthSquared.sqrt }
midpoint { return (this.length / 2) + _start }
excuseForCircularDependency { return new Vector2D(_start.x, _start.y) }
}
// main.wren
var mainProject = new Scope("project/**")
mainProject.call {
var unitLength = new Vector2D(0, 0).to(Vector2D(1, 0)).length
IO.print(unitLength)
}
Because the Scope is given file pattern(s) to determine what to load, you can replace any individual file with your own variant at any point, when it would be most advantageous. Otherwise, within a scope, all things are considered 'global' to that scope.
This would double as not only the way to 'include' code, but also the scope that code is resolved in.
// more main.wren
var experimentalProject = new Scope("project/geometry/LineSegment", "experiment/superFastVector2D.wren")
experimentalProject.call {
var unitLength = new Vector2D(0, 0).to(Vector2D(1, 0)).length
IO.print(unitLength)
}
Here LineSegment is the same code from both scopes, but the experimentalProject and mainProject use a different Vector2D. This allows the top-level to specify what is and is not in a scope. In this scenario I can compare how the two different implementations of Vector2D compare. They cannot both be loaded in to the same scope at once however, that'd be a duplicate binding error.
from wren.
Ah, I think I understand it more now, thank you!
var mainProject = new Scope("project/**")
Is the idea here that it would load everything in that directory? Or just that if it needs something, it looks there? If the latter, how does it determine what's actually needed?
I do like the idea of being able to separate how an import is physically located from the logical identifier that's being requested.
Currently, I'm working on implementing #122 instead of this proposal. Since it makes imports statements, I believe we could retrofit that same idea there if needed.
from wren.
Personally, I'd just have it load everything in the list. If Wren supports the ability to add new methods to an existing class, then this'd be useful. You could lazily compile the class contents so that the identifiers are all known, but would that really save much time? you do boast a fast single-pass compiler for Wren after all.
One thing that is missing from this proposal is a way to initialise code based on other code. Having a scope-level event of "Everything is now loaded, you may initialise" on a per-class (or per-module) basis would be required, eg:
// FunkyGraphics.wren
OpenGL.loaded {
...init resources...
}
This'd be the only explicit dependency needed though.
from wren.
Closing this because modules are in now! I ended up going with a slightly different approach since I realized while implementing that it's easier to work with a module's top-level variables as variables instead of trying to make something like a first-class modules.
from wren.
Related Issues (20)
- [Feature] Pipe Operator for Function Calls HOT 53
- [RFC] Object.responds(_) method HOT 10
- [RFC] Add routines for degrees/radians conversions HOT 21
- [RFC] Adding a `Tuple` with language support HOT 11
- [RFC] Adding `const` versions of `Object`s. HOT 9
- Class reflection for embedding HOT 3
- [RFC] `veery` lang transpiler to `wren` lang HOT 3
- [RFC] Object method message passing syntax HOT 28
- [RFC] Add `static Object.typeOf(_)` (and deprecate `Object.type` ?) HOT 9
- How can i stop wren script running? HOT 3
- Calling wren method handle from inside a bound foreign method body HOT 5
- Whitespace bugs? HOT 4
- Serialize (suspended) fibers or serialize the vm HOT 4
- wren_debug.c should use vm->config.writeFn instead of printf HOT 1
- Should we document this aspect of for loop control variable behavior?
- How do I pass a foreign object to a function call? HOT 3
- is Wren dead? HOT 2
- Where causes code to be called twice HOT 3
- How to return other foreign class obj from a foreign class ? HOT 7
- wrenCall -> foreign call causes memory corruption HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from wren.