About Monkey 2 › Forums › Monkey 2 Development › Struct goofiness
This topic contains 7 replies, has 7 voices, and was last updated by
Amon
2 years ago.
-
AuthorPosts
-
March 22, 2017 at 5:26 am #7570
https://github.com/blitz-research/monkey2/issues/160
In the following code, calling the virtual method Update() from each item in the stack will call the Base Struct’s Update, instead of the correct one. Replacing Structs with Classes works as expected.
Monkey12345678910111213141516171819202122232425262728293031323334353637#Import "<std>"Using std..Struct TestGlobal all := New Stack<Test>Method Update() VirtualPrint "Base class"EndEndStruct Test_A Extends TestMethod New()all.Push( Self )EndMethod Update() Override '<----Ignored if Struct instead of classPrint "Donald Duck"EndEndStruct Test_B Extends TestMethod New()all.Push( Self )EndMethod Update() Override '<----Ignored if Struct instead of classPrint "Scrooge McDuck"EndEnd'***********************************'Function Main()Local a := New Test_ALocal b := New Test_BFor Local n := 0 Until Test.all.LengthTest.all[n].Update()NextEndCheers.
March 22, 2017 at 7:47 am #7571In the docs:
Structs
Structs are similar classes, but differ in several important ways:
A struct is a ‘value type’, whereas a class is a ‘reference type’. This means that when you assign a struct to a variable, pass a struct to a function or return a struct from a function, the entire struct is copied in the process.
Stucts are statically typed, whereas classes are dynamically typed.
Struct methods cannot be virtual.
A struct cannot extend anything.So it should tell you may not extend struct and use virtual methods. Or structs are now extendable?
March 22, 2017 at 6:04 pm #7574Hmm bummer, didn’t know about that. An error message would be nice in a case like this.
How would you deal with this situation, where I need a single stack and each item in the stack needs to call its own “Update” method? I’m creating a render queue (so I can sort the drawing order based on coordinates) where each item in the queue can be of a different type (“Image quad”, “text”, etc.).
The reason I’m using structs is that a large number of those are created each frame and discarded on the next.
I guess I’ll create a single Struct with a “style:Int” field, and use 0 for quads, 1 for text, etc, and the Update method will select the appropriate rendering style for each item.
Thanks!
March 23, 2017 at 1:37 am #7577Structs cannot use ‘extends’ – I’m sure they use to give an error, not sure what happened there but I’ll add the error back.
Hypothetical structs of common base type could not (easily) be added to a stack anyway, mainly because different derived structs may have different sizes, eg: a ‘Text Extends Drawable’ struct may have an extra ‘text’ field etc, and stacks (or really the underlying arrays) expect elements to be of the same size for sane indexing. This is not a problem with class objects, as elements are just pointers.
In general, this is the core problem with allowing structs to ‘extend’ other structs – converting a derived struct to a base struct (when assigning to var or passing to function) often means truncating the derived struct – and this really means changing the ‘virtual function table’ pointer in case derived’s virtual methods use fields not in base. This means virtual methods are pretty much useless.
All in all it gets pretty ugly so I decided to give it a miss.
April 6, 2017 at 7:58 am #7734In the world of C structs technically are a collection of variables, where this is the only way that the data of the program can be modeled.
However in other object oriented languages, usage of structs has been limited to some very specific purposes. You have to be totally responsible why you need to use structs. Perhaps you might need, compatibility with native C libraries, or having some binary memory alignment, or have some “structs” with very precise lifescope.
Elevating the features of structs is a trap that high level programming languages make. Perhaps other programming languages as C# want to make life easier and provide some useful features. But in the end it only makes things complicated, because makes design choices ambiguous.
In practical terms, it’s not about gaining any benefits in speed or efficiency. One user in this forum created some benchmarks to see the difference in speed between classes and structs and the difference is less than 30% (structs are faster).
April 7, 2017 at 8:45 pm #7765The biggest argument not to use structs is the 1kb rule – 90% of heap allocations are garbage by the time another 1kb of data has been allocated, or something.
Even if computers are fast, I don’t think “never use structs” is a good answer though. While I don’t care about how memory is configured most of the time, I care a lot for performance-critical code, and structs give you a lot more control over how your memory is laid out (so do custom allocators, but ew). For doing 3D, for example, you can use structs to make sure that all of your mesh data is contiguous in memory. If there are tens of thousands of entities in your game, you might care about being able to have a fast way to index all of them (to iterate over some subset, or just get a list of all enemies, or whatever). The addition of structs was by far the most compelling reason for me to want to switch to monkey2 instead of staying on the otherwise-fantastic monkey1.
But yeah, unless you *know* that there’s a reason you’re supposed to use a struct, always use classes! You’ll get yourself into a lot less trouble.
April 8, 2017 at 3:17 am #7770I’m really lazy and just use classes for everything!
April 15, 2017 at 1:18 am #7900I learnt a lot from this thread. Thank you.
-
AuthorPosts
You must be logged in to reply to this topic.