Is it possible to do this?
BlitzMax Forums/BlitzMax Beginners Area/Is it possible to do this?
| ||
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. |
| ||
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 ... |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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 |
| ||
Would that work even if he have two types called the same, and how would it know which to use? |
| ||
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. |
| ||
You could use a temporary handle pointer which is the same as object.handle then just reference handle.x |
| ||
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. |
| ||
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() |
| ||
>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 ;) |
| ||
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. |
| ||
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. :-) |
| ||
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. |
| ||
"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. |