scalatypesanonymous-classrefinement-type

What is a difference between refinement type and anonymous subclass in Scala 3?


Anonymous class definition is

An anonymous class is a synthetic subclass generated by the Scala compiler from a new expression in which the class or trait name is followed by curly braces. The curly braces contains the body of the anonymous subclass, which may be empty. However, if the name following new refers to a trait or class that contains abstract members, these must be made concrete inside the curly braces that define the body of the anonymous subclass.

Refinement type definition is

A type formed by supplying a base type a number of members inside curly braces. The members in the curly braces refine the types that are present in the base type. For example, the type of “animal that eats grass” is Animal { type SuitableFood = Grass }

-- Both definitions are taken from book Programming in Scala Fifth Edition by Martin Odersky and others.

What is the difference? Can you illustrate it with simple examples?


Let's see my code example which compiles:

abstract class A:
  type T

// anonymous class
var o1 = new A { type T = String }

// refinement type
var o2: A { type T = String } = null

o1 = o2 // OK
o2 = o1 // OK

It seems to me that refinement type is a handy way to create a new type, which anonymous class does implicitly.


Solution

  • Type and class are different (and actually orthogonal) concepts. Types belong to type theory, classes belong to OOP. Classes exist in bytecode, types mostly don't exist in bytecode (if they are not persisted to runtime specially or if they don't correspond to classes obviously).

    What is the difference between a class and a type in Scala (and Java)?

    What is the difference between Type and Class?

    https://typelevel.org/blog/2017/02/13/more-types-than-classes.html

    new A { type T = String } is a shorthand for

    {
      class AImpl extends A {
        type T = String
      }
    
      new AImpl
    }
    

    If you define an anonymous class

    val o1 = new A { type T = String }
    

    the type of o1 can be, for example, refined

    val o1: A { type T = String } = new A { type T = String }
    

    or even structural

    val o1: A { type T = String; def foo(): Unit } = new A { 
      type T = String
      def foo(): Unit = println("foo")
    }
    

    or not refined if we statically upcast, just

    val o1: A = new A { type T = String }
    

    So defining an anonymous class doesn't mean that the type of variable is a refinement type.

    On the other hand, you can consider refined type

    type X = A { type T = String }
    
    val o2: A { type T = String } = null
    

    not introducing an anonymous class. The only class in bytecode now is A, there is no AImpl (until you instantiate new ...).

    Scala refined types can be compared with refinement types in type theory (or programming languages with dependent types), i.e. (dependent) types endowed with a predicate.