Double-edged constraints with a twist

One of the types in Skila library is generic Sequence (the counterpart of IEnumerable interface in C#). Assuming method concat is not supposed to create exactly the same type as the original one (as in Array for Array, List for List, and so on) but simply some Sequence how its signature should look like?

In C# it is defined as an extension method:

public static IEnumerable<TSource> Concat<TSource>(
	this IEnumerable<TSource> first,
	IEnumerable<TSource> second

Which is almost fine until you have to play with such code:

animals = cats.Select(it => (Animal)it).Concat(dogs);

Obviously it is an obstacle and those are not welcome in Skila — here is our signature:

interface Sequence<out T>
  // ~ stands for Sequence
  def concat<C>(seq ~C) ~C
    where C base T;

Unlike C#, Skila has two-way constraints — you can say some type parameter A has to inherit from B (A is B), or A has to be inherited by B (A base B). As for concat it is enough to write:

animals = cats +++ dogs; // temporary syntax for concat operator

base constraint works for type inference as well — of course noticing that Object is base of any other type is correct, but not very productive, thus for each constraint the lowest common ancestor (LCA) is computed. Still correct and probably exactly what you would like to see:

def twist<C,D,A>(b Bool,c C,d D) A
    A base C;
    A base D;

  return b ? c : d;

When you absorb this let Skila infer Animal type for you:

animal = twist(true,cat,dog);
Tagged , , ,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: