-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Introduce This
type to replace self types
#7374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
You can't type trait Foo { this: Bar => }
trait Bar
trait Foobar extends Foo
the last line is already illegal and flagged with a compile error, because the self type in trait Foo { type This <: Foo with Bar }
trait Bar { type This <: Bar }
trait Foobar extends Foo { type This <: Foobar }
But would that always be the case? I can't convince myself, but maybe it's true. |
The It's only safe if you know what you are doing and you have a sealed hierarchy (or you have |
It's enforced in the same way in Dotty, at least:
There is one restriction we have to add: In a |
Before we can properly evaluate alternatives, we need to come up with an exhaustive list of all the semantics of self types, for example they influence the implicit scope: trait Foo {
implicit def x: Int = 1
}
trait Bar { self: Foo =>
println(implicitly[Int])
} |
Do you have some reliable way of compiling such a list? This is another case where I would feel much safer if we evolved the language gradually, instead of introducing so many changes at once. At this point there is a big limit to what people are using Dotty for. OTOH if we would ship a final release with some subset of features, and "scala.next" would always have a limited set of changes relative to "scala.current," you would have much more projects trying out the changes in "scala.next." IMO the only changes that should be in 3.0 are (a) changes that form the identity of 3.0, and (2) changes whose design affects other changes in 3.0 (so that if you implement it later you may regret a change that was already released in light of the newer change). Theoretically, if you would make a graph of all the changes in Dotty right now, with arrows indicating how the design of one change can be influenced by the design or reception of other changes, each disconnected subgraph could be in its own release. I understand that would make keeping documentation and training materials up to date harder but that has to be the cart that follows the horse of low-risk changesets. |
The self-type is stored in the field
http://dotty.epfl.ch/docs/reference/features-classification.html is an attempt at doing something like that, though not fully up-to-date |
To me, these scream for a solution where what's refined is not a fictitious class C { this: T => ... } would be replaced by class C { val this: T; ... } This has several advantages:
So we've achieved the stated goal: remove the vey strange The downside is that it doesn't give us a way to talk about "the current class" in operations like |
Just saw this. I think this could be interesting and desirable (I've seen people try to get this by using (OTOH, it's not clear that this feature is especially worrisome). The Also, how does this compare to ThisType from Kim Bruce or from Sukyoung Ryu (TOPLAS 2016, https://dl.acm.org/citation.cfm?id=2888392)? (Yes, I should take a look, no time now). |
Non-paywalled link to the Sukyoung Ryu paper here. |
A related thread on contributors: |
Self types declarations are a weird little corner case of the language. They achieve two things:
this
to a proper subtype of the current classthis
.Self type declarations have non-obvious syntax (somebody not well versed in the Scala language wouldn't know what a self type declaration is) and add considerable complexity to the compiler.
(2) can already be achieved by giving a simple alias like
or
So the real addition to expressiveness that self types provide is (1). But in my mind a better way to achieve (1) is to introduce a
This
type, with the following rules:Every class or trait
C
has an implicitThis
type declaration.C
is final, the declaration istype This = C
type This <: C
o
, the declaration istype This = o.type
.The type of
this
isThis
.This
types may also be declared explicitly.type This <: B
.This
type declaration. I.e. in classC
,an explicit declaration
type This <: B
would yieldtype This <: B & C
as the finaltype of
This
.Once
This
types are introduced, self type declarations are redundant and can be dropped. A definition likewould be replaced by
Motivation
This
types are more powerful than self types. In particular they allow to accurately type copying operations:This
types are also more regular than self types since they need no special syntax.Problems
The main problem lies with migration.
This
is already used as a type name, in most cases in a role quite similar to the meaning ofThis
defined here. The rule thatThis
may only have upper bounds will probably detect almost all existing uses ofThis
that are now illegal. A simple mitigation is to pick another name for existing usages (e.g.ThisType
, orSelf
). But is it feasible to do it automatically?The text was updated successfully, but these errors were encountered: