Arrays in User-Types

BlitzMax Forums/BlitzMax Programming/Arrays in User-Types

Grover(Posted 2005) [#1]
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.


fredborg(Posted 2005) [#2]
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.


Grover(Posted 2005) [#3]
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.


fredborg(Posted 2005) [#4]
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


Grover(Posted 2005) [#5]
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?


Grover(Posted 2005) [#6]
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.


Grover(Posted 2005) [#7]
Additionally, each type will need a respective delete method. Oh well.. ce la vie..


teamonkey(Posted 2005) [#8]
Additionally, each type will need a respective delete method. Oh well.. ce la vie..

No it won't.


Tiggertooth(Posted 2005) [#9]
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


Grover(Posted 2005) [#10]
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?


teamonkey(Posted 2005) [#11]
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.


Tiggertooth(Posted 2005) [#12]
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


Grover(Posted 2005) [#13]
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++... :-)