Advanced Topics
Interfacing with other languages
You can use the Import command to add certain non-BlitzMax source files to your projects, and the Extern command to make the functions in those files available to BlitzMax applications.
The currently supported non-BlitzMax source file types are: .c (C); .cpp (C++); .cxx (C++); .m (ObjectiveC); and .s (Assembler).
BlitzMax will use the GNU compiler tools to compile C, C++ and ObjectiveC files, and either the 'fasm' assembler for x86 assembly or GNU assembler for PowerPC assembly.
Here is a simple example of importing C source code into your project and accessing a C function:
//----- file: c_funcs.c -----
int Doubler( int x ){
return x+x;
}
'----- file: app.bmx -----
Import "c_funcs.c"
Extern
Function Doubler( x )
End Extern
Print Doubler(10)
You can also use Import to add a C compiler 'include' directory. To do this, use an import path that ends in "*.h", for example:
Import "include/*.h"
Extern can also be used to work with C++ style objects from within BlitzMax. To do this, simply place a user-defined type declaration within an extern block. For example:
//----- file: mytype.cpp -----
#include <stdio.h>
class MyType{
public:
virtual ~MyType(){}
virtual void Test(){ printf( "Hello World!\n" ); }
};
extern "C"{
MyType *CreateMyType(){
return new MyType;
}
void DestroyMyType( MyType *t ){
delete t;
}
}
'----- File: app.bmx -----
Import "mytype.cpp"
Extern
Type TMyType
Method _pad1() 'padding for virtual destructors
method _pad2()
Method Test()
End Type
Function CreateMyType:TMyType()
Function DestroyMyType( t:TMyType )
End Extern
Local t:TMyType=CreateMyType()
t.Test
DestroyMyType t
Note that there are several limits on the use of extern types:
- Methods declared in an extern type must be declared virtual in the C++ class.
- Objects of extern type cannot be created with New. Instead, such objects must be created by an extern function.
- Extern types can extend other extern types, but can not extend standard BlitzMax types. Similarly, BlitzMax types can not extend extern types.
- Objects of extern type cannot be cast to 'Object'.
Memory management issues
BlitzMax currently uses an optimized form of reference counting to implement memory management.
However, there is one situation where you need to be a bit careful about memory management and that is when you are dealing with cyclic data structures.
A cyclic data structure is a data structure (in BlitzMax, a user defined type) that can potentially 'point to itself'. The most extreme example of a cyclic data structure is something like:
Type TCyclic
Field cycle:TCyclic=Self
End Type
For k=1 To 10
Local cyclic:TCyclic=New TCyclic
GCCollect
Print GCMemAlloced()
Next
If you run this program, you will notice that memory is slowly leaking. This is happening because the reference count for each TCyclic object never reaches 0, thanks to the objects 'cyclic' field.
It is therefore necessary to ensure such cyclic data structures are cleanly handled. This can be achieved by adding a method to 'unlink' any such cycles. For example:
Type TCyclic
Field cycle:TCyclic=Self
Method Remove()
cycle=Null
End Method
End Type
For k=1 To 10
Local cyclic:TCyclic=New TCyclic
GCCollect
Print GCMemAlloced()
cyclic.Remove
Next
In real world use this problem seldom arises, and when it does it's typically when designing container types. Indeed, in this author's opinion, a cyclic data structure is often a sign of poor design - object dependancies should ideally form a cycle-free tree.
If you are at all worried about this, you can easily track memory usage with the GCMemAlloced() function from the BlitzMax runtime library.