Multiple function definitions for fake templating

General FreeBASIC programming questions.
Post Reply
Zamaster
Posts: 1025
Joined: Jun 20, 2005 21:40
Contact:

Multiple function definitions for fake templating

Post by Zamaster »

Hey so I wrote a header with some template macros that generate types/methods based on a data type provided to the macro (standard C style fake templating). What I wasn't paying attention to was that including the header in multiple .bas units would confused the linker since their would be multiple copies of method definitions.

Is there a way I can get the functionality of:
fileA.bas

Code: Select all

#include "templated_thing.bi"

'define it once
define_TemplatedThing(integer)
fileB.bas

Code: Select all

#include "templated_thing.bi"

'now define it again, multiple method definitions so the linker explodes
define_TemplatedThing(integer)
...without having to know beforehand the types I'd like to pass to define_TemplatedThing and having to separate theses known types into a .bi and .bas?
St_W
Posts: 1627
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Multiple function definitions for fake templating

Post by St_W »

It's no problem to do declarations of functions or types multiple times for different modules (actually you have to). Just don't provide multiple implementations in different modules. So you probably need to separate declaration and implementation in your macros. I don't really know what your macros do (or should do), so here's a general example:

a.bas (main module)

Code: Select all

' declaration -------------

type test
	a as Integer
	b as String
End Type

declare function printa(a as test) as integer

' implementation -------------

dim aInstance as test
aInstance.a = 5
aInstance.b = "Hello"

printa(aInstance)

sleep
b.bas

Code: Select all

' declaration -------------

type test
	a as Integer
	b as String
End Type

declare function printa(a as test) as integer

' implementation -------------

function printa(a as test) as integer
	print "a: "; a.a
	print "b: "; a.b
	return a.a
End Function
If you'd like to have your implementation in the .bi file too you have to take care that it's excluded from all but one module. You could use e.g. __FB_MAIN__ (http://freebasic.net/wiki/wikka.php?wakka=KeyPgDdFBMain) to put all the implementations in the main module.
St_W
Posts: 1627
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Multiple function definitions for fake templating

Post by St_W »

Macro Example:

a.bi

Code: Select all

#macro define_TemplatedThing(DATATYPE)

' declaration -------------

type test
	a as DATATYPE
	b as String
End Type

declare function printa(a as test) as DATATYPE

' implementation -------------
' (only in main module)

#ifdef __FB_MAIN__

function printa(a as test) as DATATYPE
	print "a: "; a.a
	print "b: "; a.b
	return a.a
End Function

#endif

#endmacro
a.bas

Code: Select all

#include "a.bi"
define_TemplatedThing(integer)


declare sub doSomething(a as test)

dim aInstance as test
doSomething(aInstance)

sleep
b.bas

Code: Select all

#include "a.bi"
define_TemplatedThing(integer)


Sub doSomething(a as test)
	a.a = 5
	a.b = "Hello"
	printa(a)
End Sub
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: Multiple function definitions for fake templating

Post by dkl »

I've also used separate templates/macros for declaration and implementation:

Code: Select all

#define Array(T) Array__##T

#macro declareArray(T)
	type Array(T)
		p as T ptr
		count as integer
		declare operator let(byref as const Array(T))
		declare destructor()
		declare sub appendCopy(byref as const T)
	end type
#endmacro

#macro implementArray(T)
	operator let(byref rhs as const Array(T))
		...
	end operator

	destructor Array(T)()
		...
	end destructor

	sub Array(T).appendCopy(byref item as const T)
		...
	end sub
#endmacro

'' declare it everywhere you need to use it (typically in multiple .bi header files and .bas modules)
declareArray(integer)

'' provide the needed implementations, but in one .bas module only
implementArray(integer)

dim a as Array(integer)
a.append(123)
I think that's not even "fake" templating, it's the same as C++ templates with explicit instantiations.
Zamaster
Posts: 1025
Joined: Jun 20, 2005 21:40
Contact:

Re: Multiple function definitions for fake templating

Post by Zamaster »

Thanks guys, I had most of that but St_W's solution to use FB_MAIN is close to what I needed. Unfortunately this requires that the code is included at least once in the main module. Is there a way to do it so that its included in exactly ONE of the modules even if not included in FB_MAIN?
St_W
Posts: 1627
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Multiple function definitions for fake templating

Post by St_W »

Zamaster wrote:Thanks guys, I had most of that but St_W's solution to use FB_MAIN is close to what I needed. Unfortunately this requires that the code is included at least once in the main module. Is there a way to do it so that its included in exactly ONE of the modules even if not included in FB_MAIN?
Summary: As the modules are compiled separately I see no way to automatically implement the methods in one of the modules. Just implement the methods explicitly in one of the modules.

Attempt of an explanation:
I guess you are referring to the C++-way of using templates. Unfortunately I don't know a lot about C++, so I'll try explain in a more general manner.
The problem with templates is that in theory the number of possible types for whose the template could be instantiated is infinitely large. And this problem does matter because the compiler does not know the types in all different modules - just of the one it is compiling at a time.

There are (at least) two solutions for this problem:
1. Explicitly tell the compiler which types can be used for template instantiation, so that the set of types is finite. That is exactly what dkl has shown above and what one would call "explicit instantiation". So the template is only allowed to be used with the types for which an explicit instantiation exists in any module (but only once). There's no special compiler support needed for this to work.

2. Provide the template implementation everywhere, where it is used, so that the compiler can instantiate it always for any type it encounters. As the compiler cannot know about other modules this will usually lead to a lot of duplicated instantiations (when we assume that the compiler just instantiates the template for every new type it encounters for every module separately). Duplicate instantiations are a problem, though, so e.g. the linker has to remove the duplicates and thus has to explicitly support templates. I don't know how common C++ toolchains implement this (object files would be blown up if they did it like I assumed) - maybe some C++ expert could tell me? I'd really like to know it.
While the compilation of single modules could be done that way in FB with preprocessor-stuff, I don't see a possibility to eliminate the duplicates during linking or somehow else.

3. maybe other solutions??
Post Reply