The Slang record syntax is similar to that of Slang data types, with additional features added to support mutability. Records can have a mix of mutable and immutable fields. var is used to indicate mutability for both fields listed in the class declaration/constructor as well as for internal fields. As with Slang data types, fields without a val/var annotation are implicitly val. For internally declared fields, private can also be used to control visibility (this also applies to data types).

		
  @record class MutCoordinate(var x: Z, var y: Z, z: Z) {
                          // var fields (e.g., x and y) are mutable.
                          // Fields without var/val (e.g., z) default to val.
                          // val fields are immutable.

    var used: B = F       // Records can also have var/val fields whose initial values
                          // are not provided via the constructor.

    private var flagged: B = F  // internally declared fields can be declared private, as in Scala

    def isCenter: B = { return x == 0 && y == 0 && z == 0}

    def isEqualX(other: Coordinate): B = {
      return x == other.x
    }

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

The example client code below illustrates how var record fields can be updated, whereas val fields cannot. Note that there is a distinction between the mutability of identifier/variables and the mutability of structures to which they bind. For example, val identifiers can be bound to records – in such cases, the record structure can be updated, but the identifier binding itself cannot. Similarly, var identifiers can be bound to immutable data types – a new data type instance may be assigned to the variable, but the structure itself cannot be changed.


  val c4: MutCoordinate = MutCoordinate(5,7,20)  // construct a record instance
                   // A val (immutable var) can used to refer to a mutable structure.
                   // While fields of the structure can be updated, the variable itself cannot.

  c4.x = 6
  // c4.z = 21      // ERROR: assignment to val fields of record is not allowed.

  c4.used = T       // Public internal fields can be assigned.

  // c4.flagged = T  // ERROR: private internal fields cannot be assigned

The examples below illustrate Slang’s copy-on-demand semantics for records (an explanation follows below).


  val c5 = c4       // When Slang mutable structures are assigned to other variables,
                  // they are implicitly copied to avoid aliasing.  In this case,
                  // a copy of the record bound to c4 is created to bind to c5.
  c4.y = 8          // Update a field of c4

  assert(c4.y != c5.y)  // Record bound to c4 is not shared with c5
                      // (update to c4 is not reflected in c5).

  var c6 = c5(y = 8)  // The "copy syntax" used for data types can also be used for records.

  assert(c4 == c6)    // Equality is structural.

When the value of c4 is assigned to c5, c4’s value is notionally copied to c5. The Slang compiler does not necessarily cause the copy to be implemented immediately. The effect of the copy can be seen in that the assignment to c4.y does not affect the value of c5.y, as indicated by the following assertion.

The struct(field1 = value1, fieldn = valuen) notation for creating a copy of the structure with the same value except for changes to the listed fields can be used for records as well as data types.

Note

JH: To Robby, the Slang By Example includes an additional example where the isEqual method is overridden. I wasn’t sure how to explain or motivate this. I was worried that overriding the definition of == would generate problems with the logic (i.e., changing the notion of equality). Are there some properties that the new equality must maintain?