Include or Import?

BlitzMax Forums/BlitzMax Beginners Area/Include or Import?

QuickSilva(Posted 2008) [#1]
Could someone please explain the difference between the Import command and the Include command. Is Import just for Importing modules or can it be used to include other files too, in place of include?

I`m a little confused. Any help would be great.

Jason.


Brucey(Posted 2008) [#2]
Include works as if the files you are including were part of the same, very large file. That is, when you compile, it replaces the Include line with the contents of the file you are including.

Importing on the otherhand keeps the source separate at compile time, instead linking each compiled section together. This has benefits in that depending on which files you've made changes to, only the changes need to be re-compiled, and therefore speeding up the compile time significantly.
One issue with Importing is its inability to support cyclic imports, where A imports B imports A. You might find you need to do that if a Type in A referred to a Type in B, and vice versa. However, more often than not, a change to your code logic can get around that problem.

I use imports exclusively :-)


QuickSilva(Posted 2008) [#3]
Cheers that make much more sense now :)

Jason.


MGE(Posted 2008) [#4]
Thanks Brucey. So..... if you use import, it's up to you to compile ahead of time any changes because import does pre-compile. Right?


Macguffin(Posted 2008) [#5]
Anyone know how else Import is different from Include? When I did a quick experiment with it this morning, I started getting compile errors in some outside code. Things like duplicate local variables and missing type references... but this stuff didn't show up when it was an include. I'm guessing that there's some sort of different set of compile time dependencies that are in play?


Brucey(Posted 2008) [#6]
Remember that include effectively replaces the Include line with the source from the included file. Therefore, all those files are basically really one big file. That means that any included files that depend on Types/Functions etc in other files don't really depend on the other files, since it is just one *big* file split into parts.

However, since Imported files are compiled separately, you cannot have file A importing B when you have B depending on code in type A. You will get compilation errors.

You can always create files for Globals if you need them. Say, call it C, which both A and B can import.

Using Import is all down to the design of your code. If you build it modularly then you won't have a problem. If however, everything depends on everything else, then you might find difficulty using Imports.
A good design can avoid that problem.

HTH


Yan(Posted 2008) [#7]
So..... if you use import, it's up to you to compile ahead of time any changes because import does pre-compile. Right?
No, the imported code will be recompiled by BMK if it has changed (source timestamp later than object timestamp*).

This is only relevant for normal code if 'QuickBuild' is enabled, otherwise the imported code will *always* be recompiled before being linked.


*This is determined differently if you're using the speed-up hack, I believe.


Walla(Posted 2012) [#8]
I have a big stegosaurus of code from a little project I began some years ago and I wanted to go through and refactor (if that is the right term) into import-able and ideally reusable) sections - something like one source file per type or suchlike.

I am thinking that this should work in principle, but may be in reality a sticky process - I tried it not long ago and found lots of errors popping up where I was doing stuff in the wrong places in the monolithc tract of code I have. I decided to accept the malpractise as a tradeoff against actually making progress on my little project, but it is a real bugbear in the back of my mind and I'd like to attack it.

I am trying to glean as much as I can from the boards on this topic, and I'd love to see any other really useful threads if you guys have anything helpful to share with me. :)

Many thanks!

cw


ima747(Posted 2012) [#9]
When writing new code write with imports, they help keep you in line (you can't do recursive things that make things a nightmare to deal with because it just won't let you compile it... same reason to use at least strict mode if not superstrict...)

Relating to old code and transitioning do one segment at a time. When inevitably something blows up you will know the last thing you did that caused that to happen and that gives you a starting point to look at for solving it.

For using imports try to think from top down. What's the *most* generic thing (like an "thing" in your game, could be anything, but all "things" contain maybe a graphic and an x/y position and a method to draw the graphic at that position...), make that a type, stick that in a file. Now you want to make something more specific, like say a kind of object for static objects (trees, trash cans, just dumb stuff that sits in one place). Subclass your first type in a new file, import the previous file at the top, add whatever needs adding. Now you want to make smarted objects, maybe stuff that has a simple animation so it needs a new draw method and a frame counter. Subclass the last one, import that at the top. Repeat. You want one thing to always be an extension of something else so you can follow one single path back. That way when you get to more complex things, like say a guy which has a field for a "weapon", you just import the guy super class at the top for the guy, and import the weapon class as well since the guy will need to know about weapons to hold one...

The more you break things up the less the compiler has to do when you compile, and it becomes far easier to track down the root of your problems. What if a bunch of objects are being drawn upside down? they all share the same draw method... problem is probably in there. Additionally you have to do a LOT less scrolling to find things in your code, the time this wastes is amazing (you have to think about what you want, try to remember where that is, go look for it, finally found it? ok, why were you looking for it in the first place... oh right, to compare to the first thing you were looking at... crap where was that? scroll... OR tab 1 centered on code snippet 1, tab 2 centered on snippet 2 in another file, flip flip, done.)

This doesn't even touch on recycling things... subclassed generics are great for starting new projects. Just copy the files, import what you need to get started with, you have half functioning objects already, just add some logic and some graphics and you've got a game... I use "just" quite loosely there obviously...

Last edited 2012


Walla(Posted 2012) [#10]
hey ima, thanks for the clarification, I will begin my odyssey this weekend and opst back with soe progress or if I hit any bumps! :D


Walla(Posted 2012) [#11]
Well, the first few things went quite ok, I was able to disconnect the types and import the requred bits to each one, and then they be imported into the main file - lovely!

Now I'm starting to get stuck as things get a bit more complex.

What I will do is carry on and pull out all the stuff I can, but for the tricky ones I may need some assistance.

I also am quite sure that my non-existing idea of code design has made a bit of a mess of some things - I'm having a hard time deciding where certain stuff should actually live.

examples - I have a bunch of globals in my game type for handing the viewport offset for relative positioning etc. and they are popping up in types which have a draw method which puts them into screen space.
My first instinct is to pass in the offset as a function parameter, but I'm not sure if I should possibly put all that stuff in my misc namespace and import that into anything which needs it.

If anyone has good practise code examples for games I'd be more than slightly interested to have a look-see. Its all very hobbyish for me and I'm keen to hae a tidy up and get more productive rather than just tinkering.

I'm quite happy with the syntax and other aspects - but it's this really meaty chunk of learning about wat the hell I am even tryig to do which is hard work! :)


ima747(Posted 2012) [#12]
screen offsets are one of those sticky things where ease of use can override optimal code...

If it's possible then passing the offsets into applicable methods is generally optimal as then your code can be re-used in another program later, just change the offset as needed to make it work, yay. However passing offsets down through nested update routines can get REALLY tedious when you only need the value once at the very last step. re-thinking your code flow is usually too big of a headache at this point. The boogie man of the global comes in to play... Personally in cases like that I tend to attempt to at least sweep my globals into types... so I may have 1 global "display" type which contains things like offsets, screen rotations, display size, whatever else may be applicable. Still accessing a global (boo) but at least that display type can be adjusted in one place and re-used in other apps (modified as needed) etc.


Walla(Posted 2012) [#13]
Those approaches sound similar to what I am doing, which is a relief.

I'm also thinking my base entity type is a bit heavy, but I think I will ignore that until I start a new project.

I have to fix so much stuff - I have for some reason got a large collision check method in the entity type wil tons of checking and actually then doing the stuff. I am moving the collision response and so on into each derived type, and abstracting the collision method in the base type.

I have no idea what I was thinking in the old days, or whether wat I am doing is actually better, but it feels more sensble to do collision that way. :)


matibee(Posted 2012) [#14]
While keeping away from globals is a good thing, you can still use them (kind of) sensibly through manager types. (I'm crap at examples..)

So, for a bunch of values relating to the graphics system that I would like lots of sections of code to work with, stick them in one type (in one file)..

Type TGraphicsUtils
  Global clearcolor:Int[] = [0,0,0]
  Global waveylinecolor:Int[] = [128,0,0]

  Function SetWaveyLineColor()
    SetColor waveylinecolor[0],waveylinecolor[1],waveylinecolor[2]
  end function 

  'etc
End Type


Now you can include that file in as many other files as you wish, giving each one access to its values and functions ie: TGraphicsUtils.SetWaveyLineColor(). If that gets too much of a mouthful, write a simple wrapper function and stick that in the TGraphicsUtils file..

Function SetWaveyLineColor()
  TGraphicsUtils.SetWaveyLineColor()
end function 


Of course, you have to weigh up code maintenance with ease of use.

You'll probably benefit from some sort of read/write standard too so that code that accesses TGraphicsUtils knows its place. Some people prefer to denote type fields as "not to be touched by outside code" by prefixing them with an underscore..

Type a
  Global _b:Int
  Global name:String


Which would mean:

a._b = 2 ' bad do not write to this variable!

a.name = "bob" ' allowed


Mostly I prefer not to write directly to ANY fields and provide access methods instead..
Function Setb( a:Int )
  _b = a
end function 


That way, I can always tell how to correctly interact with a type by its methods and functions.

So, stick your "globals" in sensible manager types and be very disciplined about how and when you set their values. But letting other parts of your code get access to those values is (for the example above) as simple as:

Include "GraphicsUtils.bmx"



Walla(Posted 2012) [#15]
Just to chip back in -

It is going quite well, I am now at mosty no errors - the gnarliest bits of code logic have sorted themselves out and I am back at the point ot getting the functionality back - then it will be much easier to move forward!

Thanks for all your help!


Walla(Posted 2012) [#16]
It's all up and running now, more or less, with the bonus of quite a bit of tidying up.

One thing I am contemplating is how to handle collisions now.

I am thinking that each type of entity should have some kind of number assigned to them, and I can just pass the generic entity into the different subclasses' collision methods, so that they can do the appropriate behaviours.

hmm, maybe this is not the best way - if anyone has good ideas I'd be pleased to hear more info!