Type-oriented programming/Bounded type arguments

Consider the following code:

type Equatable {
  func equals(x Any) Bool
}

type Complex : Equatable {
  property real Float
  property imag Float

  func equals(x Any) Bool {
    if x is Complex then {
      var x = x as Complex
      return self.real == x.real & self.imag == x.imag
    }
    return false
  }
}

type Pair[T] {
  property first T
  property second T
}

main {
  var x = new Complex { real=2.0, imag=3.0 }
  var y = new Complex { real=2.0, imag=3.0 }
  return x.equals(y)
}

We now want to implement the equals method also for Pair:

func equals(p Pair[T]) Bool {
  return self.first.equals(p.first) & self.second.equals(p.second)
}

Note, however, that this code won’t compile since the compiler can’t be sure that T represents an equatable type. We need to change the declaration of Pair to

type Pair[T:Equatable] { ... }

Now it’s ensured that T is equatable and we can check pairs for equality:

main {
  var x = new Complex { real=2.0, imag=3.0 }
  var y = new Complex { real=2.0, imag=4.0 }
  var p1 = new Pair[Complex] { first=x, second=y }
  var p2 = new Pair[Complex] { first=x, second=y }
  return p1.equals(p2)
}

Here, the T type argument is called bounded since there’s a type constraint placed on it.

NB: The pseudocode can be tried out using the Funcy app, which can be downloaded for free from Apple’s App Store (iOS/macOS), Google Play (Android) or Amazon Appstore. The code to be executed must be placed in a main {} block.