www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Interface file

reply Jan Johansson <jan.johansson.mr gmail.com> writes:
Hello all,

I'm testing D language, and the first thing I want to do is to 
separate declaration from implementation. I was happy to find 
support of interfaces in the D language, and set out to do a 
basic test. However, this test failed, and I want some newbie 
help to understand how it should be done in D language.

----------------------

The interface file (I called it test.di):

// Interface
interface IMyTest {
   void Write(string message);
}

// Factory for type implementing IMyTest
IMyTest createInstance();

----------------------

The library file (I called it test.d):

import std.stdio;

class MyTest : IMyTest {
     void Write(string message) {
         writeln(message);
     }
}

IMyTest createInstance() {
     return new MyTest;
}

----------------------

And finally the main file (I called it main.d):

import test;
import std.stdio;

void main() {
     auto p = createInstance();
     p.Write("Hello, World!");
}

----------------------

The assumption was that I could do:

   dmd test.d test.di -lib -oftest

and next do:

   dmd main.d test.di test.a


The shared information is in the test.di file.

However, this failed, since the first statement generates the 
following:

   dmd test.d test.di -lib -oftest
   Error: module test from file test.di conflicts with another 
module test from file test.d

I guess it is because the file name test.d and test.di creates 
conflict, surfaced as module test.

How can I accomplish what I want to do?

Kind regards,
Jan Johansson
Sep 30 2015
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 30 September 2015 at 17:51:50 UTC, Jan Johansson 
wrote:
 The interface file (I called it test.di):
FYI there's no actual difference between .di files and .d files. The way D is meant to be used is you write the declarations together, then if you want to, you can automatically strip the bodies out of a .d file (dmd -H does it) and that makes the .di file. But you always substitute the .di file for the .d file with the same name. They cannot be used together like a .h and .cpp file. You can put an interface in a separate module than a class. Then you import the interface module from both locations, though your factory function won't work like that. Try something like: itest.d: module itest; interface IMyTest { void Write(string message); } test.d: public import itest; // import the interface definition too import std.stdio; private class MyTest : IMyTest { void Write(string message) { writeln(message); } } public IMyTest createInstance() { return new MyTest; } main.d: import test; import std.stdio; void main() { auto p = createInstance(); p.Write("Hello, World!"); } And that should work.
   dmd test.d test.di -lib -oftest
would be more like `dmd itest.d test.d -lib -oftest`
   dmd main.d test.di test.a
and `dmd main.d itest.d test.a` Or you could just compile it all at once with `dmd main.d test.d itest.d`
Sep 30 2015
next sibling parent reply Jan Johansson <jan.johansson.mr gmail.com> writes:
On Wednesday, 30 September 2015 at 18:01:57 UTC, Adam D. Ruppe 
wrote:
 On Wednesday, 30 September 2015 at 17:51:50 UTC, Jan Johansson 
 wrote:
 The interface file (I called it test.di):
FYI there's no actual difference between .di files and .d files. The way D is meant to be used is you write the declarations together, then if you want to, you can automatically strip the bodies out of a .d file (dmd -H does it) and that makes the .di file. But you always substitute the .di file for the .d file with the same name. They cannot be used together like a .h and .cpp file. You can put an interface in a separate module than a class. Then you import the interface module from both locations, though your factory function won't work like that. Try something like: itest.d: module itest; interface IMyTest { void Write(string message); } test.d: public import itest; // import the interface definition too import std.stdio; private class MyTest : IMyTest { void Write(string message) { writeln(message); } } public IMyTest createInstance() { return new MyTest; } main.d: import test; import std.stdio; void main() { auto p = createInstance(); p.Write("Hello, World!"); } And that should work.
   dmd test.d test.di -lib -oftest
would be more like `dmd itest.d test.d -lib -oftest`
   dmd main.d test.di test.a
and `dmd main.d itest.d test.a` Or you could just compile it all at once with `dmd main.d test.d itest.d`
Thanks, But (there is always a but) ;-) The main.d should rely on itest.d, not test.d, otherwise I do the declaration for the library itself, but the main.d includes the test.d - the implementation (not the declaration). If I change the 'dmd main.d test.d test.a' to 'dmd main.d itest.d test.a', then I got a new error: itest.d:(.text._Dmain+0x5): undefined reference to `_D5itest14createInstanceFZC5itest7IMyTest' The linker get confused about the separation of the declaration and implementation. Best regards Jan Johansson
Sep 30 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/30/15 2:12 PM, Jan Johansson wrote:

 Thanks,

 But (there is always a but) ;-)

 The main.d should rely on itest.d, not test.d, otherwise I do the
 declaration for the library itself, but the main.d includes the test.d -
 the implementation (not the declaration).

 If I change the 'dmd main.d test.d test.a' to 'dmd main.d itest.d
 test.a', then I got a new error: itest.d:(.text._Dmain+0x5): undefined
 reference to `_D5itest14createInstanceFZC5itest7IMyTest'

 The linker get confused about the separation of the declaration and
 implementation.
There is no reason to use interfaces here, you can separate declaration from implementation without them: test.di: module test; class MyTest { void Write(string message); } test.d: module test; class MyTest { void Write(string message) { writeln(message); } } main.d: import test; // will work even if only test.di is available import std.stdio; void main() { auto p = new MyTest; p.Write("Hello, World!"); } Interfaces are only necessary when you are unsure what concrete type you need until runtime. -Steve
Sep 30 2015
parent Jan Johansson <jan.johansson.mr gmail.com> writes:
On Wednesday, 30 September 2015 at 19:17:41 UTC, Steven 
Schveighoffer wrote:
 On 9/30/15 2:12 PM, Jan Johansson wrote:

 [...]
There is no reason to use interfaces here, you can separate declaration from implementation without them: test.di: module test; class MyTest { void Write(string message); } test.d: module test; class MyTest { void Write(string message) { writeln(message); } } main.d: import test; // will work even if only test.di is available import std.stdio; void main() { auto p = new MyTest; p.Write("Hello, World!"); } Interfaces are only necessary when you are unsure what concrete type you need until runtime. -Steve
Thanks Steve, Your last statement is exactly what I want to do! Using contract based design, and factories to instantiate types that implements the interface. //Jan
Sep 30 2015
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/30/2015 02:01 PM, Adam D. Ruppe wrote:
[snip]

Good material for a Q&A section of TWiD. -- Andrei
Sep 30 2015
prev sibling next sibling parent reply Jeremy DeHaan <dehaan.jeremiah gmail.com> writes:
On Wednesday, 30 September 2015 at 17:51:50 UTC, Jan Johansson 
wrote:
 Hello all,

 I'm testing D language, and the first thing I want to do is to 
 separate declaration from implementation. I was happy to find 
 support of interfaces in the D language, and set out to do a 
 basic test. However, this test failed, and I want some newbie 
 help to understand how it should be done in D language.

 ----------------------

 The interface file (I called it test.di):

 // Interface
 interface IMyTest {
   void Write(string message);
 }

 // Factory for type implementing IMyTest
 IMyTest createInstance();

 ----------------------

 The library file (I called it test.d):

 import std.stdio;

 class MyTest : IMyTest {
     void Write(string message) {
         writeln(message);
     }
 }

 IMyTest createInstance() {
     return new MyTest;
 }

 ----------------------

 And finally the main file (I called it main.d):

 import test;
 import std.stdio;

 void main() {
     auto p = createInstance();
     p.Write("Hello, World!");
 }

 ----------------------

 The assumption was that I could do:

   dmd test.d test.di -lib -oftest

 and next do:

   dmd main.d test.di test.a


 The shared information is in the test.di file.

 However, this failed, since the first statement generates the 
 following:

   dmd test.d test.di -lib -oftest
   Error: module test from file test.di conflicts with another 
 module test from file test.d

 I guess it is because the file name test.d and test.di creates 
 conflict, surfaced as module test.

 How can I accomplish what I want to do?

 Kind regards,
 Jan Johansson
Like Adam said, the real difference between a .d and a .di file is that the .di file has all the guts removed and is just the declarations. If using a .di file is really what you want, you could try something like this? test.d: module test; interface IMyTest { void Write(string message); } IMyTest createInstance() { class MyTest : IMyTest { void Write(string message) { import std.stdio; writeln(message); } } return new MyTest; } --------------- test.di: module test; interface IMyTest { void Write(string message); } IMyTest createInstance(); --------------- main.d: import test; void main() { auto p = createInstance(); p.Write("Hello, World!"); } -------------- and then dmd test.d -lib -oftest and dmd main.d test.di test.a Also like Adam said, dmd can create these .di files for you so you don't have to! (This is untested, but should work/be close to working)
Sep 30 2015
parent reply Jan Johansson <jan.johansson.mr gmail.com> writes:
On Wednesday, 30 September 2015 at 19:24:05 UTC, Jeremy DeHaan 
wrote:
 On Wednesday, 30 September 2015 at 17:51:50 UTC, Jan Johansson 
 wrote:
 [...]
Like Adam said, the real difference between a .d and a .di file is that the .di file has all the guts removed and is just the declarations. If using a .di file is really what you want, you could try something like this? test.d: module test; interface IMyTest { void Write(string message); } IMyTest createInstance() { class MyTest : IMyTest { void Write(string message) { import std.stdio; writeln(message); } } return new MyTest; } --------------- test.di: module test; interface IMyTest { void Write(string message); } IMyTest createInstance(); --------------- main.d: import test; void main() { auto p = createInstance(); p.Write("Hello, World!"); } -------------- and then dmd test.d -lib -oftest and dmd main.d test.di test.a Also like Adam said, dmd can create these .di files for you so you don't have to! (This is untested, but should work/be close to working)
Thanks Jeremy, Do you spot a weakness in your proposed code snip? The declaration for interface is done in two separate files, both test.d and test.di. Scattered declarations has never been a good idea. I know that I can ask the DMD to do declaration files for me, but the use case for that is to speed up building of executable. But is it that the separation of declaration and implementation was never the intention in the design of D? //Jan
Sep 30 2015
parent reply Jeremy DeHaan <dehaan.jeremiah gmail.com> writes:
On Thursday, 1 October 2015 at 01:41:22 UTC, Jan Johansson wrote:
 Thanks Jeremy,

 Do you spot a weakness in your proposed code snip? The 
 declaration for interface is done in two separate files, both 
 test.d and test.di. Scattered declarations has never been a 
 good idea. I know that I can ask the DMD to do declaration 
 files for me, but the use case for that is to speed up building 
 of executable.

 But is it that the separation of declaration and implementation 
 was never the intention in the design of D?

 //Jan
Having the declarations in both files is the point though. If you notice, the only difference between my test.d and test.di files is that test.di is only the declarations. The speed increase for compiling happens because of this. You still need all declarations to be there when you build, or at least the ones you use. You build the library with test.d and then build using test.di when you use the library. You never use both test.d and test.di together. Double check my build commands.
Oct 01 2015
parent Atila Neves <atila.neves gmail.com> writes:
On Thursday, 1 October 2015 at 17:12:02 UTC, Jeremy DeHaan wrote:
 On Thursday, 1 October 2015 at 01:41:22 UTC, Jan Johansson 
 wrote:
 [...]
Having the declarations in both files is the point though. If you notice, the only difference between my test.d and test.di files is that test.di is only the declarations. The speed increase for compiling happens because of this. You still need all declarations to be there when you build, or at least the ones you use. You build the library with test.d and then build using test.di when you use the library. You never use both test.d and test.di together. Double check my build commands.
The linker will be the bottleneck anyway, I don't think .di files are worth it. Atila
Oct 02 2015
prev sibling parent Jan Johansson <jan.johansson.mr gmail.com> writes:
On Wednesday, 30 September 2015 at 17:51:50 UTC, Jan Johansson 
wrote:
 Hello all,

 I'm testing D language, and the first thing I want to do is to 
 separate declaration from implementation. I was happy to find 
 support of interfaces in the D language, and set out to do a 
 basic test. However, this test failed, and I want some newbie 
 help to understand how it should be done in D language.

 ----------------------

 The interface file (I called it test.di):

 // Interface
 interface IMyTest {
   void Write(string message);
 }

 // Factory for type implementing IMyTest
 IMyTest createInstance();

 ----------------------

 The library file (I called it test.d):

 import std.stdio;

 class MyTest : IMyTest {
     void Write(string message) {
         writeln(message);
     }
 }

 IMyTest createInstance() {
     return new MyTest;
 }

 ----------------------

 And finally the main file (I called it main.d):

 import test;
 import std.stdio;

 void main() {
     auto p = createInstance();
     p.Write("Hello, World!");
 }

 ----------------------

 The assumption was that I could do:

   dmd test.d test.di -lib -oftest

 and next do:

   dmd main.d test.di test.a


 The shared information is in the test.di file.

 However, this failed, since the first statement generates the 
 following:

   dmd test.d test.di -lib -oftest
   Error: module test from file test.di conflicts with another 
 module test from file test.d

 I guess it is because the file name test.d and test.di creates 
 conflict, surfaced as module test.

 How can I accomplish what I want to do?

 Kind regards,
 Jan Johansson
Hi again, Here is a re-worked example. Again, I want to use the factory pattern, and have created four files. --- test.d (interface): interface IMyTest { void Write(string message); } --- mytesting.d (one implementation of interface): import test; class MyTesting : IMyTest { void Write(string message) { import std.stdio; writeln("MyTesting: " ~ message); } } --- factory.d (factory): import test; import mytesting; IMyTest createInstance() { return new MyTesting; } --- main.d (program): import factory; import std.stdio; void main() { auto p = createInstance(); p.Write("Hello, World!"); } --- There are a number of ways to build the executable. I want to use binary linkage as much as possible (the next step is to do dynamically linkage - but here I need help - I'm still a newbie). First I build the component (class) artifact: dmd mytesting.d -lib -ofmytesting Next I build the factory artifact: dmd factory.d -lib -offactory And then I close the loop: dmd main.d test.d factory.a mytesting.a --- //Jan
Sep 30 2015