Jump to page: 1 2
Thread overview
Irritating shortcoming with modules and externs
May 17, 2006
Derek Parnell
May 17, 2006
Brad Roberts
May 17, 2006
Derek Parnell
May 17, 2006
Mike Parker
May 17, 2006
Mike Parker
May 20, 2006
Bruno Medeiros
May 21, 2006
Mike Parker
May 16, 2006
Maybe it's not so much a shortcoming as it is just dumb.

Say I want to create a library which has a "pluggable function."  By that I mean that I want the library to reference an external function, defined by the user of the library.  So, in my library module, I write:


module mod;

extern(D) int intFunc();

void spork()
{
    for(int x = intFunc(); x != 0; x = intFunc())
        writefln(x);
}


Something purposeless, but it shows that I want to be able to use this function within this module.

So I compile this to an obj/lib, and create my "host" program which uses the library.  I have this:


module main;

import mod;

int intFunc()
{
    static int[5] ints = [4, 3, 2, 1, 0];
    static int counter = 0;

    counter = (counter + 1) % 5;
    return ints[counter];
}

void main()
{
    spork();
}


The problem: even though I've defined my intFunc() to match the signature to be the same as the signature expected by the library, the linker won't resolve the reference because the function names are mangled with the module names as well.  Meaning that the linker is looking for mod.intFunc, but I've given it main.intFunc.  So I limit the ability to use the library by dictating that the user define the intFunc in a certain module (and it gets worse when multiple source levels come up).

One workaround is to put "extern(C)" before the reference in the library and before the definition, but I don't know if that interferes with the exception handling stuff.

I doubt there's any robust solution to this, but it's frustrating nonetheless.  This "feature" also dictates that import-only files (to go along with closed-source modules) must follow the exact directory structure as the original source so that the mangling matches up, instead of putting all the declarations into one big import file.  A fairly minor inconvenience, but still..


May 17, 2006
On Tue, 16 May 2006 18:22:40 -0400, Jarrett Billingsley wrote:

> Maybe it's not so much a shortcoming as it is just dumb.
> 
> Say I want to create a library which has a "pluggable function."  By that I mean that I want the library to reference an external function, defined by the user of the library.  So, in my library module, I write:
> 
> module mod;
> 
> extern(D) int intFunc();
> 
> void spork()
> {
>     for(int x = intFunc(); x != 0; x = intFunc())
>         writefln(x);
> }
> 
> Something purposeless, but it shows that I want to be able to use this function within this module.
> 
> So I compile this to an obj/lib, and create my "host" program which uses the library.  I have this:
> 
> module main;
> 
> import mod;
> 
> int intFunc()
> {
>     static int[5] ints = [4, 3, 2, 1, 0];
>     static int counter = 0;
> 
>     counter = (counter + 1) % 5;
>     return ints[counter];
> }
> 
> void main()
> {
>     spork();
> }
> 
> The problem: even though I've defined my intFunc() to match the signature to be the same as the signature expected by the library, the linker won't resolve the reference because the function names are mangled with the module names as well.  Meaning that the linker is looking for mod.intFunc, but I've given it main.intFunc.  So I limit the ability to use the library by dictating that the user define the intFunc in a certain module (and it gets worse when multiple source levels come up).
> 
> One workaround is to put "extern(C)" before the reference in the library and before the definition, but I don't know if that interferes with the exception handling stuff.
> 
> I doubt there's any robust solution to this, but it's frustrating nonetheless.

I've hit this limitation a few times too. The method I've used to get around it (which might actually be the D-way) is to isolate the "pluggable" function in its own module.

// --------- mod.d --------
module mod;
import std.stdio;
import oth;
void spork()
{
    for(int x = oth.intFunc(); x != 0; x = oth.intFunc())
        writefln(x);
}
//  -------- end mod.d -----------

// ---------- oth_r.d  ------------
// This is the source code for the library object.
module oth;
int intFunc()
{
    static int[5] ints = [4, 3, 2, 1, 0];
    static int counter = 0;

    counter = (counter + 1) % 5;
    return ints[counter];
}

// --------end of oth_r.d -----------

// ---------- oth_h.d  ------------
// This is the 'header' file for the library object.
module oth;
int intFunc();
// --------end of oth_h.d -----------

// -------- main. d ----------
module main;
import mod;
void main()
{
    mod.spork();
}
// ------- end of main.d -----------


To compile these, first I created the library...

 > copy oth_r.d oth.d /Y
 > build oth -full -Tmylib.lib

Then I created the executable ...

 > copy oth_h.d oth.d /Y
 > build main -full mylib.lib

Then I ran it ...

 >main
  3
  2
  1


-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocracy!"
17/05/2006 10:14:19 AM
May 17, 2006
On Wed, 17 May 2006, Derek Parnell wrote:

> On Tue, 16 May 2006 18:22:40 -0400, Jarrett Billingsley wrote:
> 
> > Say I want to create a library which has a "pluggable function."  By that I mean that I want the library to reference an external function, defined by the user of the library.  So, in my library module, I write:

<snip>

> > The problem: even though I've defined my intFunc() to match the signature to be the same as the signature expected by the library, the linker won't resolve the reference because the function names are mangled with the module names as well.  Meaning that the linker is looking for mod.intFunc, but I've given it main.intFunc.  So I limit the ability to use the library by dictating that the user define the intFunc in a certain module (and it gets worse when multiple source levels come up).
> > 
> > One workaround is to put "extern(C)" before the reference in the library and before the definition, but I don't know if that interferes with the exception handling stuff.
> > 
> > I doubt there's any robust solution to this, but it's frustrating nonetheless.
> 
> I've hit this limitation a few times too. The method I've used to get around it (which might actually be the D-way) is to isolate the "pluggable" function in its own module.

How about moving to a delegate model instead of a direct global symbol model?  It's much more obvious, imho.

Later,
Brad
May 17, 2006
On Tue, 16 May 2006 18:44:39 -0700, Brad Roberts wrote:

> On Wed, 17 May 2006, Derek Parnell wrote:
> 
>> On Tue, 16 May 2006 18:22:40 -0400, Jarrett Billingsley wrote:
>> 
>>> Say I want to create a library which has a "pluggable function."  By that I mean that I want the library to reference an external function, defined by the user of the library.  So, in my library module, I write:
> 
> <snip>
> 
>>> The problem: even though I've defined my intFunc() to match the signature to be the same as the signature expected by the library, the linker won't resolve the reference because the function names are mangled with the module names as well.  Meaning that the linker is looking for mod.intFunc, but I've given it main.intFunc.  So I limit the ability to use the library by dictating that the user define the intFunc in a certain module (and it gets worse when multiple source levels come up).
>>> 
>>> One workaround is to put "extern(C)" before the reference in the library and before the definition, but I don't know if that interferes with the exception handling stuff.
>>> 
>>> I doubt there's any robust solution to this, but it's frustrating nonetheless.
>> 
>> I've hit this limitation a few times too. The method I've used to get around it (which might actually be the D-way) is to isolate the "pluggable" function in its own module.
> 
> How about moving to a delegate model instead of a direct global symbol model?  It's much more obvious, imho.
> 
> Later,
> Brad

That is actually what I did in Build ;-)

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocracy!"
17/05/2006 1:01:44 PM
May 17, 2006
"Brad Roberts" <braddr@puremagic.com> wrote in message news:Pine.LNX.4.64.0605161842050.2422@bellevue.puremagic.com...

> How about moving to a delegate model instead of a direct global symbol model?  It's much more obvious, imho.

That's probably what I'll end up doing, although the function that I wanted to do this with was main (so basically I could "intercept" the call to main in my library, and call the user-defined "LibMain" or something to that effect).  Of course, seeing that D is an OOP language, I might as well make some kind of context class that wraps the entire program, ending you up with something like:

abstract class Context
{
...
}

class MyContext : Context
{
    // override all those stubbed-out methods
}

void main(char[][] args)
{
    MyContext c = new MyContext();
    c.main(args);
}


May 17, 2006
Jarrett Billingsley wrote:
> 
>> How about moving to a delegate model instead of a direct global symbol
>> model?  It's much more obvious, imho.
> 
> That's probably what I'll end up doing, although the function that I wanted to do this with was main (so basically I could "intercept" the call to main in my library, and call the user-defined "LibMain" or something to that effect).  Of course, seeing that D is an OOP language, I might as well make some kind of context class that wraps the entire program, ending you up with something like:
> 
> abstract class Context
> {
> ...
> }
> 
> class MyContext : Context
> {
>     // override all those stubbed-out methods
> }
> 
> void main(char[][] args)
> {
>     MyContext c = new MyContext();
>     c.main(args);
> } 
> 
> 

How about this:

##########################################
// main.d
module main;

abstract class Context
{
public:
	abstract void run(char[][] args);
	
protected:
	this()
	{
		theContext = this;
	}
}

private Context theContext;

void main(char[][] args)
{
	theContext.run(args);
}

===========================================

// mygame.d
module mygame;

import main;

class MyContext : Context
{
public:
	override void run(char[][] args)
	{
		// blah
	}	
}

static this()
{
	new MyContext();
}
#######################################

I did something similar with a GameTask system I was working on. Works like a charm.
May 17, 2006
Mike Parker wrote:

> 
> How about this:
> 
> ##########################################
> // main.d
> module main;
> 
> abstract class Context
> {
> public:
>     abstract void run(char[][] args);
>     protected:
>     this()
>     {
>         theContext = this;
>     }
> }
> 

Of course, there should be a null check in the constructor so that only one primary cotext is ever set:
	if(theConext is null)
		theContext = this;
May 17, 2006
"Mike Parker" <aldacron71@yahoo.com> wrote in message news:e4ed7h$162h$2@digitaldaemon.com...
> Mike Parker wrote:
>
>>
>> How about this:
>>
>> ##########################################
>> // main.d
>> module main;
>>
>> abstract class Context
>> {
>> public:
>>     abstract void run(char[][] args);
>>     protected:
>>     this()
>>     {
>>         theContext = this;
>>     }
>> }
>>
>
> Of course, there should be a null check in the constructor so that only
> one primary cotext is ever set:
> if(theConext is null)
> theContext = this;

Oh that's really cool :)  I might go with that.


May 20, 2006
Jarrett Billingsley wrote:
> "Mike Parker" <aldacron71@yahoo.com> wrote in message news:e4ed7h$162h$2@digitaldaemon.com...
>> Mike Parker wrote:
>>
>>> How about this:
>>>
>>> ##########################################
>>> // main.d
>>> module main;
>>>
>>> abstract class Context
>>> {
>>> public:
>>>     abstract void run(char[][] args);
>>>     protected:
>>>     this()
>>>     {
>>>         theContext = this;
>>>     }
>>> }
>>>
>> Of course, there should be a null check in the constructor so that only one primary cotext is ever set:
>> if(theConext is null)
>> theContext = this;
> 
> Oh that's really cool :)  I might go with that. 
> 
> 

I do something very similar:

  int main(char[][] args)
  {
    // .. proccess args..
    // ..maybe load some libs (like Derelict)..
    App.appmain();
    return 0;
  }

However, in my case, App is a module. If you only have one Context, and it is allways active during the program lifetime, why bother creating a singleton instead of simply using a module?

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 20, 2006

Bruno Medeiros wrote:
> Jarrett Billingsley wrote:
> 
>> "Mike Parker" <aldacron71@yahoo.com> wrote in message news:e4ed7h$162h$2@digitaldaemon.com...
>>
>>> Mike Parker wrote:
>>>
>>>> How about this:
>>>>
>>>> ##########################################
>>>> // main.d
>>>> module main;
>>>>
>>>> abstract class Context
>>>> {
>>>> public:
>>>>     abstract void run(char[][] args);
>>>>     protected:
>>>>     this()
>>>>     {
>>>>         theContext = this;
>>>>     }
>>>> }
>>>>
>>> Of course, there should be a null check in the constructor so that only one primary cotext is ever set:
>>> if(theConext is null)
>>> theContext = this;
>>
>>
>> Oh that's really cool :)  I might go with that.
>>
> 
> I do something very similar:
> 
>   int main(char[][] args)
>   {
>     // .. proccess args..
>     // ..maybe load some libs (like Derelict)..
>     App.appmain();
>     return 0;
>   }
> 
> However, in my case, App is a module. If you only have one Context, and it is allways active during the program lifetime, why bother creating a singleton instead of simply using a module?
> 

The singleton pattern can be useful if you want to pass a reference to the singleton to some function or method later that expects an arbitrary object (maybe implementing a certain interface, for example).  Although, if you only have the one singleton, and there's no possible reason to pass it around, your point is dead-on.

-- Chris Nicholson-Sauls
« First   ‹ Prev
1 2