Closed LPTK closed 1 year ago
val
/fun
implicit this
insertion is inconsistent. It is performed for abstract class C { val x = 1; fun f = x }
whereas abstract class C { val x : int; fun f = x }
fails with "Code generation encountered an error: unresolved symbol x
".
The second one should work as well.After some consideration, I figured the best approach may be to:
virtual
keyword for members that may be overridden later; andthis
-less) accesses to virtual members.This has lots of benefits:
val
members, fun
members, val
parameters, and non-val
parameters can all be safely accessed without qualification uniformly in any place of the class, including in the constructor, and their semantic is obvious and unsurprising, unlike in Scala (1).this.
prefix (it won't happen implicitly by just referring to a plain identifier).this
not being available in constructors.I expect virtual members to be the exception rather than the rules; therefore, the limitations attached to them are a fair price to pay for all these benefits.
(1) Consider how Scala is affected by potential initialization problems/footguns due to implicit virtuality by default (unless one uses the new initialization checker, which itself adds complexity and mental burden):
abstract class Foo { val x: Int; def foo = x }
object Bar extends Foo { val x = foo }
Bar.x // 0 (!!! uninitialized !!!)
class A { val x = 1; val y = x + 1; def z = x + 1 }
object B extends A { override val x = 2 }
B.y // 1 (!!! value was set from uninitialized access to x, yielding 0 !!!)
B.z // 3
Addressed in https://github.com/hkust-taco/mlscript/pull/175.
let
bindings (unlikeval
fields)val
this
implicitly when accessing members defined in the same scope. Currently we do it for members but not for parameters. We need something consistent and not too surprising.Definitions:
Implicit
this
insertion: Accesses to members in scope are implicitly prefixed withthis.
in JS Direct member access: Accesses to members in scope refer to the specific member definition does not virtually dispatch to possibly overridden ones. This might be a bit annoying to implement for methods.Currently, we use direct access for parameters, which is (currently) not very consistent but has advantages:
this
should be forbidden for safety). Note that the ctor includes the initializers of all class fields. Making ctor semantics different from method body semantics is possible but would be surprising.val
to make the parameter generate an accessor would change the semantics of references to this parameter.Pros of direct accesses for methods and fields:
this
insertion would make these calls virtual)Cons of direct accesses for methods:
this
.