Sunday, August 23, 2015

Runtime Partial Specialization Dispatch

Sorry about the delay. After last post, I decided to implement runtime partial specialization to keep the behavior of the language consistent - if you have a method override that is a better "match" for your arguments, then Tangent will use it.

It turns out that was not quite as straightforward as I would've liked. The issues were mostly in how I was working with product types. In Tangent, a type tends to be anonymous and self-contained. Type Declarations on the other hand supply names and generic parameters for types. This caused an issue with compilation since generic product type constructors didn't really know where their generic bits came from. So by the time they made it down to the code-gen, I couldn't construct the appropriate .NET type.

Of course, it took a while to actually figure out that was the issue - after it took a while to write up the partial specialization dispatch code into the code-gen. Anyways - this example code now works:

foo(T) :> f(x: T){}

do(x: (T)) => void {
  print "in generic";

do(x: foo(T)) => void {
  print "in foo generic";

do(x: foo int) => void {
  print "in foo int";

bar(x: (T))=> void{
  do x;

entrypoint => void {
  bar "bar";
  bar f "bar";
  bar f 42;

Producing the properly dispatched output:

in generic
in foo generic
in foo int

I'm not sure if it's going to stay in the implementation or not. The dispatch for the most generic function is about 60 CIL operations, and doing type inference for the partial specialization requires reflection trickery. In short - it is slow, and slow in a way that I doubt could be improved too much.

I'll revisit it once I have users to complain about it.