Type-oriented programming/Self at the type level

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Just like the self variable refers contextually to the instance in whose method it’s used, the Self type variable contextually refers to the type. Let’s have a look at a simple example:

type A {
  sfunc create() Self {
    return new Self
  }
}

type B : A {}

main {
  var obj = $B.create()
  return obj
}

The create method’s return type is Self so in the example above it refers to the B type because we called the type method using $B.create().

Using Self gives the type system considerable power since it squares well with type operators, as illustrated by the following example:

type Maybe[T] {
  property val T

  func description() String {
    return self.val.isNil() ? "none" : self.val.description()
  }

  func map[U](f Func[T,U]) Self[U] {
    return new Self[U] {
      val = self.val.isNil() ? nil : f(self.val)
    }
  }
}

main {
  var x = new Maybe[Int] { val=3 }
  var y = x.map[Float](\(x Int) Float . x.asFloat())
  return y.description() + " " + y.typeName()
}

Note that the map method has a type argument and how new Self[U] is used. In this case Self is a contextual type operator.

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.