Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A rule to make typing nested classes more flexible #14390

odersky started this conversation in CC experiment
Discussion options

#14387 can replace some of #13657 but not all. For instance, the following would still require #13657 to be able to typecheck tail:

extension [A](xs: {*} LazyList[A])
 def map[B](f: A => B): {xs, f} LazyList[B] =
 final class Mapped extends LazyList[B]:
 this: {xs, f} Mapped =>
 def isEmpty = false
 def head: B = f(xs.head)
 def tail: {this} LazyList[B] = xs.tail.map(f) // OK

But we can hopefully get on safer ground by adding an alternative rule. The idea is that the local class Mapped sees the outer references f and xs through this. You could imagine a meaning preserving transformation where f and xs are cached in additional fields of class Mapped like this:

 val this_f = f
 val this_xs = xs

and every reference to f or xs is replaced by this.this_f and this.this_xs.

Let's now compare the expression xs.tail.map(f) of type {f, xs} LazyList[B] with the expected type {this} LazyList[B]. Since there are no tracked parameters enclosing the expression inside class Mapped, every occurrence of f or xs in the capture set C must have come through this, so we can equivalently use this.this_f and this.this_xs, which are both subsumed by this. In other words, to compare actual {f, xs} with expected {this}, we can ignore any reference in the actual capture set that goes to a variable defined outside Mapped, so both f and xs are discarded and the check succeeds.

More generally: When checking an expression e: Ca Ta against an expected type Cx Tx where the capture set of Cx contains this and any method inside the class Cls of this that contains e has only pure parameters, drop from Ca all references to variables or this references outside Cls. These are all accessed through this, so are already accounted for by Cx.

You must be logged in to vote

Replies: 1 comment

Comment options

I meditated a bit on this example and now I'm no longer sure why does it matter that Mapped cannot "reach" xs and f otherwise than through its own members. @odersky, do you have an example that breaks if we don't have this restriction?

EDIT: ok, let me be a bit more explicit. If I look at the example, I already see xs and f inside Mapped as references to fields of Mapped - after all, that's also how this code is compiled, right? So if I get a value from outside that has the (surface) capture set of xs, I understand that as a value that captures at most {this.this_xs}, which is still strictly less things than {this}, which must capture both of {xs,f} ({this.this_xs,this.this_f}).

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /