What is the use of `*.this` in Scala? - scala

class S {
case class A(a: Int)
}
abstract class R(val s: S) {
type T1 = R.this.s.A
type T2 = s.A
implicitly[T1 =:= T2] // compiles
type T3 = R.this.type
type T4 = this.type
implicitly[T3 =:= T4] // compiles
val v1 = R.this // v1 == `this`
val v2 = R.this.s // v2 == `s`
}
Looks like the .this part has no effect whatsoever. To make a concrete question:
When do you use the .this ?

It matters for inner classes. E.g.
class Outer(val x: Int) {
class Inner(val x: Int) {
def outer_this = Outer.this.x
def inner_this = this.x // or just x
}
}
val outer = new Outer(0)
val inner = new outer.Inner(1)
println(inner.outer_this) // 0
println(inner.inner_this) // 1
Each Outer.Inner instances "belongs to" a specific Outer instance, and can refer to that instance as Outer.this. By itself x in Inner refers to its own property, so if you need the enclosing instance's x property, you write Outer.this.x.

One rule is Scala never infers singleton type this.type. For example first consider the mechanics of it
scala> trait Foo {
| type T
| def f() = this // we left out the return type to see what Scala will infer
| }
// defined trait Foo
scala> new Foo { type T = String }
val res0: Foo{T = String} = anon$1#6d3ad37a
scala> res0.f()
val res1: Foo = anon$1#6d3ad37a
Note how res1 has return type of Foo and not Foo { type T = String }, so we have lost some type information
scala> val x: res1.T = ""
1 |val x: res1.T = ""
| ^^
| Found: ("" : String)
| Required: res1.T
Note compiler does not know res1.T is actually a String. So compiler did not infer the singleton type this.type which would have all the type information including what type member T was instantiated to
scala> trait Foo {
| type T
| def f(): this.type = this
| }
// defined trait Foo
scala> new Foo { type T = String }
val res2: Foo{T = String} = anon$1#7d381eae
scala> res2.f()
val res3: Foo{T = String} = anon$1#7d381eae
scala> val x: res3.T = ""
val x: res3.T = ""
Note how after we explicitly declared singleton return type this.type compiler knows T is a String.
Here is another mechanical example of what happens because compiler does not infer singleton type this.type
scala> trait Foo {
| def f() = this // let inference do its thing
| }
// defined trait Foo
scala> trait Bar {
| def g() = 42
| }
// defined trait Bar
scala> trait Bar extends Foo {
| def g(): Int = 42
| }
// defined trait Bar
scala> new Bar {}
val res5: Bar = anon$1#6a9a6a0c
scala> res5.f()
val res6: Foo = anon$1#6a9a6a0c
scala> res6.g()
1 |res6.g()
|^^^^^^
|value g is not a member of Foo
Note how f() call typed to Foo and not perhaps expected Bar. On the other hand if we provide explicit singleton return type this.type then
scala> trait Foo {
| def f(): this.type = this
| }
// defined trait Foo
scala> trait Bar extends Foo {
| def g(): Int = 42
| }
// defined trait Bar
scala> new Bar {}
val res7: Bar = anon$1#4707d60a
scala> res7.f()
val res8: Bar = anon$1#4707d60a
scala> res8.g()
val res9: Int = 42
we see f() call typed to Bar.
Those were the mechanics but what about practical applications? Two uses I am aware of are:
supporting fluent style of programming
supporting summoners of type class instances (see also Scala 3 summon)

Related

Value assigned to type member via method type parameter breaks type equivalence

Why does the following type equivalence hold
trait Foo { type T }
val fa = new Foo { type T = Int }
implicitly[fa.T =:= Int] // OK
but when type member T is assigned via method parameter A then type equivalence does not hold
def makeFoo[A]: Foo = new Foo { type T = A }
val fb = makeFoo[Int]
implicitly[fb.T =:= Int] // ERROR
Intuitively I would expect if T = A and A = Int then T = Int?
This is because the return type of makeFoo is only Foo and not Foo { type T = A }. If you don't explicitly declare it or if you refine it, the error will go away.
def makeFoo[A] = new Foo { type T = A }
val fb = makeFoo[Int]
implicitly[fb.T =:= Int] // No more error
or
def makeFoo2[A]: Foo { type T = A } = new Foo { type T = A }
val fc: Foo { type T = Int } = makeFoo[Int]
implicitly[fc.T =:= Int] // No more error
Scastie:
<script src="https://scastie.scala-lang.org/knIfPcXqSQKXXCXJ2teHkg.js"></script>
I'll just add that possibility to specify not the precise return type but its supertype (an upper bound) is called whiteboxity.
In Scala 2 this can be achieved with whitebox macros
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
def makeFoo[A]: Foo = macro impl[A]
def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
q"new Foo { type T = ${weakTypeOf[A]} }"
}
val fb = makeFoo[Int]
implicitly[fb.T =:= Int] //compiles
In Dotty this can be achieved with keyword transparent (currently)
transparent inline def makeFoo[A]: Foo = new Foo { type T = A }
val fb = makeFoo[Int]
summon[fb.T =:= Int] //compiles
Former syntax is
inline def makeFoo[A] <: Foo = new Foo { type T = A }

How to use path-dependent types with type classes in Scala

I’m having some problems with path dependent types.
I have some types Foo with an abstract type member F. Instances such as Bar will provide the concrete type.
Then there is a type class Baz. I have instances of the type class for each concrete type of Foo#F (but not for Foo itself).
Here is an example:
sealed trait Foo {
type F
}
object Bar extends Foo {
type F = Array[Byte]
}
trait Baz[B] {
def b(b: B): String
}
object Baz {
implicit val bazByteArray: Baz[Array[Byte]] = (b: Array[Byte]) => new String(b)
}
I can't get this to compile:
def f(a: Foo): Baz[a.F] = {
val baz = a match {
case bar#Bar => g(bar)
}
baz
} // Expression of type Baz[(a.type with Bar.type)#F] doesn't conform to Baz[a.F]
val x2: Foo = Bar
val y2: Baz[x2.F] = f(x2) // Expression of type Baz[Foo#F] doesn't conform to expected type Baz[x2.F]
This does compile:
def g(a: Foo)(implicit baz: Baz[a.F]): Baz[a.F] = {
baz
}
val x1: Bar.type = Bar
val y1: Baz[x1.F] = f(x1)
Why does g compile but not f? Aren't the types the same?
How can I get f to compile? Is there some sort of evidence I need to add?
Seems somewhat similar to this question. Here is a way to make it compile:
sealed trait Foo {
type F
def asSingleton: FooSingleton[F]
}
trait FooSingleton[X] extends Foo {
type F = X
def asSingleton: FooSingleton[X] = this
}
object Bar extends FooSingleton[Array[Byte]]
trait Baz[B] {
def b(b: B): String
}
object Baz {
implicit val bazByteArray: Baz[Array[Byte]] =
(b: Array[Byte]) => new String(b)
}
def g(a: Foo)(implicit baz: Baz[a.F]): Baz[a.F] = {
baz
}
val x1: Bar.type = Bar
val y1: Baz[x1.F] = f(x1)
def f[T](a: Foo { type F = T } ): Baz[T] = {
(a.asSingleton: FooSingleton[T]) match {
case bar # Bar => g(bar)
}
}
val x2: Foo = Bar
val y2: Baz[x2.F] = f(x2)
Your g compiles, because the path-dependent argument baz of type Baz[a.F] comes from the outside, a concrete implicit instance is inserted by the compiler, and the actual value a isn't used anywhere inside g.
Your f does not compile, because the B[a.F] appears only in the return type, and it cannot be made more concrete before an actual argument a is passed to f.
In a sense, the f breaks the path between the argument a and the returned value, because it makes the following "discontinuous jumps":
Start with a: Foo
Jump from a to the Bar singleton (by pattern-matching)
Use g to get from the concrete Bar singleton to the concrete Baz[Array[Byte]]
try to return this Baz[Array[Byte]], which seems no longer connected to Baz[a.F].
This path can be repaired by proving that the discontinuous "jump" is indeed just an identity path that stays in the same spot all the time, so it really doesn't move anywhere, so that a.F and the inferred type are the same, namely T.

Factory method with dependent type

I am struggling with dependent types in Scala 2.11.7. Here is the context:
trait Counter {
type T
def zero: T
def incr( t: T ): T
}
object IntCounter extends Counter {
type T = Int
val zero = 0
def incr( t: Int ) = t + 1
}
case class Foo( counter: Counter )
def twice( foo: Foo )( cntr: foo.counter.T ): foo.counter.T =
foo.counter.incr( foo.counter.incr( cntr ) )
So far so good, everything compiles. However I would like to add an object which contains both a Foo instance and a corresponding counter state. For instance:
trait Bar {
val foo: Foo
val current: foo.counter.T
}
The definition is OK (provided I use abstract vals). But I cannot define a factory method (aka smart constructors). All my naive attempts fail to compile. For example, the definition:
def bar( f: Foo )( cntr: f.counter.T ): Bar = new Bar {
val foo = f
val current = cntr
}
fails to compile with the error:
xxx: overriding value current in trait Bar of type this.foo.counter.T;
value current has incompatible type
val current = cntr
^
How can I force the compiler to understand that both type are indeed the same ? I could solve the problem with generics instead but I prefer to avoid this option if possible.
If bar is single constructor for Bar, you could solve it like this:
sealed trait Foo { //can't be case class because you can't even call `twice` method then
type Ctr <: Counter
type Z <: Ctr#T
val counter: Ctr
}
def foo[Ct <: Counter](ctr: Ct): Foo{type Ctr = Ct} = new Foo {
type Ctr = Ct
type Z = ctr.T
val counter = ctr
}
sealed trait Bar {
type Ctrr <: Counter
type TT <: Counter#T
val foo: Foo {type Ctr = Ctrr}
val current: TT
}
def bar[Ct <: Counter]( f: Foo{type Ctr = Ct} )( cntr: f.counter.T )(implicit ev: Ct =:= f.Ctr): Bar {type Ctrr = Ct; type TT = f.counter.T} = new Bar {
type Ctrr = Ct
type TT = f.counter.T
val foo = f
val current = cntr
}
Usage:
scala> val br = bar(foo(IntCounter))(5)
br: Bar{type Ctrr = IntCounter.type; type TT = Int} = $anon$1#35267fd4
scala> br.foo.counter.incr(br.current)
res41: Int = 6
The disadvantage here is that you have to specify (and maintain) the same root-type between TT and foo members wherever you create a new Foo instance.

Find implicit value by abstract type member

With a type like trait A[T], finding an implicit in scope is simply implicitly[A[SomeType]]
Can this be done and, if so, how is this done where the type-parameter is replaced with an abstract type member, like in trait A { type T }?
You can do
implicitly[A { type T = Int }
but you risk to lose precision:
scala> trait Foo { type T ; val t: T }
defined trait Foo
scala> implicit val intFoo: Foo { type T = Int } = new Foo { type T = Int ; val t = 23 }
intFoo: Foo{type T = Int} = $anon$1#6067b682
scala> implicitly[Foo].t // implicitly loses precision
res0: Foo#T = 23
To solve this problem, you can use the newly introduced the method, from the shapeless library (from which I've take the example above)
scala> the[Foo].t // the retains it
res1: Int = 23
scala> the[Foo].t+13
res2: Int = 36
I just realized this can be done with implicitly[A { type T = SomeType }]

How do I setup multiple ORed type bounds in Scala

Is it possible to do something like this in Scala:
class MyTest {
def foo[A <: String _or_ A <: Int](p:List[A]) = {}
}
That is, the type A could be a String or Int. Is this possible?
(Similar question here)
Not really possible as you put it, but you can do it using the type class pattern. For example, from here:
sealed abstract class Acceptable[T]
object Acceptable {
implicit object IntOk extends Acceptable[Int]
implicit object LongOk extends Acceptable[Long]
}
def f[T: Acceptable](t: T) = t
scala> f(1)
res0: Int = 1
scala> f(1L)
res1: Long = 1
scala> f(1.0)
<console>:8: error: could not find implicit value for parameter ev: Acceptable[Double]
f(1.0)
^
EDIT
This works if class and object are companions. On REPL, if you type each on a different line (ie, a "result" appears between them), they are not companions. You can type it like below, though:
scala> sealed abstract class Acceptable[T]; object Acceptable {
| implicit object IntOk extends Acceptable[Int]
| implicit object LongOk extends Acceptable[Long]
| }
defined class Acceptable
defined module Acceptable
You could get a little mileage from the Either type. However the Either hierarchy is sealed and handling more than two types becomes cumbersome.
scala> implicit def string2either(s: String) = Left(s)
string2either: (s: String)Left[String,Nothing]
scala> implicit def int2either(i: Int) = Right(i)
int2either: (i: Int)Right[Nothing,Int]
scala> type SorI = Either[String, Int]
defined type alias SorI
scala> def foo(a: SorI) {a match {
| case Left(v) => println("Got a "+v)
| case Right(v) => println("Got a "+v)
| }
| }
foo: (a: SorI)Unit
scala> def bar(a: List[SorI]) {
| a foreach foo
| }
bar: (a: List[SorI])Unit
scala>
scala> foo("Hello")
Got a Hello
scala> foo(10)
Got a 10
scala> bar(List(99, "beer"))
Got a 99
Got a beer
Another solution is wrapper classes:
case class IntList(l:List[Int])
case class StringList(l:List[String])
implicit def li2il(l:List[Int]) = IntList(l)
implicit def ls2sl(l:List[String]) = StringList(l)
def foo(list:IntList) = { println("Int-List " + list.l)}
def foo(list:StringList) = { println("String-List " + list.l)}
There is this hack:
implicit val x: Int = 0
def foo(a: List[Int])(implicit ignore: Int) { }
implicit val y = ""
def foo(a: List[String])(implicit ignore: String) { }
foo(1::2::Nil)
foo("a"::"b"::Nil)
See http://michid.wordpress.com/2010/06/14/working-around-type-erasure-ambiguities-scala/
And also this question.