7

Let's say I have such code (and its meaning is like in C#):

class Foo<T>
{
   public T my_field;
}

and later in code I have:

var foo = new Foo<int>(); 
foo.my_field = 5;

My problem starts with the Foo<int>. What I currently do is I take type Foo<T> and mapping T -> int and clone the surface of that type. Surface because I skip init expressions, method/property bodies, but nevertheless I create something like this on the fly:

class Foo<int>
{
   public int my_field;
}

and then continue as it would be the usual type. The good thing is it works but the bad thing is it works slowly -- profiler does not hestitate to point out it is the bottleneck.

The other idea I have is using something like a "view" which would consist of reference to generic type (here Foo<T>) and mapping (here T -> int) and then using it each time I reference instance of generic type. In case of foo, I would go through such view to a field, I would get its type T, and "filter" it back through the view to get finally the result: int. I would like to avoid trial&error approach so...

My question is how instances of generic type are handled in compiler (not in runtime)? I mean for real :-).

4
  • 1
    Not sure my compiler is real enough, but I use your view concept.
    – Telastyn
    Jul 3, 2016 at 13:52
  • Have you looked at the Roslyn source code? The C# compiler is freely available. Maybe just take a look to see how the Roslyn team did it?
    – RubberDuck
    Jul 3, 2016 at 14:26
  • @RubberDuck, I already checked several compilers (not Roslyn actually), but I drowned in the code, that is why I asked :-). But thank you for the tip, maybe Roslyn will be a bit easier. Jul 3, 2016 at 14:28
  • @greenoldman Roslyn is the C# compiler, so being you're interested in what looks like verbatim C# syntax, it could be useful. Might not be, because of the whole swimming in code thing...
    – RubberDuck
    Jul 3, 2016 at 14:32

1 Answer 1

3

What I've done (in a compiler that targets CIL) is have a series of objects that represent the various elements in the type system:

  • GenericParameter - represents T in the code above - specifically the T owned by Foo. It has a name, and a constraint.
  • GenericArgumentReferenceType - represents T as used in the field above. It's not a declaration of a generic type, it's a reference to another.
  • BoundGenericType - represents Foo<int> when int is bound to T. This binding is useful since you can see what the source generic type is, as well as what the concrete type is, and models the .NET TypeBuilderInstantiation stuff and MakeGenericType constructs. It's a simple pair with some logic to return the "effective" type.

So Foo<T> is a type with one GenericParameter, which has one field with a GenericArgumentReference. Foo<int> then constructs a new BoundGenericType tying Foo<T> and int. For me the bound generic type has no fields - it is just a pair tying the two together. I need to do it in order to prevent scope explosion, but that might be particular to my language.

I also have separate objects to represent inference points for function generics. And there are separate expressions that access the generic parameters in functions. These are perhaps outside of the scope of your question.

Regardless, generics tend to get tricky. Remember to work out:

  • What happens when you have Bar<T>, and it has a Foo<T> member?
  • What happens when you have a function in Foo<T> that has a generic parameter T?
  • What happens when you have a List<T> in Foo<T>?
  • What happens when you're inferring T for a Foo<T> in a function?
2
  • Do you blog? :-) This is very interesting, and true, I didn't ask about how to implement generic functions, but I would love to hear how did you do it. So if you don't mind small update or something like this... :-) Jul 3, 2016 at 20:49
  • 1
    @greenoldman - here though I'm not sure how well done or helpful it is. Also, the broader language is... Atypical, so some things cannot translate. Generic functions work very similarly, though inference needs to be done.
    – Telastyn
    Jul 3, 2016 at 21:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.