```csharp= public void Foo<TValue>(TValue x) where TValue : new() { var x = new TValue(); } public void Main() { Foo(42); Foo("asdlkjadsf"); Foo(0.234); Foo(1_394_258u); Foo(new MyType {x = "Pancake"}); } ``` With polymorphism this compiles to ```csharp= public void Foo<TValue>(TValue x) where TValue : new() { TValue x = new TValue(); } public void Main() { Foo<int>(42); Foo<string>("asdlkjadsf"); Foo<double>(0.234); Foo<long>(1_394_258u); Foo<MyType>(new MyType {x = "Pancake"}); } ``` Line 1-5 function in the compiled example uses dynamic dispatch to invoke the constructor, the psuedo code is like ```csharp= public void Foo<TValue>(TValue x) where TValue : new() { unsafe//This is psuedo code in C# style { var type = typeof(TValue); var vTable = type.Functions; var constructor = vTable.Single(x => x.Parameters.IsEmpty); var size = type.DataStorageSize; using fixed IntPointer ptr = Marshaller.AllocateObject(type, size); var constructedObject = constructor(ptr, null); TValue x = (TValue)constructedObject; } } ``` There is one version of the function that always works in terms of `TValue` and at runtime looks up the information to decide what object type to allocate and how to construct it. With monomorphism you trade increased space for better time. ```csharp= public void Foo<int>(int x) where TValue : new() { unsafe//This is psuedo code in C# style { using fixed IntPointer ptr = Marshaller.AllocateObject(int), 4); var constructedObject = intEmptyConstructor(ptr, null); int x = (int)constructedObject; } } public void Foo<string>(string x) where TValue : new() { unsafe//This is psuedo code in C# style { using fixed IntPointer ptr = Marshaller.AllocateObject(string), 8); var constructedObject = stringEmptyConstructor(ptr, null); string x = (string)constructedObject; } } public void Foo<double>(double x) where TValue : new() { unsafe//This is psuedo code in C# style { using fixed IntPointer ptr = Marshaller.AllocateObject(double), 8); var constructedObject = doubleEmptyConstructor(ptr, null); double x = (double)constructedObject; } } public void Foo<long>(long x) where TValue : new() { unsafe//This is psuedo code in C# style { using fixed IntPointer ptr = Marshaller.AllocateObject(long), 8); var constructedObject = longEmptyConstructor(ptr, null); long x = (long)constructedObject; } } ``` With the monomorphized version that are no type arguments anymore. The compiler spits "one type" versions of the function instead of the "many type" that the polymorphic world view has. Since it is a single type the compiler can plug in a lot of known values at compile time instead of having to look up at runtime what was passed in. We don't have to lookup the type, find the constructor, and ask it how many bytes it takes. The compiler finds the single empty constructor for int. The compiler can look at the data structure for int and know it's exactly 4 bytes long. This leaves the only things the compiler can't do upfront as: * Getting the memory address of the new object. * Can't do this since it needs to ask the GC system for the next available address. This can't be known ahead of time. * Running the constructor to produce those 4 bytes * With our language there are situations in which this could also be moved to compile time, if it can proven pure.