From the strawman proposal, it is unclear how classes referring mutually to each other--i.e., a method of one creates a new instance of the other--could be written. It is very clear that functions that want to mutually call each other must be defined next to each other. Should classes also do the same?
Is it possible to define functions *and* classes mutually referring to each other?
However, it's actually a bit more tricky than that. Consider:class C { d() { return D } }class D extends (new C).d() {}I have some ideas how the semantics could be relaxed to be more permissive while still detecting such cases, but it's not there yet.
Is it possible to define functions *and* classes mutually referring to each other?That would be a possible generalisation, though potentially yet more cumbersome to specify. I would be inclined to leave that out, at least for now, until we know better what common patterns will emerge with ES6 classes. Do you have an immediate use case that would be hard to refactor?
Yes, I do. The story is that I am the author of Scala.js, the Scala to JavaScript compiler [1], and I'm in the process of porting the back-end to Strong Mode. In general, Strong Mode looks like a perfect target for Scala.js--it already emits code that is semantically very close to it, and for most of the discrepancies, I have a quite clear vision on how to adapt things.
Is it possible to define functions *and* classes mutually referring to each other?That would be a possible generalisation, though potentially yet more cumbersome to specify. I would be inclined to leave that out, at least for now, until we know better what common patterns will emerge with ES6 classes. Do you have an immediate use case that would be hard to refactor?
About this, though, there are static methods (which become global functions) and classes, and all of them can mutually reference each other (and they do). I am fine with bundling all the functions and classes next to each other. But I don't see how I would work around not being able to define mutually recursive functions and classes.At least, I am absolutely certain that without mutually recursive classes, I'll have to abandon completely. I have a feeling that top-level functions *could* be encoded as methods of a class StaticMethods with a singleton instance, but I have a hard time coming up with an initialization step for this singleton: I always end up in a cyclic dependency between the singleton's class, the 'let/const' holding its instance, and the other classes.
I understand the definition of mutually recursive classes will complicate things. I don't see why functions and classes together would complicate them *further*, though.
Yes, I do. The story is that I am the author of Scala.js, the Scala to JavaScript compiler [1], and I'm in the process of porting the back-end to Strong Mode. In general, Strong Mode looks like a perfect target for Scala.js--it already emits code that is semantically very close to it, and for most of the discrepancies, I have a quite clear vision on how to adapt things.Cool, that's exciting! Please keep us posted.
Hm, given recursive classes, couldn't you trivially encode this using a class with a static method? E.g. for your example:
For classes, forward references are only legal from within methods, and only if the referenced class does not have a (direct or indirect) backwards reference to the original class outside any method.
class Child extends Parent {}return new Child();foo() {class Parent {IIUC, this still does not allow a useful top-level-only pattern:I see that the strawman was updated wrt this discussion. It says (in Scoping):For classes, forward references are only legal from within methods, and only if the referenced class does not have a (direct or indirect) backwards reference to the original class outside any method.
}
}
isEmpty() { return false; }this.tail = tail;this.head = head;super();constructor(head, tail) {class Cons extends List {isEmpty() { return true; }class Nil extends List {return new Cons(elem, this);prepend(elem) {class List {The pattern is for example necessary to implement a functional List:
}
}
}
}
}
I understand why this clause was added. It addresses Andreas' problematic snippet above, which I repeat here for convenience:class C { d() { return D } }
class D extends (new C).d() {}Could we relax the wording a little bit further to allow backwards references *if* it is directly as an IdentifierReference in the ClassHeritage of the class?