Tag Archives: type inference

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;
    ...
  end
end

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
  where 
    A base C;
    A base D;

  return b ? c : d;
end

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

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

Action type inference

Last time I showed you the code:

params_ -> (COMMA- 
            p:param ~ <RichStr>{ new RichStr(p)})*
           { new Parameters(currCoords(),p) };

It’s no-brainer I didn’t like it very much because the type of the projection is too obvious. As the matter of fact the type of main action is also obvious.

At least I could add simple type inference — when the action starts with constructor call, extract the type name — so I did. It is enough to write:

params_ -> (COMMA- 
            p:param ~ { new RichStr(p)})*
           { new Parameters(currCoords(),p) };

and the types for “param” and “params_” will be inferred by NLT.

More features didn’t make this release because NLT code was plagued with bugs and annoyances — black Friday one could say. The most embarrassing showed up on LALR and forking LALR parser comparison. As it turned out when executing user actions in forking parser I didn’t check if there are any syntax errors, only if there are action errors.

Well, actually there is one more feature added — reducing number of productions in generated grammar. But since I don’t have plenty of use cases at hand I decided to play safely and disabled it. The code is in the uploaded solution so it is enough to uncomment one line to activate it.

Tagged ,