www.digitalmars.com         C & C++   DMDScript  

D - Separating implementation from definition

reply "Derek Parnell" <Derek.Parnell psyc.ward> writes:
I've struggled with this for a few hours now, and admit defeat.

I'd like to be able to have a file that defines a class's public interface  
AND the class name, but not contain the implementation code. I'd like to  
do this so I can distribute the class definition and an .OBJ file, but  
without distributing the implementation code.

I thought I could define an interface to do this but that isn't quite  
right either, as all that does is specify a set of member functions, and  
has nothing to do with a class Name etc.

Here is what I'd like to do ...

In a file called 'foo_defn.d' I'd have ...
   // The publicly exposed API for the Foo class.
   class Foo definition
   {
       this();
       this(int pValue);
       ~this();
       int TheValue();
       void TheValue(int pValue);
   }

And in another file 'foo.d' I'd have ...

   import foo_defn;
   class Foo implementation
   {
       int v_TheValue;
       this() {v_TheValue = 1;}
       ...etc...
   }

I would then compile 'foo.d' to create 'foo.obj'. Then I would distribute  
'foo.obj' and 'foo_defn.d' so that somebody else could create a file such  
as 'myfoo.d' ...

   import foo_defn;
   class MyFoo
   {
       Foo f;
       this() { f = new Foo;}
       ...etc...
   }

They would then compile 'myfoo.d' and link in 'foo'obj'. This way, they  
could use my foo class without knowing how it was implemented.


This all seems so basic to me that I'm sure I've missed something dead  
obvious.
-- 
Derek
Mar 18 2004
next sibling parent John Reimer <jjreimer telus.net> writes:
Derek Parnell wrote:
 I've struggled with this for a few hours now, and admit defeat.
 
 I'd like to be able to have a file that defines a class's public 
 interface  AND the class name, but not contain the implementation code. 
 I'd like to  do this so I can distribute the class definition and an 
 .OBJ file, but  without distributing the implementation code.
 
 I thought I could define an interface to do this but that isn't quite  
 right either, as all that does is specify a set of member functions, 
 and  has nothing to do with a class Name etc.
 
<sip> I fail to see why a separate public interface is needed. The way I understood it was that D simpifies the work with its import. You just provide your object file and appropriate documentation so that your user knows how to access the public class details. Documentation amounts to the same thing as a the separate class interface anyway. You have fewer source files to worry about as well, meaning less chance of creating inconsistancies between the interface and the implementation (although you could still make mistakes in the documentation too ;-D ). Or maybe I'm not seeing things straight... Take care, John
Mar 18 2004
prev sibling next sibling parent reply "Walter" <walter digitalmars.com> writes:
Check out the example in phobos for gc.d. There are two; one is the
interface, the other is the definition.

"Derek Parnell" <Derek.Parnell psyc.ward> wrote in message
news:opr43anbhtu2m3b2 news.digitalmars.com...
 I've struggled with this for a few hours now, and admit defeat.

 I'd like to be able to have a file that defines a class's public interface
 AND the class name, but not contain the implementation code. I'd like to
 do this so I can distribute the class definition and an .OBJ file, but
 without distributing the implementation code.

 I thought I could define an interface to do this but that isn't quite
 right either, as all that does is specify a set of member functions, and
 has nothing to do with a class Name etc.

 Here is what I'd like to do ...

 In a file called 'foo_defn.d' I'd have ...
    // The publicly exposed API for the Foo class.
    class Foo definition
    {
        this();
        this(int pValue);
        ~this();
        int TheValue();
        void TheValue(int pValue);
    }

 And in another file 'foo.d' I'd have ...

    import foo_defn;
    class Foo implementation
    {
        int v_TheValue;
        this() {v_TheValue = 1;}
        ...etc...
    }

 I would then compile 'foo.d' to create 'foo.obj'. Then I would distribute
 'foo.obj' and 'foo_defn.d' so that somebody else could create a file such
 as 'myfoo.d' ...

    import foo_defn;
    class MyFoo
    {
        Foo f;
        this() { f = new Foo;}
        ...etc...
    }

 They would then compile 'myfoo.d' and link in 'foo'obj'. This way, they
 could use my foo class without knowing how it was implemented.


 This all seems so basic to me that I'm sure I've missed something dead
 obvious.
 -- 
 Derek
Mar 18 2004
parent reply "Derjo Phar" <not available.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:c3e7hl$l03$2 digitaldaemon.com...
 Check out the example in phobos for gc.d. There are two; one is the
 interface, the other is the definition.
There are two whats? Two files called 'gc.d'? Two examples? If so what are their file names? I really do not know what you are talking about. I found a file called gc.d in the folder 'phobus\std', all that contains is a collection of function templates - nothing to do with classes in there though. And I found a file called 'gcstats.d' in the folder 'phobus', but that just contains a structure definition - again no classes. Maybe I'm not explaining myself clearly enough. Sorry about that. I'll have another go... I want to enable a third party to use a CLASS that I have created, but I do not want to give that person the source code to my class's implementation. As I see it, to do that the person will need to have the OBJ file that I would supply. However, if that person is to refer to my class in their own source code, the D compiler needs to have a source definition of my class too. So the question is simply this -- How can I write a source code file that exposes the public API for my class, without exposing the implemention code? At first, I thought that the D interface concept would be just the thing. So I tried this... I created a file called 'Foo_i.d" that contained... interface i_Foo { int FuncA(); int FuncB(); ...etc... } Hoping that all the third party need to do then was to use this file thus ... import Foo_i; class SuperFoo: i_Foo { . . . } But all this meant was that now they had to implement FuncA, FuncB, etc... Not what I wanted! Next I created the file 'foo_i.d' that contained my complete class definition AND implementation code. I compiled that to get a OBJ file 'foo_i.obj'. I renamed that to 'foo.obj'. Then I create a file 'foo.d' that only had the parts of my Foo class that I wished to expose - some functions (not all) and none of the class's variables. Then I pretended to be the third party wishing to use the Foo class. So I create a file 'sfoo.d' that looked like this ... import foo; class SuperFoo: Foo { int FuncC(){return 1;} } This compiled okay, picking up my cut-down version of Foo's definition (from importing 'foo'). I then created 'test.d' with this ... import sfoo; void main() { SuperFoo a; a = new SuperFoo; a.FuncA(); a.FuncC(); } This also compiled okay. But it wouldn't link correctly. The functions that I exposed in my foo.d and the class Foo itself were all undefined. So then I changed 'sfoo.d' so it would import 'foo_i' rather than 'foo' then recompiled 'test.d' and it compiled and linked okay. NOt surprising as 'foo_i.d' contains my implementation code as well as the class API definition. So this is my problem. I don't want to distribute foo_i.d, the one with my class implementation code. Just documenting the Foo API is not enough. Sure it needs to be done, but that doesn't avoid the need for the third party to have the source code for the Foo class (including implementation code). I hope what I want to do is a bit clearer now. -- Derek
 "Derek Parnell" <Derek.Parnell psyc.ward> wrote in message
 news:opr43anbhtu2m3b2 news.digitalmars.com...
 I've struggled with this for a few hours now, and admit defeat.

 I'd like to be able to have a file that defines a class's public
interface
 AND the class name, but not contain the implementation code. I'd like to
 do this so I can distribute the class definition and an .OBJ file, but
 without distributing the implementation code.

 I thought I could define an interface to do this but that isn't quite
 right either, as all that does is specify a set of member functions, and
 has nothing to do with a class Name etc.

 Here is what I'd like to do ...

 In a file called 'foo_defn.d' I'd have ...
    // The publicly exposed API for the Foo class.
    class Foo definition
    {
        this();
        this(int pValue);
        ~this();
        int TheValue();
        void TheValue(int pValue);
    }

 And in another file 'foo.d' I'd have ...

    import foo_defn;
    class Foo implementation
    {
        int v_TheValue;
        this() {v_TheValue = 1;}
        ...etc...
    }

 I would then compile 'foo.d' to create 'foo.obj'. Then I would
distribute
 'foo.obj' and 'foo_defn.d' so that somebody else could create a file
such
 as 'myfoo.d' ...

    import foo_defn;
    class MyFoo
    {
        Foo f;
        this() { f = new Foo;}
        ...etc...
    }

 They would then compile 'myfoo.d' and link in 'foo'obj'. This way, they
 could use my foo class without knowing how it was implemented.


 This all seems so basic to me that I'm sure I've missed something dead
 obvious.
 -- 
 Derek
Mar 19 2004
next sibling parent =?ISO-8859-1?Q?Sigbj=F8rn_Lund_Olsen?= <sigbjorn lundolsen.net> writes:
Derjo Phar wrote:

 "Walter" <walter digitalmars.com> wrote in message
 news:c3e7hl$l03$2 digitaldaemon.com...
 
Check out the example in phobos for gc.d. There are two; one is the
interface, the other is the definition.
There are two whats? Two files called 'gc.d'? Two examples? If so what are their file names? I really do not know what you are talking about. I found a file called gc.d in the folder 'phobus\std', all that contains is a collection of function templates - nothing to do with classes in there though. And I found a file called 'gcstats.d' in the folder 'phobus', but that just contains a structure definition - again no classes.
The garbage collector source is in /dmd/src/phobos/internal/gc 'std' is just one of three directories in the phobos directory. Cheers, Sigbjørn Lund Olsen
Mar 19 2004
prev sibling next sibling parent John Reimer <jjreimer telus.net> writes:
I understand what you are saying, and I apologize for my rather quick, 
non-thinking reply.  You are right.  It can't be done the way I said.  I 
think this has been discussed before, and I agree it's an important 
issue.  The DMD compiler seems to be more suited for open source 
projects currently.  But it does link to external C object files with 
the extern attribute and export directive, so I would think that there 
is a way to interface with external D object files as well.  I've just 
never had to worry or deal with that particular problem.

Have you tried searching this newsgroup for past posts on this topic?

Later,

John
Mar 19 2004
prev sibling parent reply John Reimer <jjreimer telus.net> writes:
These topics have been discussed before.  And Walter has gone into more 
detail in previous threads.  A method of doing something like this is 
shown in the gc.  You just have to dig far enough.  This actually would 
be a very good topic for a tutorial, though.

This thread in particular is pertanent and detailed:

"Implementing extern methods"

http://www.digitalmars.com/drn-bin/wwwnews?D/19210

Also, it's always a good idea to check for information on

http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage

Hope that helps,

John
Mar 19 2004
parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
John Reimer wrote:

 You just have to dig far enough.
dig being a keyword here. Dig separates the implementation from definition using doxygen and by compiling to a lib. -- -Anderson: http://badmama.com.au/~anderson/
Mar 19 2004
parent John Reimer <jjreimer telus.net> writes:
J Anderson wrote:

 John Reimer wrote:
 
 You just have to dig far enough.
dig being a keyword here. Dig separates the implementation from definition using doxygen and by compiling to a lib.
Yes, a reference to dig :-). The Dig toolkit is probably the best example of this kind of thing in action. Yet a highly simplified example helped me get a feel for how it worked.
Mar 20 2004
prev sibling parent reply John Reimer <jjreimer telus.net> writes:
I hope this is what you were looking for:

Here’s a quick tutorial for setting up an interface file and and 
implementation file. (I apologize about formatting... might turn up very 
bad in the newsgroup).

STEP 1:

Create your implementation file:

/* -------------------------------------- */
module foo;

import std.c.stdio;

class Foo {
public:
      int funcA() {
	printf(“Inside method implementation funcA of class Foo”); 			return 1;
	}
      int funcB() {
	printf(“Inside method implementation funcB of class Foo”);  			return 2;
	}
}

/* ----- end of implementation file ----- */


STEP 2:

Compile the implementation file in a separate directory (your work 
directory for the project):

dmd -c foo.d

This should produce foo.obj.

Move to another directory of your choice.  This will be a directory that 
contains a project  that will make use of the foo implementation.  You 
will be providing an “interface” module that will allow the user to only 
see the public members of the class.

So in this directory there will be:

/* -------------------------------------- */
/*
    This module must be of the SAME NAME as the implementation module
    because of the way symbols are combined with the module
    name.
*/
module foo;

class Foo {
public:
     int funcA();
     int funcB();
}

/* ---------- end of interface module -------- */

The interface module is the file you will provide along with the foo.obj 
(implementation) to the developer.  You do not compile this foo.d.  It 
will be imported into the external developers project.

An example:

/* --- main project --- */
module project;

import foo;

int main( char[][] args )
{
	int a, b;
	Foo Foo1 = new Foo;
	
	printf("\nStarting from main():\n");
	a=Foo1.funcA();
	b=Foo1.funcB();
	printf("\na = %d, b = %d\n", a, b);
	return 1;
}


The developer will then compile the project like so (making sure that 
the interface module and implementation object file are in the same 
directory; if they are not, remember to specify the correct paths):

dmd project.d foo.obj -of project.exe

The provided implementation is linked in with the project.  The 
developer never sees the implementation details.  Thanks to Walter for 
the for the gc reference ;-).  Feel free to point any errors.

I'm supposed to be busy studying for an exam... obviously I got 
sidetracked :-).

Later,

John
Mar 19 2004
next sibling parent reply "Derjo Phar" <not available.com> writes:
"John Reimer" <jjreimer telus.net> wrote in message
news:c3gnjg$1s5f$1 digitaldaemon.com...
 I hope this is what you were looking for:
Thank you John. Yes this is exactly it. I was almost there too. The only difference between the correct way you have shown and the way I was doing it, was that in the correct way there is the line 'module foo;' at the start of both the definition file and the implementation file. When I was doing it, I did not have that line or any 'module' statement at all. I guess I didn't really understand the purpose of the module statement. It seems that this identifies the namespace for the file, and if not supplied, the namespace is the same as the file name. -- Derek
Mar 19 2004
parent reply John Reimer <jjreimer telus.net> writes:
Derjo Phar wrote:
 "John Reimer" <jjreimer telus.net> wrote in message
 news:c3gnjg$1s5f$1 digitaldaemon.com...
 
I hope this is what you were looking for:
Thank you John. Yes this is exactly it. I was almost there too. The only difference between the correct way you have shown and the way I was doing it, was that in the correct way there is the line 'module foo;' at the start of both the definition file and the implementation file. When I was doing it, I did not have that line or any 'module' statement at all. I guess I didn't really understand the purpose of the module statement. It seems that this identifies the namespace for the file, and if not supplied, the namespace is the same as the file name.
In fact, you don't need the module statement. I believe that if you leave it out, the module name defaults to the filename. So you probably had it figured out on your own afterall. I just included it for clarity. For more information about the specifics of "module": http://www.digitalmars.com/d/module.html I also realize it may have been more accurrate to use the terms definition/implementation vereses interface/implementation. Oh well. Later, John
Mar 20 2004
parent reply "Derjo Phar" <not available.com> writes:
"John Reimer" <jjreimer telus.net> wrote in message
news:c3gvrr$2b48$1 digitaldaemon.com...
 Derjo Phar wrote:
 "John Reimer" <jjreimer telus.net> wrote in message
 news:c3gnjg$1s5f$1 digitaldaemon.com...

I hope this is what you were looking for:
Thank you John. Yes this is exactly it. I was almost there too. The only difference between the correct way you have shown and the way I was
doing
 it, was that in the correct way there is the line 'module foo;' at the
start
 of both the definition file and the implementation file. When I was
doing
 it, I did not have that line or any 'module' statement at all.

 I guess I didn't really understand the purpose of the module statement.
It
 seems that this identifies the namespace for the file, and if not
supplied,
 the namespace is the same as the file name.
In fact, you don't need the module statement. I believe that if you leave it out, the module name defaults to the filename. So you probably had it figured out on your own afterall. I just included it for clarity. For more information about the specifics of "module": http://www.digitalmars.com/d/module.html
I had read that section of the documentation many times before giving up. I now realize that the paragraph "Modules have a one-to-one correspondence with source files. The module name is the file name with the path and extension stripped off." was what confused me. Now I realize that the module name can actually be different from the file name. It's the module name that is the namespace name, and its this that is used by the linkeditor to resolve symbols in the .OBJ file. Anyhow, I now have two source files... //---------------- foo.d --------- module foo; import std.c.stdio; class Foo { private int x; /* expose */ int FuncA(){ printf("Inside method implementation funcA of class Foo\n"); return 1;} /* expose */ int FuncB(){ printf("Inside method implementation funcB of class Foo\n"); return 2;} } and ... //---------------- foo_i.d --------- module foo; class Foo { public: int FuncA(); int FuncB(); } So I compile foo.d to get a .OBJ file and I distribute this OBJ file with the foo_i.d file. The "/* expose */" is a tag I can use to generate the foo_i.d automatically via a preprocessor job. Thanks again. -- Derek
Mar 20 2004
parent reply John Reimer <jjreimer telus.net> writes:
<snip?
 
 So I compile foo.d to get a .OBJ file and I distribute this OBJ file with
 the foo_i.d file. The "/* expose */" is a tag I can use to generate the
 foo_i.d automatically via a preprocessor job.
 
 
 Thanks again.
 
You know what? I never thought of using module keyword that way; the simple solution escaped me. That's a great idea because than the two files don't have to be the same name. And foo_i.d can point out the definition file better. Also the stripping of the implementation with a preprocessor or script is indeed the way to go. Good work, John
Mar 20 2004
parent reply J C Calvarese <jcc7 cox.net> writes:
John Reimer wrote:
 <snip>
 Also the stripping of the implementation with a preprocessor or script is
 indeed the way to go.
In fact, there's already a tool available that does some of this. Dig's strip.d doesn't require the rest of Dig. It's not perfect, but it works on some cases that I've thrown at it.
 
 Good work,
 
 John
-- Justin http://jcc_7.tripod.com/d/
Mar 21 2004
parent John Reimer <jjreimer telus.net> writes:
J C Calvarese wrote:

 John Reimer wrote:
 
 <snip>
 Also the stripping of the implementation with a preprocessor or script is
 indeed the way to go.
In fact, there's already a tool available that does some of this. Dig's strip.d doesn't require the rest of Dig. It's not perfect, but it works on some cases that I've thrown at it.
<snip lots of D code> Hmmm... I should have known. Thanks for posting it. That should make things easier :-). I was thinking a good 'ol python script was in order here. Later, John
Mar 22 2004
prev sibling parent reply larry cowan <larry_member pathlink.com> writes:
With the following changes in the implementation file, what has to be in the
interface module (definition file?).

In article <c3gnjg$1s5f$1 digitaldaemon.com>, John Reimer says...
I hope this is what you were looking for:

Here’s a quick tutorial for setting up an interface file and and 
implementation file. (I apologize about formatting... might turn up very 
bad in the newsgroup).

STEP 1:

Create your implementation file:

/* -------------------------------------- */
module foo;

import std.c.stdio;

class Foo {
static int basis = 0; int start = 0; static int funcS(int arg) { return start + arg; } int incrBase() { basis++; }
public:
this(int begin) { start = basis + begin; }
      int funcA() {
	printf(“Inside method implementation funcA of class Foo”);
return ++start;
	}
      int funcB() {
	printf(“Inside method implementation funcB of class Foo”);
return ++start;
	}
}

/* ----- end of implementation file ----- */


STEP 2:

Compile the implementation file in a separate directory (your work 
directory for the project):

dmd -c foo.d

This should produce foo.obj.

Move to another directory of your choice.  This will be a directory that 
contains a project  that will make use of the foo implementation.  You 
will be providing an “interface” module that will allow the user to only 
see the public members of the class.

So in this directory there will be:

/* -------------------------------------- */
/*
    This module must be of the SAME NAME as the implementation module
    because of the way symbols are combined with the module
    name.
*/
module foo;

class Foo {
public:
     int funcA();
     int funcB();
}

/* ---------- end of interface module -------- */

The interface module is the file you will provide along with the foo.obj 
(implementation) to the developer.  You do not compile this foo.d.  It 
will be imported into the external developers project.

An example:

/* --- main project --- */
module project;

import foo;

int main( char[][] args )
{
	int a, b;
	Foo Foo1 = new Foo;
	
	printf("\nStarting from main():\n");
	a=Foo1.funcA();
	b=Foo1.funcB();
	printf("\na = %d, b = %d\n", a, b);
	return 1;
}


The developer will then compile the project like so (making sure that 
the interface module and implementation object file are in the same 
directory; if they are not, remember to specify the correct paths):

dmd project.d foo.obj -of project.exe

The provided implementation is linked in with the project.  The 
developer never sees the implementation details.  Thanks to Walter for 
the for the gc reference ;-).  Feel free to point any errors.

I'm supposed to be busy studying for an exam... obviously I got 
sidetracked :-).

Later,

John
Mar 20 2004
next sibling parent "C. Sauls" <ibisbasenji yahoo.com> writes:
As I understand it, you simply provide a decleration/prototype for all 
public members, and that's that... could be wrong, haven't tried it.

-C. Sauls
-Invironz
Mar 20 2004
prev sibling parent John Reimer <jjreimer telus.net> writes:
larry cowan wrote:

 With the following changes in the implementation file, what has to be in
 the interface module (definition file?).
 
<snip> Yes, a more thorough example would have been better, one that included private and static members. I may work out something later. Truth be told, I haven't experimented beyond this point, but my assumption was that of C. Sauls. You just reveal what you want to reveal in the definition (the public members). It should all work properly because it doesn't change how the implementation module operates internally. It shouldn't be too much work to add those additions and give it a try. Later, John
Mar 20 2004