Re: writeln if not empty

2014-03-10 Thread Timothee Cour
On Mon, Mar 10, 2014 at 9:14 PM, Jonathan M Davis wrote:

> On Monday, March 10, 2014 21:50:25 Nick Sabalausky wrote:
> > On 3/10/2014 9:24 PM, Timothee Cour wrote:
> > > Is there a way to do the following lazily:
> > >
> > > writelnIfNotEmpty(T)(T a){
> > > auto b=text(a);
> > > if(b.length)
> > >
> > >writeln(b);
> > >
> > > }
> > >
> > > ie, without using std.conv.text (which needlessly computes an
> intermediate
> > > string, which could be quite large) or launching a separate process ?
> > >
> > > writelnIfNotEmpty(""); //doesn't print new line
> > > writelnIfNotEmpty("a"); //prints "a\n"
> >
> > Sounds like what you need is a version of to!string() or text() that
> > takes an output sink. Taking a look at std.conv, I'm kinda surprised I
> > don't see one :/
>
> std.format.formattedWrite will do the equivalent of writef to an output
> range,
> though I'm not sure that that will really do what the OP wants, since it
> would
> still have to write the result to an output range even if it were empty,
> and
> odds are that the output range would be something on the heap anyway (e.g.
> Appender is technically on the stack, but it's contents are on the heap),
> making it so that it probably doesn't help much in this case.
>
> Though to be honest, I'm not quite sure why writelnIfNotEmpty would be very
> useful unless what's being passed in would result in the empty string, and
> I
> would think that that would almost always be detectable (the one exception
> being user-defined types whose toString results in an empty string).
> Something
> as simple as
>
> void writelnIfNotEmpty(T)(T a)
> {
> static if(isInputRange!T)
> {
> if(!a.empty)
> writeln(a);
> }
> else
> writeln(a);
> }
>
> would then cover most cases - the one exception being toStrings which can
> result in empty. And if that's a concern, then something like
>
> else static if(is(T == struct) || is(T == class))
> {
> auto b = to!string(a);
> if(b.length)
> writeln(b);
> }
>
> should take care of the toString case. It doesn't avoid creating an
> intermediate string, but unless the toString takes an output range, it's
> always going to allocate anyway, and if it does take an output range, once
> again, you'd need one which somehow avoided allocating altogether, which
> isn't
> particularly likely.
>
> Alternatively, you could just assume that no toString will result in the
> empty
> string, as it's probably pretty rare that it would, but I'm not sure that
> that
> would actually save you any overhead except in the case where the toString
> takes an output range (since otherwise, it'll allocate a new string
> regardless), but toStrings which take output ranges are fairly uncommon at
> this point.
>
> - Jonathan M Davis
>


Thanks,
that indeed works in many cases but there are still others (eg what if
empty() prints, say in debug mode: writelnIfNotEmpty would not print the
debug information even though writeln() would execute that debug code and
print something).

I was wondering whether there would be a robust way that would check
whether anything was written to stdout (eg via accessing raw file pointer/C
lib), eg something like that :

void writelnIfNotEmpty(T)(T a){
auto file_pos=get_filepos(stdin);
write(a);
if(get_filepos(stdin)!=file_pos)
writeln;
}


Re: writeln if not empty

2014-03-10 Thread Jonathan M Davis
On Monday, March 10, 2014 21:50:25 Nick Sabalausky wrote:
> On 3/10/2014 9:24 PM, Timothee Cour wrote:
> > Is there a way to do the following lazily:
> > 
> > writelnIfNotEmpty(T)(T a){
> > auto b=text(a);
> > if(b.length)
> > 
> >writeln(b);
> > 
> > }
> > 
> > ie, without using std.conv.text (which needlessly computes an intermediate
> > string, which could be quite large) or launching a separate process ?
> > 
> > writelnIfNotEmpty(""); //doesn't print new line
> > writelnIfNotEmpty("a"); //prints "a\n"
> 
> Sounds like what you need is a version of to!string() or text() that
> takes an output sink. Taking a look at std.conv, I'm kinda surprised I
> don't see one :/

std.format.formattedWrite will do the equivalent of writef to an output range, 
though I'm not sure that that will really do what the OP wants, since it would 
still have to write the result to an output range even if it were empty, and 
odds are that the output range would be something on the heap anyway (e.g. 
Appender is technically on the stack, but it's contents are on the heap), 
making it so that it probably doesn't help much in this case.

Though to be honest, I'm not quite sure why writelnIfNotEmpty would be very 
useful unless what's being passed in would result in the empty string, and I 
would think that that would almost always be detectable (the one exception 
being user-defined types whose toString results in an empty string). Something 
as simple as

void writelnIfNotEmpty(T)(T a)
{
static if(isInputRange!T)
{
if(!a.empty)
writeln(a);
}
else
writeln(a);
}

would then cover most cases - the one exception being toStrings which can 
result in empty. And if that's a concern, then something like

else static if(is(T == struct) || is(T == class))
{
auto b = to!string(a);
if(b.length)
writeln(b);
}

should take care of the toString case. It doesn't avoid creating an 
intermediate string, but unless the toString takes an output range, it's 
always going to allocate anyway, and if it does take an output range, once 
again, you'd need one which somehow avoided allocating altogether, which isn't 
particularly likely.

Alternatively, you could just assume that no toString will result in the empty 
string, as it's probably pretty rare that it would, but I'm not sure that that 
would actually save you any overhead except in the case where the toString 
takes an output range (since otherwise, it'll allocate a new string 
regardless), but toStrings which take output ranges are fairly uncommon at 
this point.

- Jonathan M Davis


Re: writeln if not empty

2014-03-10 Thread Nick Sabalausky

On 3/10/2014 9:24 PM, Timothee Cour wrote:

Is there a way to do the following lazily:

writelnIfNotEmpty(T)(T a){
auto b=text(a);
if(b.length)
   writeln(b);
}

ie, without using std.conv.text (which needlessly computes an intermediate
string, which could be quite large) or launching a separate process ?

writelnIfNotEmpty(""); //doesn't print new line
writelnIfNotEmpty("a"); //prints "a\n"



Sounds like what you need is a version of to!string() or text() that 
takes an output sink. Taking a look at std.conv, I'm kinda surprised I 
don't see one :/




writeln if not empty

2014-03-10 Thread Timothee Cour
Is there a way to do the following lazily:

writelnIfNotEmpty(T)(T a){
auto b=text(a);
if(b.length)
  writeln(b);
}

ie, without using std.conv.text (which needlessly computes an intermediate
string, which could be quite large) or launching a separate process ?

writelnIfNotEmpty(""); //doesn't print new line
writelnIfNotEmpty("a"); //prints "a\n"


ambiguous definition

2014-03-10 Thread Pasqui23

Hi.
I was editing std.string,but when I tried to compile it it game
me this error:

string.d(368): Error: template std.string.indexOf cannot deduce
function from argument types !()(string, dchar), candidates are:
string.d(306):std.string.indexOf(S)(S s, ElementType!S c,
CaseSensitive cs = CaseSensitive.yes) if (isSomeString!S ||
isInputRange!S && isSomeChar!(ElementType!S))
string.d(404):std.string.indexOf(S)(S s, ElementType!S c,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isInputRange!S && isSomeChar!(ElementType!S))
string.d(468):std.string.indexOf(S1, S2)(S1 s, S2 sub,
CaseSensitive cs = CaseSensitive.yes) if
(is(Unqual!(ElementType!S1) == Unqual!(ElementType!S2)) &&
(isSomeString!S1 || isSomeChar!(ElementType!S1) &&
isForwardRange!S1 && isForwardRange!S2))
string.d(551):std.string.indexOf(S1, S2)(S1 s, S2 sub,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isForwardRange!S1 && isForwardRange!S2 &&
isSomeChar!(ElementType!S1))
string.d(369): Error: template std.string.indexOf cannot deduce
function from argument types !()(string, dchar), candidates are:
string.d(306):std.string.indexOf(S)(S s, ElementType!S c,
CaseSensitive cs = CaseSensitive.yes) if (isSomeString!S ||
isInputRange!S && isSomeChar!(ElementType!S))
string.d(404):std.string.indexOf(S)(S s, ElementType!S c,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isInputRange!S && isSomeChar!(ElementType!S))
string.d(468):std.string.indexOf(S1, S2)(S1 s, S2 sub,
CaseSensitive cs = CaseSensitive.yes) if
(is(Unqual!(ElementType!S1) == Unqual!(ElementType!S2)) &&
(isSomeString!S1 || isSomeChar!(ElementType!S1) &&
isForwardRange!S1 && isForwardRange!S2))
string.d(551):std.string.indexOf(S1, S2)(S1 s, S2 sub,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isForwardRange!S1 && isForwardRange!S2 &&
isSomeChar!(ElementType!S1))
string.d(370): Error: template std.string.indexOf cannot deduce
function from argument types !()(string, dchar), candidates are:
string.d(306):std.string.indexOf(S)(S s, ElementType!S c,
CaseSensitive cs = CaseSensitive.yes) if (isSomeString!S ||
isInputRange!S && isSomeChar!(ElementType!S))
string.d(404):std.string.indexOf(S)(S s, ElementType!S c,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isInputRange!S && isSomeChar!(ElementType!S))
string.d(468):std.string.indexOf(S1, S2)(S1 s, S2 sub,
CaseSensitive cs = CaseSensitive.yes) if
(is(Unqual!(ElementType!S1) == Unqual!(ElementType!S2)) &&
(isSomeString!S1 || isSomeChar!(ElementType!S1) &&
isForwardRange!S1 && isForwardRange!S2))
string.d(551):std.string.indexOf(S1, S2)(S1 s, S2 sub,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isForwardRange!S1 && isForwardRange!S2 &&
isSomeChar!(ElementType!S1))
string.d(371): Error: template std.string.indexOf cannot deduce
function from argument types !()(string, dchar), candidates are:
string.d(306):std.string.indexOf(S)(S s, ElementType!S c,
CaseSensitive cs = CaseSensitive.yes) if (isSomeString!S ||
isInputRange!S && isSomeChar!(ElementType!S))
string.d(404):std.string.indexOf(S)(S s, ElementType!S c,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isInputRange!S && isSomeChar!(ElementType!S))
string.d(468):std.string.indexOf(S1, S2)(S1 s, S2 sub,
CaseSensitive cs = CaseSensitive.yes) if
(is(Unqual!(ElementType!S1) == Unqual!(ElementType!S2)) &&
(isSomeString!S1 || isSomeChar!(ElementType!S1) &&
isForwardRange!S1 && isForwardRange!S2))
string.d(551):std.string.indexOf(S1, S2)(S1 s, S2 sub,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isForwardRange!S1 && isForwardRange!S2 &&
isSomeChar!(ElementType!S1))
string.d(553): Error: undefined identifier S
string.d(373): Error: template std.string.indexOf cannot deduce
function from argument types !()(string, dchar, CaseSensitive),
candidates are:
string.d(306):std.string.indexOf(S)(S s, ElementType!S c,
CaseSensitive cs = CaseSensitive.yes) if (isSomeString!S ||
isInputRange!S && isSomeChar!(ElementType!S))
string.d(404):std.string.indexOf(S)(S s, ElementType!S c,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isInputRange!S && isSomeChar!(ElementType!S))
string.d(468):std.string.indexOf(S1, S2)(S1 s, S2 sub,
CaseSensitive cs = CaseSensitive.yes) if
(is(Unqual!(ElementType!S1) == Unqual!(ElementType!S2)) &&
(isSomeString!S1 || isSomeChar!(ElementType!S1) &&
isForwardRange!S1 && isForwardRange!S2))
string.d(551):std.string.indexOf(S1, S2)(S1 s, S2 sub,
const size_t startIdx, CaseSensitive cs = CaseSensitive.yes) if
(isSomeString!S || isForwardRange!S1 && isForwardRange!S2 &&
isSomeChar!(ElementType!S1))
string.d(553):

Re: Explicit Declaration of Pureness and Throwness of Higher Order Ranges

2014-03-10 Thread Nordlöw
I'm not quite sure what you're asking. You either mark a 
function as @safe,
pure, and/or nothrow - or you don't, in which case, if it's a 
templated
function, the attributes are inferred to the best of the 
compiler's
capabilities, and if it's not, then the function doesn't have 
those

attributes.

If you're asking whether we should prefer to be explicit with 
attributes on
template functions, then the answer is no. We want the 
inference to be done by
the compiler for the very reason that it was introduced in the 
first place.
Without inference, if the function is marked with @safe, pure, 
or nothrow,
then that restricts the list of valid template arguments to 
arguments that
fulfill those requirements, and if we don't mark the templated 
function as
@safe, pure, or nothrow, then it can't be used in other 
functions marked with

those attributes.

Now, prior to dmd 2.065, the attribute inference was pretty 
poor, but it looks

like the various bugs with regards to that were fixed:

http://dlang.org/changelog.html#attribinference2

So, attribute inference should be working much better now.

- Jonathan M Davis


That's exactly the answer I asked for and wanted to hear ;)

Thanks again,
Sifu


Re: Explicit Declaration of Pureness and Throwness of Higher Order Ranges

2014-03-10 Thread Jonathan M Davis
On Monday, March 10, 2014 22:02:39 Nordlöw wrote:
> Is it, in D today, possible to explicitly tag higher order ranges
> such as for example `map` with their pureness, safeness and
> throwness based on the corresponding properties on their function
> arguments such as `fun...`?
> 
> And is this motivated? now that the D compiler deduce these
> properties for us automagically?
> 
> I guess if we had some intricate IDE-integration with DMD/DCD or
> alike these properties could be automatically presented to the
> programmer for each range instantiation.

I'm not quite sure what you're asking. You either mark a function as @safe, 
pure, and/or nothrow - or you don't, in which case, if it's a templated 
function, the attributes are inferred to the best of the compiler's 
capabilities, and if it's not, then the function doesn't have those 
attributes.

If you're asking whether we should prefer to be explicit with attributes on 
template functions, then the answer is no. We want the inference to be done by 
the compiler for the very reason that it was introduced in the first place. 
Without inference, if the function is marked with @safe, pure, or nothrow, 
then that restricts the list of valid template arguments to arguments that 
fulfill those requirements, and if we don't mark the templated function as 
@safe, pure, or nothrow, then it can't be used in other functions marked with 
those attributes.

Now, prior to dmd 2.065, the attribute inference was pretty poor, but it looks 
like the various bugs with regards to that were fixed: 

http://dlang.org/changelog.html#attribinference2

So, attribute inference should be working much better now.

- Jonathan M Davis



Explicit Declaration of Pureness and Throwness of Higher Order Ranges

2014-03-10 Thread Nordlöw
Is it, in D today, possible to explicitly tag higher order ranges 
such as for example `map` with their pureness, safeness and 
throwness based on the corresponding properties on their function 
arguments such as `fun...`?


And is this motivated? now that the D compiler deduce these 
properties for us automagically?


I guess if we had some intricate IDE-integration with DMD/DCD or 
alike these properties could be automatically presented to the 
programmer for each range instantiation.


Re: Any way to print compile-time generated code?

2014-03-10 Thread Chris Williams

On Monday, 10 March 2014 at 18:25:10 UTC, Adam D. Ruppe wrote:
Change the mixin(x) line to pragma(msg, x);. It will then print 
out the generated string at compile time instead of mixing it 
in so you can take a look at it.


That just gives me an error:

source/app.d(29): Error: Cannot interpret 
ProtocolBufferFromString!"\x0amessage Person {\x0a  
required string name = 1;\x0a  required int32 id = 2;\x0a 
 optional string email = 3;\x0a\x0a  enum PhoneType {\x0a 
   MOBILE = 0;\x0aHOME = 1;\x0aWORK = 2;\x0a  
}\x0a\x0a  message PhoneNumber {\x0arequired string 
number = 1;\x0aoptional PhoneType type = 2 [default = 
HOME];\x0a  }\x0a\x0a  repeated PhoneNumber phone = 
4;\x0a}\x0a" at compile time


Re: Any way to print compile-time generated code?

2014-03-10 Thread Adam D. Ruppe
Change the mixin(x) line to pragma(msg, x);. It will then print 
out the generated string at compile time instead of mixing it in 
so you can take a look at it.


Any way to print compile-time generated code?

2014-03-10 Thread Chris Williams
I'm toying with the dproto library and have encountered an issue 
where I can't remove items from a "repeated" list of items. I'd 
like to see what the mixins are producing in terms of actual D 
code, so that I can figure out how I can correctly try to delete 
an entry or find the code that's generating the array and add 
whatever corrections are necessary to expose this ability.


Is there any way to push a mixin into a string, instead of into 
the code, or otherwise to view the output of the "preprocessor"?


linking against libmilter

2014-03-10 Thread Hugo Florentino

Hi,

Does anyone have an example of linking against libmilter? The milter 
applications I have seen are a little overweight for my taste, I just 
want to check email headers.
I sure would like to take advante of the fast regexp of D rather than 
buildin my own solution in C (which I don't master).


Regards, Hugo


Re: linear search using 'find' on an array of structs?

2014-03-10 Thread captain_fid

On Sunday, 9 March 2014 at 10:46:26 UTC, Philippe Sigaud wrote:

assert(!find!("toLower(a) == b")(s, "hello").empty);

assert(!find!("toLower(a) == b")(clist.name, 
"name2").empty);




But clist is an array of c's, it has no `.name` field by 
itself. So, put

the `.name` call inside the comparator:


 assert( find!("toLower(a.name) == b")(clist 
*,*

 "name2").empty);

This gives me this code:

import std.algorithm: find;
import std.array: empty;
import std.uni: toLower;

struct C // Use UpperCase for you user-defined types
{
  int idx;
  string name;
}

C[] clist = [ {1, "name1"}, {2, "name2"}, { 3, "name3" } ];

void main() // no need to return 0
{
  auto target = clist.find!((a,b) => toLower(a.name) == 
b)("name2");

  assert(!target.empty);
}

Using UFCS (Universal Function Call Syntax) to tranform f(a,b) 
into a.f(b).

I used it on `find`.



I went looking to replace several foreach statements. Can 
'find' (in
understand it's just a linear search) be used on an array of 
structures

like above.



Sure, as long as you tell it how you will get the info from the 
range (it

defaults to simple equality).





Example pulled and modified. Above code gives me (naturally) -
  ... no property 'name' for type 'cp[]'.

Interestingly, I had accidentally coded the commented out line 
before and

it compiles correctly but will (as you guessed it) fail.



I never use pointers in D. I suppose the `.name` call is 
propagated to the

array elements?


Thanks for the simple explanation Phillppe. Someone else 
mentioned before not using pointers in D (the loss of array 
goodness like mentioned in Andrei's book). Bad habits...


Re: Linux Dynamic Loading of shared libraries

2014-03-10 Thread Steve Teale

On Sunday, 9 March 2014 at 12:07:22 UTC, Steve Teale wrote:

Now suppose that my D shared library contains a class, rather 
that just module ctors/dtors, how do I go about creating an 
instance of that class and using its methods?


After wandering down several dead-end paths, and help from other 
contributors, I have finally come up with something that looks 
like the basis of a plugin pattern for Linux DMD using shared 
objects (.so files). This is somewhat long for a forum post. You 
can download this readme and the associated files from 
britseyeview.com/plugin101.tar.bz2


To get started, you need a base class that provides declarations 
for all functions that the plugin will be allowed to use 
externally. Why base class, and not interface? Well I guess 
because interfaces don't provide any information about data. If 
you create a shared library based on an interface, then all the 
shared object methods that reference data in the class that 
implements the interface fail miserably. I'm sure someone will 
explain why - probably some obvious thing I have overlooked.


OK, so my base class is:

module plugin;

class Plugin
{
   int n;
   this(int _n) { n = _n; }

   int foo() { return int.min; }
   void bar() {}
}


The class that implements this base in the shared library is:

module exta;
import plugin;
import std.stdio;
import std.math;

class ExtA: Plugin
{
   double d;
   this(int n) { super(n); d = PI; }

   override int foo() { return ++n; }
   override void bar() { writefln("Done my thing (%f)", d); }
}

Plugin getInstance(int n)
{
   return new ExtA(n);
}

shared static this() {
  writeln("exta.so shared static this");
}

shared static ~this() {
  writeln("exta.so shared static ~this");
}

The module ctor/dtor are included because that has become 
conventional in discussions about dynamic loading. Otherwise, the 
so has the class implementation - ExtA, and a shared method to 
create an instance of same. It includes references to methods in 
Phobos.


The test program is as follows:

module main;
import core.runtime;
import std.stdio;
import plugin;

extern(C) void* dlsym(void*, const char*);

alias Plugin function(int) pfi;

Plugin getPlugin(string name)
{
   void* lib = Runtime.loadLibrary(name~".so");
   if (lib is null)
   {
  writeln("failed to load plugin shared object");
  return null;
   }

   void* vp = dlsym(lib, 
"_D4exta11getInstanceFiZC6plugin6Plugin\0".ptr);

   if (vp is null)
   {
  writeln("plugin creator function not found");
  return null;
   }
   pfi f = cast(pfi) vp;
   Plugin x = f(42);
   if (x is null)
   {
  writeln("creation of plugin failed");
  return null;
   }
   return x;
}

void main()
{
   Plugin x = getPlugin("exta");
   int n = x.foo();
   writefln("n = %d", n);
   x.bar();
}

The long symbol name used in the dlsym() call is of course from 
the .map file generated when the .so file is created


These can be built using the following primitive makefile, whose 
main purpose is to spell out the required compiler flags:


main :
dmd -c plugin.d
dmd -c -shared -fPIC exta.d
dmd exta.o -shared -defaultlib=libphobos2.so -map
dmd -c main.d
dmd main.o plugin.o -L-ldl -defaultlib=libphobos2.so -L-rpath=.

This assumes that the plugins will be in the same directory as 
the executable (rpath=.).


Note that there is no call to Runtime.unloadLibrary(). The 
assumption her is that once the plugin has been loaded it will be 
there for the duration of the program. If you want to unload it 
you'll probably have to make sure the plugin object is purged 
from memory first, and I have not discovered how to do that yet 
;=(


Steve


Re: Linux Dynamic Loading of shared libraries

2014-03-10 Thread Anthony Goins

On Monday, 10 March 2014 at 06:38:35 UTC, Steve Teale wrote:

On Sunday, 9 March 2014 at 14:09:28 UTC, Tolga Cakiroglu wrote:



For this, you create an "Interface" that matches to the method 
declaration of your class. But notice that instead of defining 
methods, you will define attributes those types' match to that 
class's methods. I did this before and it works. At least with 
Posix "dlsym" function's help.


OK, so then what goes wrong here:

module exta;

class ExtA
{
   int n;
   this(int _n) { n = _n; }

   int foo() { return ++n; }
}

ExtA getInstance(int n)
{
   return new ExtA(n);
}

compiled with:
dmd exta.d -c -fPIC -shared
dmd exta.o -shared -defaultlib=libphobos2.so -L-rpath=.

module main;
import core.runtime;
import std.stdio;

extern(C) void* dlsym(void*, const char*);
extern(C) void dlclose(void*);

interface ExtA
{
   int foo();
}

void main() {
   void* lib = Runtime.loadLibrary("exta.so");
   if (lib is null)
   {
  writeln("library not loaded");
  return;
   }
   writeln("loaded");

   void* vp = dlsym(lib, 
"_D4exta11getInstanceFiZC4exta4ExtA\0".ptr);

   if (vp is null)
   {
  writeln("symbol not found");
  return;
   }
   writeln("got symbol");
   ExtA function(int) f = cast(ExtA function(int)) vp;
   ExtA x = f(42);
   if (x is null)
   {
  writeln("no class object");
  return;
   }
   int n = x.foo();
   writefln("n = %d", n);
   Runtime.unloadLibrary(lib);
}

compiled with:
dmd -c main.d
dmd main.o -L-ldl -defaultlib=libphobos2.so -L-rpath=.

output:
loaded
got symbol
n = 9
Segmentation fault (core dumped)

The answer should be 43. The segfault happens on the 
Runtime.unloadLibrary(lib); call.


Any ideas?

Steve


confusion between main.Exta and exta.ExtA
following worked for me

module exta;

import main;

//===
class ExtA : ExtA_IF
{
int n;
this(int _n) { n = _n; }

int foo() { return ++n; }
}

ExtA_IF getInstance(int n)
{
return new ExtA(n);
}
//=


//==
module main;
import core.runtime;
import std.stdio;

extern(C) void* dlsym(void*, const char*);
extern(C) void dlclose(void*);

interface ExtA_IF
{
int foo();
}

void main() {
void* lib = Runtime.loadLibrary("exta.so");
if (lib is null)
{
   writeln("library not loaded");
   return;
}
writeln("loaded");

//use extern (C) to avoid mangling
void* vp = dlsym(lib,
"_D4exta11getInstanceFiZC4main7ExtA_IF\0".ptr);
if (vp is null)
{
   writeln("symbol not found");
   return;
}
writeln("got symbol");
ExtA_IF function(int) f = cast(ExtA_IF function(int)) vp;
ExtA_IF x = f(42);
if (x is null)
{
   writeln("no class object");
   return;
}
int n = x.foo();
writefln("n = %d", n);

// or free or destroy or whatever it's supposed to be to
//to avoid the seg fault  (bug?)
delete x;
Runtime.unloadLibrary(lib);
}