Is it possible to do this?

BlitzMax Forums/BlitzMax Beginners Area/Is it possible to do this?

sswift(Posted 2006) [#1]
I want to create a position type:

Type Position
   Field X#, Y#
End Type


And then add it to a sprite type like so:

Type Sprite
???
Field Handle:Position
EndType


I want to then be able to access it like so:

ThisSprite.X =
ThisSprite.Handle.X =

But I don't want the sprite type to say "Extends Position" because that's just silly from an object point of view, and it does not help me if I have a bunch of different types that I want to include as fields in this way.

Obviously I could do this:

Type Sprite
Field X#, Y#
Field Handle:Position
EndType


But that would defeat the purpouse of having a position type that contains X and Y to make things nice and clean.

Of course, this might not be a great idea after all because if I extend position later to have X Y and Z, I obviously don't want to extend the handle in the same way, so mayble I shouldn't do it, but I'm still curious to know if this is possible and how to do it.


Also, is is possible for me to have types in an include file that cannot be accessed outside the include file?

Like something local to the include, but global within the include so all the functions in the include file can access it? Or do I have to use something other than an include to do this?

The reason I want to do that, is because if I were to have a Position type, that could collide with someone else's position type in their main program. But at the same time I would rather not have to have SSS_ on the front of every type and global variable I need in my system to try to ensure no collisions.


Dreamora(Posted 2006) [#2]
No you can't.

Either you use it as a datafield and need to do then

ThisSprite.Handle.X =
(you could as well create methods to access the position)

Or you extend position and can use

ThisSprite.X

There is no way to include a type into another one


If we had multiple inheritance then stuff like this would be no problem at all ...


Bremer(Posted 2006) [#3]
Could it be something like the following that you want to do?

SuperStrict
Global positionList:Tlist = CreateList()
Type TPosition
	Field x:Int
	Field y:Int
	Function create:TPosition( x:Int, y:Int )
		Local tmp:TPosition = New TPosition
		tmp.x = x
		tmp.y = y
		ListAddLast( positionList, tmp )
		Return tmp
	End Function
End Type

Global spriteList:Tlist = CreateList()
Type TSprite
	Field pos:TPosition
	Function create:TSprite( x:Int, y:Int )
		Local tmp:TSprite = New TSprite
		tmp.pos = TPosition.create( x, y )
		ListAddLast( spriteList, tmp )
		Return tmp
	End Function
End Type

Local newSprite:TSprite = TSprite.create( 100, 100 )
Print newSprite.pos.x + "," + newSprite.pos.y

newSprite.pos.x = 200
newSprite.pos.y = 250

Print newSprite.pos.x + "," + newSprite.pos.y



sswift(Posted 2006) [#4]
Zaw:
No. That's complicated. :-)

But I do now notice a problem I had not considered with doing Handle:Position, and that is that I would have to create a position type each time I create a sprite type. So that's no good. That's just going to make a mess of things.


So what about my second question, about keeping types local to the include file? Not possible? I just haven't learned all this OOP stuff yet and I want to code my stuff neatly in a way other people will be confortable using.


Bremer(Posted 2006) [#5]
From what I know, its not possible to keep the types local for the include file. So if you have two types called the same, you are bound to get errors. Probably the only way to do it, is to have a prefix on all functions and types, or have the user not use the same names.


Dreamora(Posted 2006) [#6]
If you want to keep a type local to one file and only accessable through functions within this file, write it behind you went into private state:

 ' some code ...

 private
 type position
   field x:float, y:float
 end type

 ' end of file



Bremer(Posted 2006) [#7]
Would that work even if he have two types called the same, and how would it know which to use?


sswift(Posted 2006) [#8]
Zawran:
I assume it would work like how Global works when you have a local variable in a function with the same name. The local variable takes precedence.


ImaginaryHuman(Posted 2006) [#9]
You could use a temporary handle pointer which is the same as object.handle

then just reference handle.x


Jim Teeuwen(Posted 2006) [#10]
Type Position
	Field X#, Y#
End Type

Type Sprite
	Field Handle:Position
	
	Method New()
		Handle = New Position
	End Method
End Type

Local s:Sprite = New Sprite
Print s.Handle.X


Private
Type Position
	Field X#, Y#
	
	Method New()
		X# = 100
		Y# = 100
	End Method
End Type


This gives a 'Duplicate Identifier' Error when compiling.
So you can't have 2 types with the same name of which 1 is Local and the other is global.


Jim Teeuwen(Posted 2006) [#11]
Personally i'd use wrapping in your case. Allows for manipulation of the Position values before handing it out to whoever requests it. Also it hides the fact you use the position Type. Which in turn allows for future changes without breaking the Sprite class itself.

Type Position
	Field X#, Y#
	
	Method New()
		X = 100
		Y = 100
	End Method
End Type

Type Sprite
	Field _handle:Position
	
	Method New()
		_handle = New Position
	End Method
	
	Method X:Float()
		Return _handle.X
	End Method
	Method Y:Float()
		Return _handle.Y
	End Method
End Type

Local s:Sprite = New Sprite
Print s.X()





maximo(Posted 2006) [#12]
>But I don't want the sprite type to say "Extends Position" because that's just silly from an object point of view, and it does not help me if I have a bunch of different types that I want to include as fields in this way.

You are thinking wrong here Swift ;) Of course it's silly for an object like for example sprite to extend something that is just position. It doesn't make sense. That's why you don't call it Position, you call it 2dObject and give this 2dObject all properties that are needed for it, like x and y.

Then when you make Sprite extend 2dObject it makes sens and also Sprite now has access to x and y and any other field that 2dObject has that is relevant to Sprite.

You just don't create a class/type called position since it's not logical. you create abstract object that has all properties that all of it's children have same.

If you think like that then you don't have the logical problem where some object extends Position since it's unlogical ;)


dmaz(Posted 2006) [#13]
I don't think I really agree 100% with maximo on this. there are many times when I need(want) multiple types inside of other types, I can see where swift is going here.

swift, as been shown above yes you need to "new" position, just like any other type...
Type Position
	Field X:Float
	Field Y:Float
End Type

Type Sprite
	Field X:Float
	Field Y:Float
	Field Handle:Position
	
	Method New()
		Handle = New Position
	End Method
End Type

that's it... now, to not collide with other user's types you need to make a module out of that. it's in the docs and you don't need to install the compiler.. so

you now have
Module sswift.test

Type Position
	Field X:Float
	Field Y:Float
End Type

Type Sprite
	Field X:Float
	Field Y:Float
	Field Handle:Position
	
	Method New()
		Handle = New Position
	End Method
End Type

and the users file would be
Import sswift.test

Type Position
	Field Z
End Type

Local mysprite:Sprite = New Sprite
mysprite.X = 100
mysprite.Handle.X = mysprite.X - 32

Local mysprite2:Sprite = New Sprite
mysprite2.Handle.X = 10

Local mypos:Position = New Position
mypos.Y = 30

Print mysprite.X
Print mysprite.Handle.X
Print mysprite2.Handle.X
Print mypos.Z
'they will get an error on this
'Print mypos.Y

now as you can see the user can declare a usertype position without any problem.... now if they declare a Sprite position then they can't use yours so what you do here is just create a bunch of wrapper functions for your module and expose those so the user doesn't have to worry about your types at all. I don't see a way to block the user from accessing your types but at least they won't collide when scope is taken in account.


sswift(Posted 2006) [#14]
Yeah, but that's a mess. I don't want to have to use new when I declare position. I just want position to be a type of data that's automatically decalred.

If I'm not mistaken, in C, when you have a struct, you can declare variables using that structure, and it will be just as if you had declared an Int, but you can access those fields.

It's not like doing new, because with new, the data could be stored who knows where. If I remember right, in C you can write a struct out to a data file, and read it back in, because the data is of a fixed size. I presume in C++, it pretends the methods simply don't exist when doing this.


It's much too kludgy for me to be bothered with if I have to use New. And there's only a few things I'd really want to use it for, like:

Position, Color, Vector, Normal

If it requires a bunch of crazy stuff to implement, it is simply not worth doing. It's almost not worth doing even if I did have the ability to do C like structs. Then I'd have a bunch of extra structs to worry about. Another level of abscration. And for what? So I can type Color.R = 255 instead of Color_R = 255?

Might make a few function calls here and there a little less messy, but there'd be extra support code attached to them as well. So maybe it was a dumb idea.

There is such a thing as too much object orientation. :-)


Dreamora(Posted 2006) [#15]
You are comparing 2 totally different things.

C:

- Structs are no objects at all
- Structs are not references only

If you use objects in C++ and use pointers, then you must use new as well.

There is the method new you can overwrite (default constructor), then the position etc is initialized when the object (2dsprite for example) is created so you don't need to handle it manually.


Sure the best thing would still be multiple inheritance but we can't do anything about it.


Azathoth(Posted 2006) [#16]
"Yeah, but that's a mess. I don't want to have to use new when I declare position. I just want position to be a type of data that's automatically decalred."

Its just like previous versions of blitz, you can't create instances on the stack like you can in C++.

"It's not like doing new, because with new, the data could be stored who knows where. If I remember right, in C you can write a struct out to a data file, and read it back in, because the data is of a fixed size. I presume in C++, it pretends the methods simply don't exist when doing this."

C++ doesn't use virtual methods by default, this might have something to do with it.