Arrays in User-Types
BlitzMax Forums/BlitzMax Programming/Arrays in User-Types
| ||
Im a little puzzled by the use of arrays within usertypes. Heres the code: Type Vec Field x:Float Field y:Float Field z:Float Field w:Float End Type Type DispPos Field d:Vec[255] End Type Type Spline Field dispmap:DispPos[255] Field knot:Vec[255] End Type Global sp:Spline = New Spline My problem comes when trying to access the fields within the arrays - I always get an error informing me the Field or Method is null. this breaks: sp.knot[0].x = 10 sp.dispmap[0].d[0].x = 10 Do the arrays of usertypes need to be 'newed' also? I have tried such an implementation and still couldnt access the fields. Any assistance would be greatly appreciated. |
| ||
The type elements of the array aren't automatically instanced when you create it. You need to add: sp.knot[0] = New Vec Before trying to access the knot vector. |
| ||
So the array that is created, is only an array of references? And each reference has no allocated instance? If it were a builtin type instead what would happen? ie, replace Vec with int. (I just tried that, and builtin types work fine). Is there a way to make a default constructor for this? It seems a little wierd for me to have to new each and every Vec in the array? Certainly a little counter to the way a Type is supposed to be similar to a class. Ie in c++ class Vec { public: float x,y,z; }; class DisPos { Vec d[255]; <-- no allocations needed when DisPos created }; This must also mean things like copying user types is a manual process of implementing a copy routine (ala Blitz3d). I had hoped this would have changed. Adds a large amount of extra code, when basic is all about high level code reduction. |
| ||
Method New() is automatically called when you create a type instance, so you could go: Type DispPos Field d:Vec[255] Method New() For Local:i = 0 until d.length d[i] = New Vec Next EndMethod End Type |
| ||
Yeah, I have done that. Its just that the array declaration isnt consistant across all types, so like I said, its very counter intuitive. Especially when Types are being called Class like. Not a good way to descibe them at all. Also, I cant manage to get this to work at all sp.dispmap[0].d[0].x = 10 I have tried all sorts of different ways to tackle it - newing both the DispPos and Vec types, to no avail. The new method doesnt work either. I must be missing something? Does BlitzMax support multi-level usertypes? |
| ||
finally managed a solution.. this is plain messy and has put me off Blitz again. Type Vec Field x:Float Field y:Float Field z:Float Field w:Float End Type Type DispPos Field d:Vec[255] Method New() For Local i:Int = 0 Until d.length d[i] = New Vec Next EndMethod End Type Type Spline Field dispmap:DispPos[] Field knot:Vec[] Method New() dispmap = New DispPos[255] For Local i:Int = 0 Until dispmap.length dispmap[i] = New DispPos Next knot = New Vec[255] For Local j:Int = 0 Until knot.length knot[j] = New Vec Next EndMethod End Type Global sp:Spline = New Spline This is a very poor way to handle user typed arrays. |
| ||
Additionally, each type will need a respective delete method. Oh well.. ce la vie.. |
| ||
Additionally, each type will need a respective delete method. Oh well.. ce la vie.. No it won't. |
| ||
Seems like BlitzMax works just like C++ in terms of constructing these arrays (assuming your arrays were arrays of pointers). I think this is a reasonable approach for BlitzMax. In general, allocating the memory for you could be bad because the User Type might require construction arguments, or the size of the array might need to be dynamic, or you might want to carefully control when this memory is actually allocated. I can understand wanting to have automatic allocation, but given that User Types are stored by pointer not by value, I think BlitzMax is doing the best it can. That may not change your opinion of it though :-) Ken |
| ||
Id disagree that BlitzMax works like C++, its quite a bit different. Allocating even a struct in C is totally different to a Type in BlitzMax. BlitzMax, as you pointed out, only allocates pointers on the heap, its is expected that the user must provide all allocations - but this is counter intuitive, because BlitzMax uses a smart pointer and garbage collection system, yet it requires the user to alloc? A simple example of why BlitzMax isnt even close to C. struct Point2D { int x, y; } struct Box2D { Point2D tl, br; } In C if I declare an instance of Box2D, the members and the parent is created in its entirity. like so: Box2D abox; In Blitz: Type Point2D Field x:Int Field y:Int End Type Type Box2D Field tl:Point2D Field br:Point2D End Type Now an instance of Box2D: Global abox:Box2D That only creates a pointer to abox, its not even an object, so lets build an object abox = New Box2D Now, all that has been created is an object with two pointers in it. We still need to allocate them. abox.tl = New Point2D abox.br = New Point2D Now Im pretty sure you can see why it is nothing like C++ or even C for that matter. All the inheretence, polymorphism and overriding in the world cant help there. So, the best solution is to implement a New method in every user-defined type. Even in a small project (game) this increases the amount of extra code to write, and certainly I think has also lead to alot of users not being able to follow why they are getting 'null field' errors. It actually irks me a little that people keep calling Type's class like, when quite obviously they are nothing of the sort. And also, the term references for objects, when clearly they are not references (since a reference is an address of an already allocated object) but pointers? I have managed to get what I wanted working in BlitzMax, but I am left wondering why a Basic has so much extra workload especially when they have a memory managed system running? |
| ||
If you mean that Max can't create objects on the stack, then no it can't. Nor can Java. In fact, Max's object model is very similar to Java's (although with the advantage that you can tell when the garbage collector is going to operate). Also, your C++ example isn't memory managed. Even smart pointers in C++ (std::auto_ptr, boost::shared_ptr etc.) can't be used with objects created on the stack. To use memory management you have to create memory on the heap, just like Max, using New (or malloc or whatever). People refer to Types as "classes" because Type definitions work just like C++/Java class definitions and hold all the properties that you'd normally associate with a "class". Likewise, people call Max's references "references" because they are references, not pointers. Pointers in Max are different beasties. An unititialised reference is still a valid reference, it's just a reference to Null. |
| ||
To Grover: BlitzMax types are like C++ classes if (as I mentioned in my post) you contain by pointers rather than by value. To show your example: In C++: struct Point2 { int x,y; }; struct Box2D { Point2 *tl, *br;}; Now it works like BlitzMax (you have to new tl and br). That was the point I was trying to make. I think there are great reasons to build systems like this. It might have been nice if BlitzMax supported containment by value, but it still is powerful, works much like other OO languages, and gives you precise control. Ken |
| ||
teamonkey - yes point taken, Blitz is alot more like Java, hence then OOP in likeness. Technically the example isnt memory managed, however the stack will clean itself up :-) Okay with the pointer/reference thing, I am getting a little confused obviously by what is implemented. When an object is created is it assigned a hash key or some such, which then is used as a lookup to the memory it uses? Hence the need to New all user defined types? And builtin types are assigned directly to an object? The idea that an object and reference are the same thing holds true? I guess my confusion has mainly come from thinking it as a C++ styled implementation - thinking Java has actually made alot more sense. Thanks for the feedback Tigger and teamonkey, my head is actually alot clearer now :-) I apologise for my misunderstanding.. got it quite wrong.. <damn idiot I am>. I have been immersed in Symbian for the last 4 weeks, and I think I was starting to see everything in C++... :-) |