I am really glad I went with interpreter — it allows me to check ideas much faster than before, when I was playing with PHP transpiler.
I added support for prototypes (as in Go) and an option for regular interfaces to turn them into prototypes as well — so you can type substitution matching or structural matching:
prototype PHost { string say(); } interface IHost { string say(); } struct Host : IHost { public override string say() => "hello"; } let h1 *IHost = new Host(); h1.say(); let h2 *PHost = new Host(); h2.say();
The first declaration and call work because the types are matched as in C# — Host
is derived from IHost
and substitution is possible. In the second case it is also possible but not because Host
is derived from PHost
(it is not), but because all the methods PHost
requests are defined in Host
.
I am wondering about adding option to limit type implementation (class
or struct
) substitution. Say you have class “Parent” and derived from it class “Child”. You could pass *Child
for *Child
or *Parent
for *Parent
, but not *Child
for *Parent
. For full substitution you would have to go with interfaces/prototypes and this in turn would promote using them.
Supporting the notion of the duck typing already paid off — it was fairly easy to add has
constraints for templates:
void welcome<T>(actor *T) where T has string say(); { actor.say(); }
When there is any has
constraint present, compiler turns internally the type parameter into a prototype and the rest is already written.
In the example above I pass the pointer simply because I didn‘t yet write templates properly and they don’t work with values. Maybe next weeek…