Reputation: 3425
I am looking though the source code of the Promise[T]
trait from the scala.concurrent
package.
So here is the method declaration where I need your help in one place:
trait Promise[T] {
....
def complete(result: Try[T]): this.type =
if (tryComplete(result)) this else throw new IllegalStateException("Promise already completed.")
....
}
I do not really understand how to interpret the this.type
as a complete
method return type. Why not simple the return type could be Promise[T]
?
Sorry if my question will seem too simple for someone, I am just learning this stuff.
Upvotes: 4
Views: 86
Reputation: 108111
I suspect the reason is supporting inheritance.
Consider this simple example
trait Foo[A] {
def foo: Foo[A] = this
}
trait Bar[A] extends Foo[A]
Now let's try it out
scala> (new Foo[Int]{}).foo
res0: Foo[Int] = $anon$1@7f0aa670
scala> (new Bar[Int]{}).foo
res1: Foo[Int] = $anon$1@4ee2dd22
As you can see, the method foo
returns a Foo[Int]
in both cases, and that's because you returned the "hardcoded" type Foo[T]
in the method definition.
If you instead do
trait Foo[A] {
def foo: this.type = this
}
trait Bar[A] extends Foo[A]
then the returned type depends on the instance you're invoking foo
on:
scala> (new Foo[Int]{}).foo
res2: Foo[Int] = $anon$1@1391e025
scala> (new Bar[Int]{}).foo
res3: Bar[Int] = $anon$1@4142991e
Upvotes: 2
Reputation: 53348
this.type
is necessary in a path dependent context:
scala> class A { class B; def f(b: B): A = this }
defined class A
scala> val a1 = new A; val b1 = new a1.B; val a2 = new A
a1: A = A@721f1edb
b1: a1.B = A$B@5922f665
a2: A = A@65e8e9b
scala> a1.f(b1)
res6: A = A@721f1edb
scala> a2.f(b1)
<console>:12: error: type mismatch;
found : a1.B
required: a2.B
a2.f(b1)
^
Path dependent means that the compiler knows that types belong together. In the above example one can see that new a1.B
produces a value of type a1.B
and not only B
. However, this does not work:
scala> a1.f(b1).f(b1)
<console>:11: error: type mismatch;
found : a1.B
required: _2.B where val _2: A
a1.f(b1).f(b1)
^
The problem is that the return type of f
is A
, which has no information anymore about the path dependent relationship. Returning this.type
instead tells the compiler that the return type fulfills this relationship:
scala> class A { class B; def f(b: B): this.type = this }
defined class A
scala> val a1 = new A; val b1 = new a1.B; val a2 = new A
a1: A = A@60c40d9c
b1: a1.B = A$B@6759ae65
a2: A = A@30c89de5
scala> a1.f(b1).f(b1)
res10: a1.type = A@60c40d9c
Upvotes: 2