Monthly Archives: November 2017

Type unions and intersections

This is something I wanted to do from the first days of Skila, however the engine in Skila-1 was such a patchwork that it died before it was possible. Skila-3 finally has both kinds of sets:

let y *Submarine & *Plane = ••• 
let x *Submarine | *Plane = •••

The first line declares an intersection — we are making here some really super vehicle which can fly, dive and speedUp, because it has all the members of given element types.

On the other hand, the second line builds somewhat limited vehicle using a type union — we can only speedUp, because it has only common members, which are present in each of the given element type.

Is it practical in real life or is it just a fancy academia stuff? The former, the lack of set types in C# is killing me — I can mitigate the problem a little when I am getting data:

void loan<V>(V vehicle) 
  where V : Submarine, Plane

which gives me an intersection, but I am toasted when it comes to the output:

V create<V>() 
  where V : Submarine, Plane

It breaks the responsibility rule, because caller of create has to specify concrete type and inside create we have no chance to really create it (except for trivial case with default constructor).

And I have to cope with it all the time when writing wrappers for devices — I take them specifying their capabilities as constraints but I am unable to specify the capabilities of what I create (unless I am willing to create ton of interfaces — TelescopeWithThis, TelescopeWithThat).

Advertisement
Tagged , , ,

Prototypes and “has” constraint

I am really glad I went with interpreter — it allows me to check ideas much faster than before, when I was playing with PHP transpiler.

I added support for prototypes (as in Go) and an option for regular interfaces to turn them into prototypes as well — so you can type substitution matching or structural matching:

prototype PHost
{
  string say();
}

interface IHost
{
  string say();
}

struct Host : IHost
{
  public override string say() => "hello";
}

let h1 *IHost = new Host();
h1.say();
let h2 *PHost = new Host();
h2.say();

The first declaration and call work because the types are matched as in C# — Host is derived from IHost and substitution is possible. In the second case it is also possible but not because Host is derived from PHost (it is not), but because all the methods PHost requests are defined in Host.

I am wondering about adding option to limit type implementation (class or struct) substitution. Say you have class “Parent” and derived from it class “Child”. You could pass *Child for *Child or *Parent for *Parent, but not *Child for *Parent. For full substitution you would have to go with interfaces/prototypes and this in turn would promote using them.

Supporting the notion of the duck typing already paid off — it was fairly easy to add has constraints for templates:

void welcome<T>(actor *T)
  where T has string say();
{
  actor.say();
}

When there is any has constraint present, compiler turns internally the type parameter into a prototype and the rest is already written.

In the example above I pass the pointer simply because I didn‘t yet write templates properly and they don’t work with values. Maybe next weeek…

Tagged , ,

Skila3 — starting again…

Well, the first Skila attempt is dead and maybe luckily so. The compiler was way too slow (it needed for entire testsuite around 40 minutes) and I tried to fix it, then to start from scratch but I stopped the work — the design of the language itself was doomed to fail from the beginning. You simply cannot ignore performance of the language (not compiler) itself — in C# if you rely on exceptions instead of methods TryXXX you can face x220 slowdown. In Python if you use regular arrays you will soon hear “use NumPy instead”, in JS if you need speed you have to shove your code into GPU (“ConvNet.js is great but it is written in JS, so now we have DeepLearn.js…”). It is the same story no matter what the language is.

And so on the 28th of December, 2016 I started Skila3, initially as only a good-bye exercise in type matching. In time the work gained some speed as I added more features.

This time I dropped parser, at this point it is only a distraction. This decision allowed me to gain a new perspective — why not treat semantic analyser and code generator as engine, and parser as exchangeable skin? Something like C# and VB for .Net but on different level.

Anyway, syntax is so ahead of me that I don’t think about it at all. As for the old code, instead of refactoring it I started clean, I don’t even bring it in pieces. Currently I have rough basics — notion of deep immutability, conditionals, loops, generics, concurrency and channels (as in Go). A lot of ideas from initial Skila wait for being brought to this new project.

To speed working on compiler at first I wrote interpreter instead to check whether I can add numbers together, and well — I can.

The code is more straightforward than before — there two passes of computation, evaluation and validation. The former does name binding, computes the types of the expressions and so on, the latter one checks whether the outcomes of the expressions are read or whether the variables are assigned before they are used. I put the code at GitHub, so take a look at spare time.

Tagged , , ,