8

I'm reading Scala in depth now. Here is an excerpt from the book:

All path-dependent types are type projections. A path-dependent type foo.Bar is rewritten as foo.type#Bar by the compiler...

In Scala, all type references can be written as projects against named entities. The type scala.String is shorthand for scala.type#String where the name scala refers to the package scala and the type String is defined by the String class on the scala package.

Obviously, there isn't scala.String class, but I failed to reproduce this with Null.

scala> type N = scala.type#Null
<console>:7: error: type mismatch;
 found   : type
 required: AnyRef
       type N = scala.type#Null

So, my questions are as follows. Are path-dependent types type projections? Is it just inner compiler representation or can be expressed in scala code?

4e6
  • 10,696
  • 4
  • 52
  • 62

1 Answers1

10

Here's a quick REPL session which confirms what Josh wrote,

scala> class Foo { type T = String }
defined class Foo

scala> val foo = new Foo
foo: Foo = Foo@10babe8

scala> implicitly[foo.type#T =:= foo.T]
res0: =:=[foo.T,foo.T] = <function1>

The problem with your scala.type#Null example is that the prefix scala is a package prefix rather than being a stable identifier of a value. Arguably it ought to be the latter, but unfortunately it's not ... that's a lingering mismatch between the semantics of Scala packages and Scala objects (in the sense of modules).

Miles Sabin
  • 23,015
  • 6
  • 61
  • 95
  • But according to SLS §3.1 `A path is one of the following... p.x where p is a path and x is a stable member of p. Stable members are packages or... A stable identifier is a path which ends in an identifier.` `scala.Null` is stable identifier. Right? – 4e6 May 11 '12 at 18:49
  • No, all stable identifiers are values or packages: `scala.Null` designates a type not a value. `scala` is a stable identifier but, as you observed, being a package rather than an object, its behaviour wrt the singleton type forming in operator `.type` is different from the example `foo` I gave in my answer. – Miles Sabin May 11 '12 at 19:00
  • Oh, now, finally I see it's all about `.type` behaviour. It took so much time to understand it. Thank you so much :) – 4e6 May 11 '12 at 19:28
  • @MilesSabin Sorry to bother you but I have a question about the line ```implicitly[foo.type#T =:= foo.T]```, =:= is used to judge whether two types are the same so the result is a boolean value, but implicitly method requires a T as type parameter, so why that line works and returns a function1 in form of =:=[foo.T,foo.T]. – Allen Chou Aug 05 '15 at 02:48
  • 1
    @AllenChou No, it's a function, not a boolean. `foo.type#T =:= foo.T` is an infix type, which desugars to `=:=[foo.type#T, foo.T]`, which `extends (foo.type#T) => foo.T`. Read the `Predef` docs. The implicit evidence returned is `=:=.tpEquals[foo.T]`. – Mike Aug 23 '15 at 17:44