Type-oriented programming/Self at the type level
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.