3

I really want to use D because its language constructions do so many things I care about better than C++, but the almost-forced GC (issue handled [sort of] here), slightly less powerful operator overloading (except opDispatch. opDispatch is sexy), and the following issue are kinda turning me off.

Is it possible in D to split a method declaration from a definition? If so, how? If not, why?

Motivating example for 'how': to provide a small header file of interface functions next to a binary object, as with a C header and library, for the sake of hiding the implementation away from the eyes of a writer of user code. Preference: without depending on whether or not the user code has hacked away the garbage collector or is simply compiling without druntime (such as this found in the comments here).

Community
  • 1
  • 1
user
  • 4,920
  • 3
  • 25
  • 38
  • Read about D interface files. – DejanLekic Aug 05 '13 at 22:08
  • @DejanLekic I'm only seeing D interface files specified in documentation sections on compilers. Is it a compiler-by-compiler thing or a language thing? EDIT: Blargh, read a bit further on them. They're not part of the language. Is there a solution that *IS* part of the language? – user Aug 05 '13 at 22:41
  • The D interface file is just using a different part of the same D language. (In fact, the dmd compiler doesn't care whether the extension is .d or .di, they all work the same way.) – Adam D. Ruppe Aug 05 '13 at 23:02
  • @AdamD.Ruppe A'ight - but could you then clarify the following quote (from http://dlang.org/dmd-linux.html#interface_files): "D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process." – user Aug 05 '13 at 23:43
  • @AdamD.Ruppe I mean, to be clear, I'm not going to be a purist and say that .di files not being part of the core language definition is a turn off. I just wanna know what's up with them. – user Aug 06 '13 at 03:13

3 Answers3

4

If I write a D file like this one: http://arsdnet.net/dcode/iface/test.d and you compile with dmd -c, you'll see it goes without errors; that's a valid D file. The language allows you to write function prototypes without implementations.

A .di file is just like that, it just has a different file name.

Then given main: http://arsdnet.net/dcode/main.d if you compile dmd main, it will automatically search for iface/test.d when it sees "import iface.test;", find that .d file, or the .di if you rename it but same thing, and get your interface definition.

dmd main will fail with a linker error, so we need to implement it: http://arsdnet.net/dcode/impl.d Note: the impl does NOT import the module, so it never checks the other file. Keeping the .di and .d files in sync is one of the tricky parts here, unless you auto-generate the interface file, as undefined methods would give linker errors, but the order of methods is important: it must match, and so do the list of variables if there's any public ones. Otherwise, the usage code and the implementation code won't agree on the class' layout.

Again, it does not check that automatically, the implementation file doesn't look at the "header" file at all, so this is a major difference from C++ where you write the header file once, then use it in both the usage program and the implementation file.

You'll notice that the implementation file also lists the class, etc., too. D doesn't support the void MyClass::add(int a) {} syntax C++ has to write the method outside the class.

As far as I know, there's no way to force the implementation file to look for the header, if you put both on the command line, you get: "Error: module iface.test from file iface/test.d conflicts with another module test from file impl.d"

The way .di files are recommended to be used is to auto generate them with dmd -H. This reads the full implementation file and strips out the function bodies, leaving just the definitions. This part is probably the key thing when they say it is a feature of the compiler - the .di file is valid and standard D, but generated via a compiler option that doesn't necessarily need to be part of other compilers.

BCS
  • 75,627
  • 68
  • 187
  • 294
Adam D. Ruppe
  • 25,382
  • 4
  • 41
  • 60
  • `dmd main` to see the error and `dmd main.d impl.d` to see it run successfully. Download both files to your own folder. – Adam D. Ruppe Jun 24 '15 at 17:03
3

You can declare functions without specifying their implementation by using extern, e.g.:

extern(D):
void foo(string name);

Then simply provide an object file/archive with the implementation for linking. Do note that the module name is part of the function's mangled name so either the header file needs the same module name as the compiled module or you can use extern(C) to disable mangling (precludes overloading and uses C call convention).

Justin W
  • 2,077
  • 12
  • 17
3

Adam already explained everything. I will just try to add an extra example:

Say you are develoing a library called mylib and it has functions foo() and bar(). Your code and library test application may look like this at start:

mylib.d - interface file

module mylib;

void foo();
void bar();

mylib_impl.d - definitions are here

module mylib;

import std.stdio;

void foo() {
  writeln("foo()");
}

void bar() {
  writeln("bar()");
}

mylib_test.d - a test application

// To compile: dmd mylib_impl.d mylib_test.d
// NOTE: we do not compile the "interface" file mylib.d !!
module mylib_test;

import mylib;

int main() {
  foo();
  bar();

  return 0;
}

Now it should not be difficult to understand that we have .di files purely for convenience and clarity. If we decide to use interface file we would rename mylib.d to mylib.di, and mylib_impl.d to mylib.d. mylib_test.d would stay intact.

DejanLekic
  • 18,787
  • 4
  • 46
  • 77