@lmm Supporting your geometrical approach, representative example may look like

trait Mutable2dFigure { def shift(x: Double, y: Double): this.type } trait Immutable2dFigure { // using suggested `this#type` notation def shifted(x: Double, y: Double): this#type }

So justification for those should be quite simple: when you are moving some Bar you will probably expect that it will not become Circle or Triangle. Since this constraint is geometrically quite intuitive and obvious, you may probably have some natural wish to express this constraint in code. (Also supposing that simplicity of written form for of this construct should match to obviousness of this geometric concept). While you can express this constraint easily for mutable structures by the means of this.type , currently you can not express that constraint with the same simplicity level for the same case but with immutable structures.

lmm: lmm: (not that I’ve ever really understood it for this.type either)

If I understood your question (or irony ) correctly, answer may look like this:

def moveScale(figure: Mutable2dFigure, x: Double, y: Double, ratio: Double): Mutable2dFigure = figure.scale(ratio).moveBy(x, y) trait Movable { def moveBy(x: Double, y: Double): this.type } trait Scalable { def scale(ratio: Double): this.type } trait Mutable2dFigure extends Movable with Scalable

Without this.type you will end up with boilerplating (cause it will be always need to duplicate all “builder-line” methods definitions and refine return values in all sub-trites / sub-classes), or otherwise figure.scale(ratio).moveBy(x, y) will be invalid …

Actually more widely “target audience” for such construct is methods similar to that SeqLike.updated / MapLike.updated / <Case Class>.copy-like / java.lang.Object.clone-like / etc

Hoverer I must admit that such approach can not fit/cover 100% existing cases (which may look relevant for it applications).

For example consider following definition

trait GoodMap[K, V]{ // ... // using suggested `this#type` notation def updated(key : K, value : V) : this#type // ... } trait GoodMap2[K, +V]{ // ... // using suggested `this#type` notation def updated[V1 >: V](key : K, value : V1) : this#type with GoodMap2[K, V1] // ... }

First one ( GoodMap ) has problem with variance, while second one ( GoodMap2 ) some hove “fixes” that variance-problem, but become more verbose and looks not so clear as it should be. Other problem lays in

Map.Map1 …Map.Map4

For those types constraint that map.updated(...).getClass == map.getClass is false at all, same as

map.getClass.isAssignableFrom( map.updated(...) .getClass) . Since for example Map.Map3 after updating may become either

Map.Map2 or Map.Map3 or Map.Map4 and requirement map.getClass.isAssignableFrom( updated_map.getClass ) can not be preserved for all that cases (at least for Map.Map2 which can not be subclass of Map.Map3 )

acruise: acruise: Ah, good old MyType .

I found mentioned there discussion rather interning. Actually proposed there class.type construct perfectly matches to Roost’s self-types (also mentioned in this post)

So according to that post, at least java.lang.Object.clone -like methods in Rust could be declared correctly (with return type Self )

trait Cloneable { fn clone(&self) -> Self; }

Hoverer, in flavor of nested/inner classes (types), I would prefer to have possibility to point to “SelfType” not only for this , but for any other constant value as well. If it is possible to write (someInstance).Nested , (someInstance).type , (someInstance).type#Nested , why should’t we allow some (someInstance)#type (or more “Rust’ly” saying - something like (someInstance).Self -type). In this case if we have val a = ... ; val b : a#type = ...; then it should be obvious that b#type <: a#type same as, this dose’nt requires that a.getClass == b.getClass , it only requires that a.getClass.isAssignableFrom(b.getClass) (assuming that a != null && b != null ).

Also in that previous discussion I can see some final “solution” for HasThisType -like traits / classes. It is something like:

trait HasThisType[ThisType <: HasThisType[ThisType]] { this: ThisType => }

Hoverer it looks too verbose and less convenient comparing for an instance with that Roost’s self-types

Regarding semi-abstract methods (refereed to as “must be redefined” methods) suggested in previous discussions I would say that in fact some correct generalized approach is that “it should be some primary source of that this#type instances”. But that “primary source” could be defined / implemented differently.

So in fact it is not a problem to use that this#type in any method definition just in the same fashion, as one can use this.type (in place of both input parameters type and/or return value type and/or local variables etc), the only problem, is that how we can get some “fresh instances” of type this#type ? (the only well defined available instance of that type is this itself).

For this reason it was proposed to “enforce” some constructor signatures, to require that all sub classes of such class (which need to have such this#type factory) should also mandatory have that/same constructor signature in their definitions. Then based on that constraint some automatically generated (hidden) virtual method should be generated, and actually that method should serve as that “primary source” of that “fresh instances” of this#type . This approach was also referred to as “constructors constrains” in initial post.

An other possible technique, more close to Rust’s approach - is to allow this#type abstract factory method be implemented using some particular class (like new Foo(...) ), but ONLY in final classes (When Impl-class is final, then this#type become referencing on some strict, very well known class/type).

lmm: lmm: To me this looks like a complex feature for the sake of an obscure corner case that is going to come up pretty rarely and confuse readers when it does

Well, Maybe … Or maybe not . (At lest probably Rust language designer may argue to your opinion )

From my personal point of view, I would introduce something like this#type (aka “MyType”) at lest for fixing signatures of java.lang.Object.clone and java.lang.Object.getClass methods. Correct version should defiantly look like

trait AnyRefEx2 { // using suggested `this#type` notation def clone(): this#type // using suggested `this#type` notation def getClass: Class[this#type] }