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

235 views Asked by At

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.

2

There are 2 answers

0
Dmytro Mitin On BEST ANSWER

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.

0
Talos On

As Dmytro Mitin pointed out in [1] and [2], the main difference is the same as the difference between class and type.

A type restricts the possible values to which a variable can refer, or an expression can produce, at run time. Refinement type is still a type, which may be used instead of defining a new class.

Without using the refinement type in the example, you would have to define a new class.

class AString extends A:
  type T = String

A class is a blueprint for objects. Once you define a class, you can create objects from the class blueprint with the keyword new.