Proposal for virtual functionality

Imagine the following code :

trait drawable(otype T) {
      void draw(T* );
};

struct text {
      char* text;
};

void draw(text*);

struct line{
      vec2 start;
      vec2 end;
};

void draw(line*);

While all the members of this simple UI support drawing creating a UI that easily
supports both these UI requires some tedious boiler-plate code :

enum type_t { text, line };

struct widget {
      type_t type;
      union {
            text t;
            line l;
      };
};

void draw(widget* w) {
      switch(w->type) {
            case text : draw(&w->text); break;
            case line : draw(&w->line); break;
            default : handle_error(); break;
      }
}

While this code will work as indented, adding any new widgets or any new widget behaviors
requires changing existing code to add the desired functionality. To ease this maintenance
effort required CFA introduces the concept of dynamic types, in a manner similar to C++.

A simple usage of dynamic type with the previous example would look like :

drawable* objects[10];
fill_objects(objects);

while(running) {
      for(drawable* object : objects) {
            draw(object);
      }
}

However, this is not currently do-able in the current CFA and furthermore is not
possible to implement statically. Therefore we need to add a new feature to handle
having dynamic types like this (That is types that are found dynamically not types
that change dynamically).

C++ uses inheritance and virtual functions to find the
desired type dynamically. CFA takes inspiration from this solution.

What we really want to do is express the fact that calling draw() on a object
should find the dynamic type of the parameter before calling the routine, much like the
hand written example given above. We can express this by adding the virtual keyword on
the parameter of the constraints on our trait:

trait drawable(otype T) {
      void draw(virtual T* );
};

This expresses the idea that drawable is similar to an abstract base class in C++ and
also gives meaning to trying to take a pointer of drawable. That is anything that can
be cast to a drawable pointer has the necessary information to call the draw routine on
that type. Before that drawable was only a abstract type while now it also points to a
piece of storage which specify which behavior the object will have at run time.

This storage needs to be allocate somewhere. C++ just adds an invisible pointer at
the beginning of the struct but we can do something more explicit for users, actually
have a visible special field :

struct text {
      char* text;
      vtable drawable;
};

struct line{
      vtable drawable;
      vec2 start;
      vec2 end;
};

With these semantics, adding a "vtable drawable" means that text pointers and line pointers are now
convertible to drawable pointers. This conversion will not necessarily be a type only change however, indeed,
the drawable pointer will point to the field "vtable drawable" not the head of the struct. However, since all
the types are known at compile time, converting pointers becomes a simple offset operations.

The vtable field contains a pointer to a vtable which contains all the information needed for the caller
to find the function pointer of the desired behavior.

One of the limitations of this design is that it does not support double dispatching, which
concretely means traits cannot have routines with more than one virtual parameter. This design
would have many ambiguities if it did support multiple virtual parameter. A futher limitation is 
that traits over more than one type cannot have vtables meaningfully defined for them, as the 
particular vtable to use would be a function of the other type(s) the trait is defined over.

It is worth noting that the function pointers in these vtables are bound at object construction, rather than 
function call-site, as in Cforall's existing polymorphic functions. As such, it is possible that two objects 
with the same static type would have a different vtable (consider what happens if draw(line*) is overridden 
between the definitions of two line objects). Given that the virtual drawable* erases static types though, 
this should not be confusing in practice. A more distressing possibility is that of creating an object that 
outlives the scope of one of the functions in its vtable. This is certainly a possible bug, but it is of a 
type that C programmers are familiar with, and should be able to avoid by the usual methods.

Extensibility.

One of the obvious critics of this implementation is that it lacks extensibility for classes
that cannot be modified (ex: Linux C headers). However this solution can be extended to
allow more extensibility by adding "Fat pointers".

Indeed, users could already "solve" this issue by writing their own fat pointers as such:

trait MyContext(otype T) {
      void* get_stack(virtual T*)
};

void* get_stack(ucontext_t *context);

struct fat_ucontext_t {
      vtable MyContext;
      ucontext_t *context;
}

//Tedious forwarding routine
void* get_stack(fat_ucontext_t *ptr) {
      return get_stack(ptr->context);
}

However, users would have to write all the virtual methods they want to override and make
them all simply forward to the existing method that takes the corresponding POCO(Plain Old C Object).

The alternative we propose is to use language level fat pointers :

trait MyContext(otype T) {
      void* get_stack(virtual T*)
};

void* get_stack(ucontext_t *context);

//The type vptr(ucontext_t) all
vptr(ucontext_t) context;

These behave exactly as the previous example but all the forwarding routines are automatically generated.

Bikeshedding.

It may be desirable to add fewer new keywords than discussed in this proposal; it is possible that "virtual" 
could replace both "vtable" and "vptr" above with unambiguous contextual meaning. However, for purposes of 
clarity in the design discussion it is beneficial to keep the keywords for separate concepts distinct.

