In Slang data type declarations, fields are given a name and type as part of the Scala class signature, which defines the only constructor. Since data types are immutable, the fields are always considered to be val fields, even when the val qualifier is omitted.

Data types can have additional fields beyond those in given in the class signature, and their immutable values must be specified in terms of other variables in scope at the point of instance creation.

All types of data type fields must be immutable.

Data types can also have methods, but corresponding to the immutability of the data type, these cannot modify field values.

Note

JH: To Robby, can we consider these methods to be implicitly @pure?

		
  // Each Slang class must have a @datatype or @record annotation.
  // @datatype are immutable structures
  //   ...they can only contain val fields and immutable objects
  @datatype class Coordinate(x: Z, val y: Z) {
    // Declare fields in constructor.
    // Val can be omitted, but such fields are implicitly "val".

    val isCenter: B = x == 0 && y == 0    // additional fields can be declared that
                                          // derive their values from the (immutable) state
                                          // of constructor fields. 
                                          // Explicit type declaration is required.

    // The class may include methods that don't change the state of the object
    def isEqualX(other: Coordinate): B = {
      return x == other.x
    }

    def isEqualY(other: Coordinate): B = {
      return y == other.y
    }
  }

As with Scala case classes, one does not use the keyword new when creating instances of Slang data types (Slang record creation also omits new). Slang data types and records are compared using structural equality. Slang also provides a convenient syntax for creating copies of previous instances (this is somewhat analogous to implicitly using the copy method of Scala case classes – see here).

  
  // example client actions
  val c1 = Coordinate(3, 4)   // create an instance of the data type class
  assert(!c1.isCenter)

  val c2 = c1(x = 5) // produces a new instance (copy) where its x is 5 and its y is c1.y

  assert(!c1.isEqualX(c2) && c1.isEqualY(c2))

  assert(c1 == c2(x = 3)) // create a new instance derived from c2
                          // assertion succeeds due to structural equality

  var c3 = c1             // One can have a *variable* that refers to *immutable* objects 
  c3 = c2                 // Even though the data structure itself is immutable (we can't change the fields),
                          // the variable reference is mutable (we can assign different instances to it).

The last few lines in the above example illustrate the difference between the notions of mutability of a data structure and mutability of a Slang variable: one can have a var that can be updated (mutated) to reference different immutable structures.