Volatile types in Scala 3 changed?

Because there is no SLS for Scala 3, to understand the concept of “paths”. I read the Paths definition for Scala 2.13, and confused by the following description:

p.x where p is a path and x is a stable member of p. Stable members are packages or members introduced by object definitions or by value definitions of non-volatile types.

Tried and googled a lot about volatile types, but still cannot know what volatile types should be in Scala 3. Tried some sample codes like Cannot override a type with non-volatile upper bound and cannot override a member with non-volatile type, but they all can be compiled by Scala 3 compiler (that is, the rejected codes in Scala 2 now compiled in Scala 3).

So my questions are:

  1. what does volatile types mean in Scala 3, any change compared to Scala 2, if Scala 3 still support volatile types? or
  2. Scala 3 has no volatile types support anymore. and if so, how to understand the case of “p.x”?.
  3. Maybe the definition is OK, because of the improvement of DOT Calculus, the Scala 3 compiler is more powerful and can deal more cases correctly.

Thanks for your help!


1 Like

Thanks for the linked post. It is helpful.

For that definition about p.x, p.x where p is a path and x is a stable member of p. But how could a package be a stable member (a package is not a value)? could you give a sample about it?

Thanks for your reply.

Why would it need to be a value? Paths are a type level concept, a lot of things there aren’t values. The spec simply defines “stable member” as “packages or members introduced by object definitions or by value definitions”. As the path p may refer to a package, and packages can contain other packages, x may also be a package.

An example of where a path referring to a package is used is in import clauses. You can import foo.bar.x, where x may be a package, so the path here doesn’t refer to a value or even a type.

1 Like

Thanks for the reply. I have a better understanding now, but one more thing still confuses me: what is the problem with volatile types, for the definition of p.x mentions “non-volatile types”?

The following code pass the type check, but have runtime error. Is it related to volatile type?

scala> class A
     | class B extends A
     | trait C:
     |   type U >: Null
     |   trait D:
     |     type T >: B <: A
     |   val z: D & U = null // volatile types definition: abstract type instance does not have any non-null value
     |   val y: z.T = new B 
     | class D extends C:
     |   trait E
     |   trait F:
     |     type T = E
     |   type U = F
     |   def frob(arg: E): E = arg
// defined class A
// defined class B
// defined trait C
// defined class D
scala> val d = new D
val d: D = D@1dbeedff
scala> d.frob(d.y)
java.lang.ClassCastException: class rs$line$1$B cannot be cast to class rs$line$1$D$E (rs$line$1$B and rs$line$1$D$E are in unnamed module of loader dotty.tools.repl.AbstractFileClassLoader @7fcff1b9)
  ... 32 elided

“D & U” should be a volatile type (right?), because U is abstract type and D contributes abstract member T to “D & U”. How about “z.T”? z is the instance of the volatile type. Maybe z is the part in p, so it is type check.

Anyway, understanding volatile type is tough.

Thanks for your help again.

BTW, the above code adapted for Scala 3 based on Cannot override a type with non-volatile upper bound