Multiple function definitions for fake templating

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

Multiple function definitions for fake templating

Postby Zamaster » Mar 28, 2016 8:02

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: 1489
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Multiple function definitions for fake templating

Postby St_W » Mar 28, 2016 12:20

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: 1489
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Multiple function definitions for fake templating

Postby St_W » Mar 28, 2016 12:35

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: 3210
Joined: Jul 28, 2005 14:45
Location: Germany

Re: Multiple function definitions for fake templating

Postby dkl » Mar 28, 2016 15:53

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: 1024
Joined: Jun 20, 2005 21:40
Contact:

Re: Multiple function definitions for fake templating

Postby Zamaster » Mar 28, 2016 16:22

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: 1489
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Multiple function definitions for fake templating

Postby St_W » Mar 28, 2016 20:55

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??

Return to “General”

Who is online

Users browsing this forum: No registered users and 3 guests