June 10, 2016 at 11:54 pm #1032
Hi, Mark. I was testing out the latest release of Monkey 2 (V009), and I wanted to see how interfaces behaved with ‘Structs’.
As I expected, they’re still passed by value even in the case of an interface. however, it seems that functions don’t agree with doing this at all.
The following code doesn’t build due to an error in the C++ output caused by calling ‘F’.Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869[crayon-5d0b67a1ed888436605322 inline="true" ]Interface ISomethingMethod Func:Int()EndStruct Thing Implements ISomethingMethod Func:Int()value = 10Return valueEndField value:IntEndFunction Main()Local a:= New Thing()' Check if 'a' is uneffected by uses of 'i':Local i:= Cast(a)Print("Calling 'Func' on our interface:")Print("i.Func: " + i.Func())Print("Contents of the original variable:")Print("a.value: " + a.value)' Make sure we're still in the same state.Assert(a.value = 0)' Try the same thing, but with a function:Print("Trying the same test, but with function calls:")F(a)F(i)Print("Contents of the original variable:")Print("a.value: " + a.value)' Once again, check for changes.Assert(a.value = 0)Print("All tests behaved as expected.")EndFunction F(something:ISomething)Print("Result: " + something.Func())End
When running the above code, I get this error whenever I try to pass a structure using an interface:Monkey123456789101112131415161718192021222324252627282930313233343536373839[crayon-5d0b67a1ed88d894171555 inline="true" ]MX2CC V0.009***** Building app 'E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.monkey2' *****Parsing...Semanting...Translating...Compiling....Build error: System command 'g++ -std=c++11 -m32 -O3 -DNDEBUG -I"E:/Other/Programming Languages/Monkey/monkey2/modules/monkey/native" -c -o "E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_00Test_0Interface_00Test.cpp.o" "E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_0Test_Interface_0Test.cpp"' failed.g++ -std=c++11 -m32 -O3 -DNDEBUG -I"E:/Other/Programming Languages/Monkey/monkey2/modules/monkey/native" -c -o "E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_00Test_0Interface_00Test.cpp.o" "E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_0Test_Interface_0Test.cpp"E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_0Test_Interface_0Test.cpp: In function 'void bbMain()':E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_0Test_Interface_0Test.cpp:26:18: error: cannot convert 't_default_Thing' to 't_default_ISomething*' for argument '1' to 'void g_default_F(t_default_ISomething*)'g_default_F(l_a);^E:/Other/Programming Languages/Monkey/2016/mx2/Interface_Test.buildv009/build_cache/desktop_release_windows/Interface_0Test_Interface_0Test.cpp:27:18: error: cannot convert 't_default_Thing' to 't_default_ISomething*' for argument '1' to 'void g_default_F(t_default_ISomething*)'g_default_F(l_i);^***** Fatal mx2cc error *****Build error.Done.
As a side note, I have no idea if I formatted this correctly, because there isn’t a formatting guide for this forum.June 11, 2016 at 7:02 pm #1036
Short answer is the compiler shouldn’t be allowing the struct->interface conversions, such as the cast or the F() call with ‘a’. This should cause an error – will fix.
Although structs can implement interfaces, they don’t really! An interface is a ‘reference type’ and a struct is a ‘value type’ and without some form of boxing (which mx2 does not and probably will not support) there is no way to convert a value type to a reference type. So these conversions should fail.
I’ve allowed structs to be able to implement interfaces though for the sake of allowing you to specify generic constraints, eg: you can do this for F():Monkey123Function F<T>( something:T ) Where T Implements ISomethingEnd
When a struct implements an interace, it’s a purely static thing. The struct is checked to make sure it implements all interface methods but that’s all that really happens – the struct doesn’t gain a ‘virtual function table’ or anything, and no extra c++ code is generated.
The built-in primitives already implement some interfaces, eg: Int implements IIntegral which extends INumeric. This allows you to write methods like:Monkey123Method Add<C>( c:C ) Where C Implements INumeric 'can be used with any numeric type!End
This is currently a bit ‘loose’ in that INumeric doesn’t actually have any methods so it’s not clearly defined what it even means to be numeric. This means you can declare something that implements INumeric and ‘Add’ could fail to work with it because it expects it to have Operator+ or something. But it works OK for the built-in types.
I’m waiting until I get some more time to improve this side of things, but what’s really needed I think are generic methods in interfaces and this is a bit tricky! I had a shot and have an idea of the issues involved but decided it was a ‘later’ feature in the end.June 11, 2016 at 7:03 pm #1037
> there isn’t a formatting guide for this forum.
I just use the ‘<>’ button in the visual editor toolbar and paste my code there.June 11, 2016 at 10:57 pm #1043
Makes sense. Although, this also means that from the perspective of the programmer, the template is largely superficial. In other words, if interfaces weren’t reference-only, then ‘data-based interfaces’ could be used the same way, only allowing for tighter constraints, which would help reduce unknown behavior.
Basically, my perspective is that, like templates, the compiler could generate multiple versions based on the provided type (In the case of static uses or structs).
Then, from the perspective of Monkey, you would be purposely restricting yourself to the feature-set of the interface. In addition, like generic functions, you could take in class-based types as well.
The idea is that interfaces could be used to simplify the syntax for mundane generic routines, with self-applied restrictions. It would be less typing by the authors, and the same amount of typing for the users.
Then again, this all seems possible with templates, so it’s not like this can’t already be done. Although, it would help keep code stricter for the times you don’t need function templates.
It may be syntactic sugar, but it’s actually similar to what’s been discussed for concepts in C++ over the last few years.
At any rate, thank you for verifying the intended behavior.
You must be logged in to reply to this topic.