forked from Mirror/wren
147 lines
4.2 KiB
Plaintext
147 lines
4.2 KiB
Plaintext
var baz = "top level"
|
|
|
|
class Foo {
|
|
bar {
|
|
baz
|
|
_baz
|
|
}
|
|
|
|
baz { "getter" }
|
|
_baz { "private getter" }
|
|
|
|
this {
|
|
_baz = "field"
|
|
}
|
|
}
|
|
|
|
Given `_foo`, how do we tell if it is:
|
|
1. A call to a private getter
|
|
2. Accessing a private field
|
|
3. Tearing off a reference to a private method
|
|
|
|
It's not 3 because of arity overloading. Wren doesn't really have method
|
|
tear-off because of this.)
|
|
|
|
This is hard because the getter may not be defined yet. One option is:
|
|
It's always a call to a private getter. After the class is defined, we see if
|
|
there are any private getters that were not implemented and define implicit
|
|
getters for them that return fields.
|
|
|
|
That's weird if you take into account setters, though. Consider:
|
|
|
|
class Foo {
|
|
a { IO.write(_prop) }
|
|
_prop = value { ... }
|
|
}
|
|
|
|
For first reference to `_prop`, compile it to getter call. Then see setter
|
|
defined for it, so we no longer implicitly make a field. But there's no getter,
|
|
so now the above call will fail.
|
|
|
|
Probably do want call to fail here, so that may be OK.
|
|
|
|
---
|
|
|
|
Given `_foo(arg)`, how do we tell if it is:
|
|
|
|
1. A call to a private method
|
|
2. A call to a private getter, which returns a field that's a fn, and invoking
|
|
it.
|
|
|
|
Since arity is part of the name, the answer here is 1.
|
|
|
|
---
|
|
|
|
Given `foo(arg)` inside a class, how do we tell if it is:
|
|
|
|
1. A call to a method on this.
|
|
2. Accessing a field `foo` on this, which returns a fn, and invoking it.
|
|
3. Calling a getter `foo` on this, which returns a fn, and invoking it.
|
|
4. A call to a top-level fn.
|
|
|
|
Let's just dismiss 3. Since arity affects naming, `foo(arg)` and `(foo)(arg)`
|
|
are really different things in Wren. The parentheses and args are effectively
|
|
part of the name.
|
|
|
|
That covers 2 as well. If we ditch top level fns, we're left with 1. This is
|
|
good, I think. It means the common case of calling methods on yourself is nice
|
|
and terse.
|
|
|
|
---
|
|
|
|
Given `foo` inside a class, how do we tell if it is:
|
|
|
|
1. Accessing a field on this.
|
|
2. Calling a getter on this.
|
|
3. Accessing a global variable.
|
|
4. Accessing a top-level getter.
|
|
5. Accessing a local variable.
|
|
|
|
We can probably ditch 4. We can ditch 1 because Wren doesn't have public fields.
|
|
|
|
Because both getters and global variables can be used before they are defined,
|
|
we can't determine statically (in a single pass compiler) if there is a global
|
|
variable or getter named `foo` in order to disambiguate. Even if we could, we'd
|
|
still have to answer the ambiguous case where it's both.
|
|
|
|
If we assume it's a global and the user wants a getter, they can always do
|
|
`this.foo` to be explicit. If we assume it's getter, how would they indicate a
|
|
global?
|
|
|
|
One option is to have a different naming convention for globals, like a
|
|
capitalized initial variable. That lines up with class names at the top level
|
|
anyway. It just means if we have variables for imported modules, we'll want to
|
|
capitalize those.
|
|
|
|
We still have to distinguish locals, but since those are declared before use, we
|
|
can determine that statically. I.e. locals will shadow implicit getters.
|
|
|
|
---
|
|
|
|
OK, so here's one proposal:
|
|
|
|
class MyClass {
|
|
method {
|
|
_foo // access field
|
|
_foo(arg) // not valid
|
|
foo // local var or getter on this
|
|
foo(arg) // method on this
|
|
Foo // global variable
|
|
}
|
|
}
|
|
|
|
This is simple, and straightforward to compile. Using capitalization for globals
|
|
is a bit weird, and not having private methods is a bummer, but maybe simplicity
|
|
is the right answer.
|
|
|
|
Here's another:
|
|
|
|
class MyClass {
|
|
method {
|
|
_foo // private getter on this
|
|
_foo(arg) // private method on this
|
|
foo // local var or getter on this
|
|
foo(arg) // method on this
|
|
Foo // global variable
|
|
}
|
|
}
|
|
|
|
To get rid of the weird capitalization rule for globals, one option is to not
|
|
allow forward references to globals. That would break mutually recursive
|
|
references to classes, though:
|
|
|
|
class A {
|
|
foo { B.new }
|
|
}
|
|
|
|
class B {
|
|
foo { A.new }
|
|
}
|
|
|
|
So, not a fan of that.
|
|
|
|
Ignoring that, the main difference between the two proposals is the second has
|
|
private methods. Since the first proposal is practically a subset of the second,
|
|
let's start with that one first.
|
|
|