Problems with types and imports
BlitzMax Forums/BlitzMax Programming/Problems with types and imports
| ||
I'm trying to reach a type from another type which are all in different bmx files. I'm only using "import" so the types can't really see each other. Here's an example. Main.bmx SuperStrict Import "TGame.bmx" Global MyGame:TGame = New TGame TGame.bmx SuperStrict Import "TGameActions.bmx" Type TGame Global GameActions:TGameActions = New TGameActions Method Update() GameActions.Action(Self) EndMethod EndType And here comes the tricky part! Let's say that TGameActions will alter the game, that means TGameActions has to somehow reach TGame. TGameActions.bmx SuperStrict Type TGameActions Method Action(game:TGame) EndMethod EndType Now... This code won't work, because TGameActions doesn't know what TGame is. And I can't just throw "Import TGame.bmx" into TGameActions.bmx cause that won't compile. Importing both TGame and TGameActions from Main.bmx won't work either. So how will TGameActions alter/reach TGame? |
| ||
What about using "Include" instead on "Import", with Include you just add all the files you want to the main file and you dont have do it for the rest of the files. |
| ||
I'm working on a pretty big game, include is significantly slower. :/ |
| ||
How to you mean slow? Slow to compile? Why does that matter? Anyway, there really is no other way to do this in Bmx. |
| ||
What's a TGame? Why does TGameAction need to know about it? Why not create an abstract class/type with a defined set of methods (or even better an Interface if you are using BlitzMax NG) You can then put this abstract type in a common place, for everywhere to see, and then create a "concrete"/implementation of the actual TGame elsewhere. Type TGame Method doSomething() abstract End Type Type TGameImpl Extends TGame Method doSomething() ... End Method End Type Type TGameActions Method Action(game:TGame) game.doSomething() EndMethod EndType Just a thought.. |
| ||
To extend Brucey's hint: I use this approach: game.base.bmx: Type TGameBase Field propertyWithoutExternalConnection:int = 1 Field name:string Field ... Method GetName:string() return name End Method Method DoSomething() print "am not sure what to do" End Method End Type game.bmx: Import "game.base.bmx" Import "gameactions.bmx" Type TGame extends TGameBase Field gameActions:TGameActions[0] 'override to do something more Method GetName:string() return usingExternal.name + " " + name End Method Method DoSomething() print "now I might know what do" End Method End Type gameactions.bmx Import "game.base.bmx" Type TGameActions Method Action(gameBase:TGameBase) 'if the given "gameBase" is of type "TGame" 'it will output "now I might know what to do" gameBase.DoSomething() End Method End Type Brucey's suggestion is like giving a "definition" of the type somewhere (think this is pretty similar to ".h" files), while mine is saying: give the base type already all information which it can hold without referencing other things. It is then no longer a real "base" type but a "basic" implementation already. So what was I to add to the hint? You are able to _override_ the returned type of a method/function. Base: bla:TMyBaseObject() Implementation: bla:TBaseObject() This eases the process when just accessing the base properties (it will still return "TBaseObject" if the object is of that type). Within my code I then try to use the "lowest possible implementation" to lower the dependencies. Using Brucey's/mine approach you will see a bit more complicated setup (more classes) but compilation times (when doing quick compile) are faster as it is able to reuse already compiled code. BTW: the problem you are facing is called "circular dependencies" and it is up to you to solve them: - via base/implementation - via interfaces (more versatile, like a "programming interface description") - via "include" (as everything is "visible" during the same time) If you want to see more examples: https://github.com/GWRon/TVTower/blob/master/source/game.player.base.bmx https://github.com/GWRon/TVTower/blob/master/source/game.player.bmx ... The interesting part there is, that I use some kind of "singleton" for collections of the objects. Type TPlayerBaseCollection Type TPlayerCollection extends TPlayerBaseCollection And then I have two convenience accessors: function GetPlayerBaseCollection() function GetPlayerCollection() Instead of now defining "global playerCollection:TPlayerCollection" I use the "GetInstance:XXX()" function in the types. Within Base, it returns the base variant - and within the normal implementation it returns the normal variant. The important trick is here: I convert the base instance to a normal instance if it isn't done yet. Of course this trick just is useable if you do not have "base + impVariantA + impVariantB ...". What benefit do I have of this approach? Your code does not have two variables containing potentially 2 different instances of a single type. So this approach makes sure, that as soon as you access "GetPlayerCollection()" all further accesses to "GetPlayerBaseCollection()" are done to a "TPlayerCollection" instance instead of "TPlayerBaseCollection". If you somehow miss to "take over" information (by manually assigning "global playerCollection:TPlayerCollection = new TPlayerCollection") you else would be able to run into trouble. Using that approach in "Method New()" is not possible without trouble, as you then cannot create new instances for temporal storage. So when using Bruceys' TPersistence.mod with such singletons, you _might_ have problems then. This is why I do conversion from "Base" to "implementation" during _request_ not during _initialization_. bye Ron |
| ||
Thank you all! @Brucey I've tried BMX-NG multiple times, but compile times are even worse with it. It takes about 15 seconds to compile Digesteroids for Windows x64 in release mode. While with normal BMax it takes about 3 seconds. And since compile time is exactly what I'm trying to reduce, BMX-NG sadly isn't a solution here. I also had those nasty slowdowns with string splitting some time ago. (which I reported) Plus, I'm a bit of a sucker for Blide heh. :) So I guess I'm just waiting for it to mature a bit. The abstract "base" type method is what I'm doing, but it's always felt like a cheat or hack. But if that's the only way to do it, I guess I'll continue doing it. |
| ||
Hezkore, as you should know, you can speed up compilation times by making use of FRAMEWORK and IMPORT. Also from the main menu, click PROGRAM, BUILD OPTIONS, and make sure that QUICK BUILD is checkmarked. |
| ||
@dw817 Yeah that's what I'm doing. But quick build only works with Import (not include) so that's exactly why I made this post. :) |
| ||
Use the most current BCC / BMK and it should really improve compilation times. bye Ron |
| ||
There is one other way to speed up compile times, split your code into modules. |
| ||
Modules or imports: it is the same, "imports" are more portable than modules (unzip and compile - vs - unzip, copy to mods, compile). bye Ron |
| ||
@Hezkore If compile times are getting too high, you might want to set up a more "unit testable" approach, where a unit is a small chunk of your program that can be tested. Do you really need to compile the entire code + imported modules every time you want to test something new? |