IMPORTS

BlitzMax Forums/BlitzMax Programming/IMPORTS

rdodson41(Posted 2006) [#1]
I REALLY have a problem with the fact that Blitz doesn't allow cyclic Imports as it is impossible to create different files that rely on one another. You can use Include, but then you have to get rid of SuperStrict at the top so you have to change it if you want to Import it in another probject. If TShip needs TMissile and TMissile needs TShip, well then my program is trashed. I think this should not be too hard to implement and would make serious programing in BlitzMax much easier.


H&K(Posted 2006) [#2]
I agree. A soltion that skid said he would back, was to get the compiler to ignore all but the first strict/superstrict.
http://www.blitzbasic.com/Community/posts.php?topic=59760#666272


computercoder(Posted 2006) [#3]
I also agree. Thanks for the link H&K :)


FlameDuck(Posted 2006) [#4]
If TShip needs TMissile and TMissile needs TShip, well then my program is trashed.
Yes. But what's that got to do with cyclic imports?

How would that work anyway? How would you compile something that depends on something else (that isn't compiled, because it's waiting for the other bit to be compiled first) being compiled?


Dreamora(Posted 2006) [#5]
Thats the def of cyclic import FD, because TShip.bmx would import TMissile and vice versa.

Sushimasta: Such stuff can't be solved with "importing". Thats the simple reason modern languages dropped the idea of importing stuff, the use cluster the use or don't use.

That would as well be what I would suggest you to use.
While it sounds obscure and nonsense at first, its quite simple and powerfull:

Create a more or less empty bmx file, that includes different stuff that relys on each other.
That will be one of your "clusters"

In your app you can now import that cluster.
If Quick compile is active, the cluster will only need to be recompiled if one of its own files has changed, otherwise not, which makes it a great thing on larger project!

I often use these technique to encapsulate related stuff into a single file, because the usage of include raises the compile time drastically.


Brucey(Posted 2006) [#6]
If TShip needs TMissile and TMissile needs TShip, well then my program is trashed.


Of course, it might simply be a case of bad design :-)

But if you must reference like that, why not create a base type that they both extend...
eg:
flyingobjectthingy.bmx :

Type TFlyingObjectThingy
  Field x, y

  Method IAmHit(byMissile:TFlyingObjectThingy)
  End Method
End Type


ship.bmx :

import "flyingobjectthingy.bmx"
import "missile.bmx"

Type TShip extends TFlyingObjectThingy
  Field aMissile:TMissile

  Method IAmHit(byMissile:TFlyingObjectThingy)
    Local theMissile:TMissile = TMissile(byMissile)
    Print "Ouch"
  End Method

  Method fireAMissile()
    aMissile = new TMissile
    ....
  End Method
End Type


missile.bmx :

import "flyingobjectthingy.bmx"

Type TMissile extends TFlyingObjectThingy
  ...
  Method HitShip()
    Local theHitShip:TFlyingObjectThingy = someCollisionMethod()

    theHitShip.IAmHit( Self )
  End Method
End Type

The missile doesn't *have* to know what a ship is...

However, Max is a wee bit limited in that it only supports Extend and not Interfaces too, but it's workable...

At the end of the day, sue whatever way works for you...

:o)


H&K(Posted 2006) [#7]
Ok, so the reason sushim wanted it is workroundable. So was the reason I wanteded it.

But I still want it.


Dreamora(Posted 2006) [#8]
Its just not possible.
Not even GCC, the underlaying compiler for the C / C++ part does support it as even C / C++ does not allow cyclic imports!


H&K(Posted 2006) [#9]
No dream.

Cyclic imports were only the reason sushim wanted a change to import.
Im sujesting that even though we dont want cyclic imports we still want a change in the import/include super/superstrict

Specificaly that the compiler shouldnt throw an error when it finds a "Second" strict/superstrict as long as it wouldnt requires a change in the strict setting. (ie if all your includes have the same strict setting at the top)

I agree totaly about not including things from each other, unless very strong compiler directives are used. (But even then I would probably just use "prototypes". Hummm. Does BMax have prototypes?)

But the basic problem of the two types of "Insert", that which Sushim was posting about, is that some people spend ages reming superstrict in and out.


Dreamora(Posted 2006) [#10]
No BM has no prototype or "predeclaration" of any kind :-( All you can do is write an abstract class you extend and use that for the other class which isn't the "clean" way one would want.

On Import the multiple strict stuff isn't a problem as each bmx is compiled on its own without knowledge of other files.

But you are right, it would be usefull if the compiler ignored further strict etc if it was set on the main file.
But it must as well throw an error if the main file did not have a strict but one of the included one had ...

On the other hand: ones know upfront if they are going to import or include a file ... so that single line shouldn't make a problem after all ...


Brucey(Posted 2006) [#11]
... some people spend ages reming superstrict in and out.

Really?
I can't imagine *not* having SuperStrict enabled all the time...

As for the request that the compiler "ignores" second references to an import that it already processed. I doubt it would be very hard to implement, but whether or not it's good to have is another question.. :-)


H&K(Posted 2006) [#12]
I can't imagine *not* having SuperStrict enabled all the time


Neither can I. You spend the time reming the superstricts in and out of the Include files so that you can compile them serperatly, and together respectivly


rdodson41(Posted 2006) [#13]
What I did temporarily was just remove the SuperStricts in all the other files and fortunatly there was only 5 or 6 classes, but imagine on a larger project where you have like 40 files, it would be a load of stupid work.


But if you must reference like that, why not create a base type that they both extend...



Thats not a bad idea, but my ships are triangles and missiles are dots, so I'm not sure how I can make an abtract class that can handle any kind of collision, but anyway there are other dependencies. Such as each TPlayer has references to the TShip and TMissiles that belong to it. So I'm still at my original problem.


Yes. But what's that got to do with cyclic imports?

How would that work anyway? How would you compile something that depends on something else (that isn't compiled, because it's waiting for the other bit to be compiled first) being compiled?




Its just not possible.
Not even GCC, the underlaying compiler for the C / C++ part does support it as even C / C++ does not allow cyclic imports!



Java has this capability and I use it all the time. In Java class Ship could import class Missile and class Missile could import class Ship.

I think way imports work should be changed so that cyclic imports are available. If I'm right in what I thought .i files are for, couldn't you just generate the .i files for any .bmx file being used in compilation, then, since each .bmx file has the information about every other .bmx file, you can run the compiler proper on the .bmx files to generate the respective assembly files. And there you go. TShip knows about TMissile and TMissile knows about TShip.


rdodson41(Posted 2006) [#14]
And by the way Dreamora...


Not even GCC, the underlaying compiler for the C / C++ part does support it as even C / C++ does not allow cyclic imports!



You can do cyclic imports in C. It will crash the preproccessor when memory runs out unless you control it with conditional inclusion but you can still do it.

program.c:

#include "header.h"



header.h:

#include "program.c"



kfprimm(Posted 2006) [#15]
nvm


Dreamora(Posted 2006) [#16]
Not sure if thats a cyclic import as one is a c and the other a header.
Cyclic import would happen with 2 headers that import each other and that should result in a compiler error in C as well ...


H&K(Posted 2006) [#17]
Im not sure if it is cyclic imports either, because the only times Ive seen what "Look" like cyclic, in turns out that the compiler directives include each include only once.
#If defined DoneThis
#Define Donethis
..etc
...
#Endif
Even if cyclic imports dont work, can we still agree on the change to Strict, so its ignored if it is invoked again either in the main file or the includes (Depending on how you want to look at it)?

Edit: I dont know anything on using import properly, so If anyone know a link to a tut. Specificly designed for someone who doesnt what to know, but should really
The way I understand it at the moment is that when its an import its sort of like a "Forth" Dictionary, and when its in an include is like a "Forth" Listing. In that once its in the imports, its part of the language. (But that bit is obvious isnt it?)


rdodson41(Posted 2006) [#18]
Its a cyclic import cause the two files will keep importing eachother until theres a memory leak. Usually the preprocessor will report an error after some large number of inclusions. You can even include the same file over and over again:

program.c:

#include "program.c"


When run with the GNU C Preprocessor on my Mac it includes itself about 200 times before it reports the error "program.c:1:21: error: #include nested too deeply" and aborts.

Luckily you can use this to your advantage by using conditional includes and the traditional defines at the top of a header:

program.c:

#include "ship.h"
#include "missile.h"

/* ... */


ship.h:

#ifndef SHIP_H
#define SHIP_H

#include "missile.h"

struct ship
{
    float x;
    float y;
    struct missile m;
    /* ... */
};

#endif


missile.h:

#ifndef MISSILE_H
#define MISSILE_H

#include "ship.h"

struct missile
{
    float x;
    float y;
    struct ship parent_ship;
    /* ... */
};

#endif


This would work as each header is only included once but theres no cyclic include and error because both have information about ships and missiles.

So basically, cyclic imports with out memory leaks and errors are possible in Java and to an equivalent effect in C/C++, but in BlitzMax, you can't.

My suggestion would be this: When compiling a .bmx file, scan the file and create a header like file ( .i file I think ) that contains information about Types, Functions, other Imports, variables, etc. from that current .bmx file. Then the source .bmx file is run through the actual compiler. When you encounter an Import statement, find the file thats being imported and check if it already has an up-to-date .i file created. If not, create it in the same way the original was created, and if it needs to import the original file, THE HEADER IS ALREADY THERE. And viola! TShips can know about TMissiles and TMissiles can know about TShips and everybody is happy because the project works AND is organized into sepparate, managable files.

For those who like to read psuedocode:

compile("program.bmx")

function compile(file)
    if header doesn't exists for file then
        generate header for file
    end if

    parse(file)
end function

function parse(file)
    /* ... */

    if statement = import statement then
        if header doesn't exist for imported file then
            generate header for imported file
        end if

        import(imported file)
    end if

    /* ... */
end function

function import(file)
    /* ... */
end function


The header or .i file would look something like this:

type TShip extends TObject
    field x:float
    field y:float
    /* ... */

    method firemissile()
    /* ... */
end type


If I ever design a programming language, it will have this feature.


Dreamora(Posted 2006) [#19]
Include: Copies the content of the file into the spot the include command is. For that reason, multiple strict break logically

Import: The bmx/c/cpp/asm is compiled first. The resulting object file is then linked to the current source when it is compiled. Due to that, declarations etc within the other file can't know of what is in the current file as they get compiled before the current file is compiled. (the current thought knows of defined stuff that is accessable from outside as the other is already compiled when they merge so it can look whats present there)


Curtastic(Posted 2006) [#20]
I thought this topic was going to be on some kind of Insane Multiplayer Online RTS


rdodson41(Posted 2006) [#21]
Dreamora, I know the difference between Include and Import and I know how the current Import works. But what I'm saying is that BEFORE actually parsing and generating assembly code, the compiler could generate a header file based on definitions in the source file. That way, any file has access to the information in any other file, therefore making better structured and better organized programs.


rdodson41(Posted 2006) [#22]

I thought this topic was going to be on some kind of Insane Multiplayer Online RTS



lol. That would be a cool game to play.

But anyway would this really be that hard to implement in a future version of BlitzMax because right now I have to keep unorganized projects because the Import command is disfunctional. Will we see a change in the future or not?


Dreamora(Posted 2006) [#23]
Sushimasta: This would totally break the use of import. Import is meant to seperate the code into own "worlds" and does not know of "higher level" stuff to which it is linked at a later date. This is very elemental and important for modular OO design, that you can fully encapsulate code and guarantee that its variable scopes do not intersect.

Your idea would totally break that as it would break the guaranteed scopes to retrieve data for the outer world it is not meant to even know. (wouldn't even want to know how you plan to make precompiled modules work with your approach)

The only thing currently missing in BM are prototypes, that would remove any need of cyclic import (thats the way C++ gets around the problem as well).
that part sadly has to be faked through abstract classes with a later implementation ...


H&K(Posted 2006) [#24]
I would still like "inludes" to be able to cope with a dublicate strict. Whatever codeing rules that breaks.


Dreamora(Posted 2006) [#25]
It doesn't break anything, it just shows missing skill on the user if strict is on more than 1 file (-> forgot to first design the source and then write it)


H&K(Posted 2006) [#26]
No dream it doesnt. If you read the reason I want it, in the link on the second post in this tread. Its not a big thing to ask for.


Dreamora(Posted 2006) [#27]
I know.
But there is still the problem with "what do if the main file had a lower strict level than an included one"?
In that case the same thing as today would happen and people would start bugging again, not?


H&K(Posted 2006) [#28]
I agree, but the other (better) option would be compiler diectives
?If not defined Strict
?define Strict
Superstrict
?
Doesnt seem likly, so ....

Edit: that code thing makes no sence at all. but you know what im trying to say


rdodson41(Posted 2006) [#29]
On the topic of Strictness I think even having Strict is a bad idea. The language should just be what it is ( preferably with a strict syntax where there is no ambiguity ), but having different levels of syntax strictness is crazy.

On the topic of imports, I have actually rethought what I wanted. I would actually prefer a grouping concept such as a module that acts like a package in Java. So you have something like this:

Package rds.util.Hashtable

Import brl.blitz
...

Type Hashtable
    ...
EndType


Because what you want is everything available in your project to be available to the rest of a project because it WOULD be stupid to have a TShip in one project reference and TMissile in another project. But in my game, these classes need to reference eachother. So they would be put in the same package and any file would automaticaly know about anything else in the package. So that eliminates the need for cyclic Imports and I think then everyone is happy. Because in the real world, classes aren't always going to be standalone. They need to work together. So it would seem counter-intuitive to only be able to have classes work together if they are all in the same long file or included messily together. Ya see what I mean I hope?


Dreamora(Posted 2006) [#30]
Sushi: Yes different levels of strict are a bad idea, especially as the code works elementally different if no strict is used (variable scopes don't exist for example)

The package idea would be the best. Thats why I am actually doing throug the bmx file I import which itself only includes other files. This file is then used by my project as a single package (which then only needs to be rebuilt if any of the included files changed) with its local knowledge of the others, but without giving out such knowledge to the outer world.


H&K(Posted 2006) [#31]
No-one wants different levels of strict in a program. Sushi just wants to get rid of strict altogether, and I just want the compiler to ignore and stricts it finds other than the first.

What Sushi has just described is simple project managemnet.(Unless Ive missed something, packages are sub-projects)


rdodson41(Posted 2006) [#32]
A package can be whatever you want. In actuallity you should combine the Package idea with the Module idea so that there is a uniform way of organizing code. So basically you have the languages modules (brl.blitz, brl.max2d...), your own modules (rds.tools, rds.coolstuff...) and your project modules (rds.CoolGame, rds.MapEditor...). So my game would be in rds.Spacewar module, and would have access to all files in the Packages (Spacewar.bmx, Ship.bmx, Missile.bmx...) and THEN all the classes in a module will be able to successfully (and without cyclic imports or messy includes) access eachother and create a more powerful and more organized program.