www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to create a function declaration?

reply Marcio Faustino <m.faustino gmail.com> writes:
Hi everyone,

How can I create a function declaration only and provide its definition later?
For example:

/******************************************************************************/
extern (C) int print(char*);

extern (C) int print(char* s) {
    return printf("%s", s);
}

void main() {
    print(cast(char*) "test\0");
}
/******************************************************************************/

The compiler says:
«test.d(9): function test.print called with argument types:
        (char*)
matches both:
        test.print(char*)
and:
        test.print(char*)»

What am I doing wrong?
Thanks,
Jan 12 2007
next sibling parent Sean Kelly <sean f4.ca> writes:
Marcio Faustino wrote:
 Hi everyone,
 
 How can I create a function declaration only and provide its definition later?
 For example:
 
 /******************************************************************************/
 extern (C) int print(char*);
 
 extern (C) int print(char* s) {
     return printf("%s", s);
 }
 
 void main() {
     print(cast(char*) "test\0");
 }
 /******************************************************************************/
 
 The compiler says:
 «test.d(9): function test.print called with argument types:
         (char*)
 matches both:
         test.print(char*)
 and:
         test.print(char*)»
 
 What am I doing wrong?
 Thanks,

Nothing. I think the implementation needs to be in a separate file if you want separate compilation like that. Though it would admittedly be nice if the compiler could recognize that there is no actual conflict between a declaration and an implementation of the same function. Sean
Jan 12 2007
prev sibling next sibling parent reply rochus <rochus rochus.net> writes:
Marcio Faustino wrote:
 Hi everyone,
 
 How can I create a function declaration only and provide its definition later?
 For example:

If you meant a "foreward declaration": this is not possible in D.
Jan 12 2007
parent "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
rochus schrieb:
 Marcio Faustino wrote:
 Hi everyone,

 How can I create a function declaration only and provide its definition later?
 For example:

If you meant a "foreward declaration": this is not possible in D.

In the normal case, something like that is not needed. For libs, there is the possibilty to generate headers. For dmd use the -H option. The generated .di files will contain all declarations the compiler needs to compile a module.
Jan 12 2007
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Marcio Faustino wrote:
 How can I create a function declaration only and provide its definition later?

You can't. Not in the same file, at least.[1]
 For example:
 
 /******************************************************************************/
 extern (C) int print(char*);
 
 extern (C) int print(char* s) {
     return printf("%s", s);
 }
 
 void main() {
     print(cast(char*) "test\0");
 }
 /******************************************************************************/
 
 The compiler says:
 «test.d(9): function test.print called with argument types:
         (char*)
 matches both:
         test.print(char*)
 and:
         test.print(char*)»

 What am I doing wrong?

You're writing forward declarations. Seriously, D doesn't need them; forward references are allowed ;). A function declaration without definition is for when you put the definition in a different file, not to put it later in the same file. It's mostly useful to link to libraries designed to link to C, though Phobos also uses it in object.d to link to definitions in internal/object.d. It *could* also be useful to link to closed-source D libraries, but I haven't seen any yet... [1]: I just had an evil idea. Turns out it's technically possible. You can declare extern(C) it with a different argument type, then both overloads will have the same name in the executable (no name mangling) and the linker will link them both to the same definition. But I wouldn't use this for anything serious, and I wouldn't have been surprised if it hadn't worked at all due to a symbol conflict or something.
Jan 12 2007
next sibling parent reply Marcio Faustino <m.faustino.remove gmail.com> writes:
 You're writing forward declarations. Seriously, D doesn't need them;
 forward references are allowed ;).

 A function declaration without definition is for when you put the
 definition in a different file, not to put it later in the same file.
 It's mostly useful to link to libraries designed to link to C, though
 Phobos also uses it in object.d to link to definitions in internal/object.d.
 It *could* also be useful to link to closed-source D libraries, but I
 haven't seen any yet...

So, how can I do something like this: /*[ my_printf.d ]**************************************************************/ module my_printf; extern (C) int printf(char* format, ...) { return 0; // Just to test. } /******************************************************************************/ /*[ test.d ]*******************************************************************/ import my_printf; void main() { //printf("test\0"); // Error. my_printf.printf("test\0"); // Ok. } /******************************************************************************/ Because the line with "Error" uncommented, the compiler says: «test.d(5): Error: object.printf at /home/marcio/dmd/src/phobos/object.d(14) conflicts with my_printf.printf at my_printf.d(3)»
Jan 12 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Marcio Faustino wrote:
 So, how can I do something like this:
 
 /*[ my_printf.d ]**************************************************************/
 module my_printf;
 
 extern (C) int printf(char* format, ...) {
 	return 0;    // Just to test.
 }
 /******************************************************************************/
 /*[ test.d ]*******************************************************************/
 import my_printf;
 
 void main() {
 	//printf("test\0");            // Error.
 	my_printf.printf("test\0");    // Ok.
 }
 /******************************************************************************/
 
 Because the line with "Error" uncommented, the compiler says:
 «test.d(5): Error: object.printf at /home/marcio/dmd/src/phobos/object.d(14)
 conflicts with my_printf.printf at my_printf.d(3)»

'printf' is problematic because object.d (which is automatically imported into every D module) also declares it. That code might otherwise compile, but I'm not sure what would happen at the linking stage; printf is also defined in the C runtime library which is linked to by default. It might just use one of the two, or it might fail.
Jan 12 2007
parent reply Marcio Faustino <m.faustino.remove gmail.com> writes:
Frits van Bommel wrote:
 'printf' is problematic because object.d (which is automatically
 imported into every D module) also declares it.

 That code might otherwise compile, but I'm not sure what would happen at
 the linking stage; printf is also defined in the C runtime library which
 is linked to by default. It might just use one of the two, or it might fail.

But the problem is that the code *does not* compile with the line that says "Error" uncommented. Without getting into linking details, the compiler *should* accept the given definition because "object.d" and "internal/object.d" only contain declarations of the printf function. Am I wrong?
Jan 12 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Marcio Faustino wrote:
 Frits van Bommel wrote:
 'printf' is problematic because object.d (which is automatically
 imported into every D module) also declares it.

 That code might otherwise compile, but I'm not sure what would happen at
 the linking stage; printf is also defined in the C runtime library which
 is linked to by default. It might just use one of the two, or it might fail.

But the problem is that the code *does not* compile with the line that says "Error" uncommented. Without getting into linking details, the compiler *should* accept the given definition because "object.d" and "internal/object.d" only contain declarations of the printf function. Am I wrong?

The compiler sees two declarations for printf, in different modules. It sees these as different functions as one is 'object.printf' and the other is 'my_printf.printf'. The easiest ways to solve this ambiguity are (1) rename your printf ;). (2) add 'alias my_printf.printf printf' to your test.d to make it clear which printf you want. (3) change the import line to 'import my_printf : printf' to import only printf from that module and additionally get the effect of (2). I know it seems a bit silly to have to disambiguate between two declarations that will generate the exact same machine code when called (including the called address) but D's name resolution was probably designed with name mangling in mind...
Jan 12 2007
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Marcio Faustino wrote:
<snip>
 /*[ test.d ]*******************************************************************/
 import my_printf;
 
 void main() {
 	//printf("test\0");            // Error.
 	my_printf.printf("test\0");    // Ok.
 }
 /******************************************************************************/
 
 Because the line with "Error" uncommented, the compiler says:
 «test.d(5): Error: object.printf at /home/marcio/dmd/src/phobos/object.d(14)
 conflicts with my_printf.printf at my_printf.d(3)»

You've more or less answered your own question: use a fully-qualified name. Alternatively, use in test.d alias my_printf.printf printf; However, when doing it on functions with C linkage, you have to be careful. Because they don't have the module name mangled in, you may cause a linker conflict or end up inadvertently calling the C library function with the same name. Indeed, I don't know why this doesn't cause a linker conflict when I try it (under DMD 1.00, Win98SE). Stewart.
Jan 12 2007
parent reply Marcio Faustino <m.faustino.remove gmail.com> writes:
Stewart Gordon wrote:
 You've more or less answered your own question: use a fully-qualified
 name.  Alternatively, use in test.d

      alias my_printf.printf printf;

That's a nice alternative, but I don't want to use that. Suppose someone were writing a kernel, then the compiler should accept the printf definition he gave because he won't link against the C library. Even so, the compiler says that "object.printf" conflicts with "my_printf.printf"... but where??
Jan 12 2007
next sibling parent Jarrett Billingsley <kb3ctd2 yahoo.com> writes:
Marcio Faustino Wrote:

 Even so, the compiler says that
 "object.printf" conflicts with "my_printf.printf"... but where??

It's declared in two places, and so when you call "printf" in test.d, it finds two printfs. It's a simple matter of symbol lookup -- one name in this case maps to more than one possible function. So the conflict occurs at the call site, which can be fixed by using either an FQN or an alias, as mentioned. If you were linking against some C stdlib that didn't have an implementation of printf, the fix is very simple -- comment out the printf declaration in object.d.
Jan 12 2007
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Marcio Faustino wrote:
 Stewart Gordon wrote:
 You've more or less answered your own question: use a fully-qualified
 name.  Alternatively, use in test.d

      alias my_printf.printf printf;

That's a nice alternative, but I don't want to use that. Suppose someone were writing a kernel, then the compiler should accept the printf definition he gave because he won't link against the C library. Even so, the compiler says that "object.printf" conflicts with "my_printf.printf"... but where??

If one is writing a kernel, one probably modifies object.d ;). At least, that's what I did... (Actually, printf was the first thing to get removed :P)
Jan 12 2007
parent reply Marcio Faustino <m.faustino.remove gmail.com> writes:
Thanks for all the replies, I think I understand it now.

Frits van Bommel wrote:
 If one is writing a kernel, one probably modifies object.d ;).
 At least, that's what I did...
 (Actually, printf was the first thing to get removed :P)

The downside of modifying "object.d" is that you'll end up having a mini-phobos library with only the stuff you need, right? As for your kernel, can I see the source code? :-)
Jan 12 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Marcio Faustino wrote:
 Thanks for all the replies, I think I understand it now.
 
 Frits van Bommel wrote:
 If one is writing a kernel, one probably modifies object.d ;).
 At least, that's what I did...
 (Actually, printf was the first thing to get removed :P)

The downside of modifying "object.d" is that you'll end up having a mini-phobos library with only the stuff you need, right?

That's what happens with any kernel project in any language higher than C (i.e. any language that needs some form of runtime). Though some C compilers may generate implicit memcpy() calls etc., so I guess that counts...
 As for your kernel, can I see the source code? :-)

It doesn't do much of any use currently. It just boots and shows some status messages while initializing the system. Then it just sits there, echoing keyboard input. It doesn't even clean up after itself (no way of freeing allocated memory). I plan on implementing or porting a GC some day, but at the moment it doesn't use enough memory to make it worth freeing. I just think it should be at least marginally functional before I go spreading the source around :).
Jan 12 2007
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
Frits van Bommel wrote:
 
 You're writing forward declarations. Seriously, D doesn't need them; 
 forward references are allowed ;).
 
 A function declaration without definition is for when you put the 
 definition in a different file, not to put it later in the same file.

I think the same conflict can occur in this situation though: module a; extern (C) void fn(); module b; extern (C) void fn(); module c; import a, b; void main() { fn(); } This one has bitten me a few times where I had declared the prototype for a C library routine to avoid importing the entire header module, and a derived module imported both my module and the C header module. Even worse, the same error will occur if one of the two declarations is private, because of how symbol resolution is handled. This makes the approach outlined above completely intractable, and actually more restrictive than C where multiple prototypes of the same function are allowed. Sean
Jan 12 2007
next sibling parent reply Tyler Knott <tywebmail mailcity.com> writes:
Sean Kelly wrote:
 This one has bitten me a few times where I had declared the prototype 
 for a C library routine to avoid importing the entire header module, and 
 a derived module imported both my module and the C header module.  Even 
 worse, the same error will occur if one of the two declarations is 
 private, because of how symbol resolution is handled.  This makes the 
 approach outlined above completely intractable, and actually more 
 restrictive than C where multiple prototypes of the same function are 
 allowed.

What's wrong with importing the entire header module? That's what modules are designed for: avoiding declaring the same function multiple times. They also don't add any code bloat.
Jan 12 2007
parent Sean Kelly <sean f4.ca> writes:
Tyler Knott wrote:
 Sean Kelly wrote:
 This one has bitten me a few times where I had declared the prototype 
 for a C library routine to avoid importing the entire header module, 
 and a derived module imported both my module and the C header module.  
 Even worse, the same error will occur if one of the two declarations 
 is private, because of how symbol resolution is handled.  This makes 
 the approach outlined above completely intractable, and actually more 
 restrictive than C where multiple prototypes of the same function are 
 allowed.

What's wrong with importing the entire header module? That's what modules are designed for: avoiding declaring the same function multiple times. They also don't add any code bloat.

In the past, there were some issues with D where importing even empty modules bloated the executable quite noticeably (I think it was ~500 bytes per empty module). This appeared related to ModuleInfo that was generated apparently regardless of whether it was necessary. I re-tested this recently, however, and was unable to reproduce my old results, so I think this problem has been fixed as a side-effect of other changes. Still, there are some places in my code where I have declarations of C routines rather than imports, as I haven't gone to the trouble of changing them now that this seems to have been resolved. Sean
Jan 12 2007
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Sean Kelly wrote:
 Frits van Bommel wrote:
 You're writing forward declarations. Seriously, D doesn't need them; 
 forward references are allowed ;).

 A function declaration without definition is for when you put the 
 definition in a different file, not to put it later in the same file.

I think the same conflict can occur in this situation though: module a; extern (C) void fn(); module b; extern (C) void fn(); module c; import a, b; void main() { fn(); } This one has bitten me a few times where I had declared the prototype for a C library routine to avoid importing the entire header module, and a derived module imported both my module and the C header module. Even worse, the same error will occur if one of the two declarations is private, because of how symbol resolution is handled. This makes the approach outlined above completely intractable, and actually more restrictive than C where multiple prototypes of the same function are allowed.

You cut that quote a bit short. Reread the rest of that paragraph at the end of your quote. What I was talking about was more in the line of Phobos' object.d & internal/object.d, or a C source file and its D import module. Either way, only one of the files is intended to be imported (but shouldn't get compiled itself). The other file then gets compiled and linked in its place.
Jan 12 2007
parent Sean Kelly <sean f4.ca> writes:
Frits van Bommel wrote:
 
 You cut that quote a bit short. Reread the rest of that paragraph at the 
 end of your quote.
 What I was talking about was more in the line of Phobos' object.d & 
 internal/object.d, or a C source file and its D import module.
 Either way, only one of the files is intended to be imported (but 
 shouldn't get compiled itself). The other file then gets compiled and 
 linked in its place.

Fair enough. I replied mostly because I thought it may be useful to mention a related issue I'd encountered in the past. My apologies if the implication was otherwise. Sean
Jan 12 2007