www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Function prototype + definition in the same file

reply Manu <turkeyman gmail.com> writes:
So I have this recurring pattern, it's really starting to annoy me.
It stems from the fact that a function prototype and the definition can not
appear in the same file in D (as it can in C/C++)
Eg,

void func(int x); // <-- declaration of function, informs type and
associated names, args, ...

//later
void func(int x) // <-- may be generated with magic (and may use the
prototype declaration for type information as declared by the prototype
above)
{
  ... do stuff
}

I really need this. Why is it illegal? Is there chance of having this
supported? What are the problems?

My problem is essentially to do with supporting both static or dynamic
linkage optionally, but it also shows up in situations where I want to
perform comprehensive magic code generation, but want clear-readable user
declarations.
The simplest case:
  I have an extern that I may want to statically or dynamically link.
    In the case of static linkage, one just produces a prototype, and it
links, no problem.
    In the case of dynamic linkage, one must produce a stub for the
function, a function pointer to call through, and perhaps some code to
hook-up the function pointer at init.

I have a fairly comprehensive binding solution which automates the work in
the case of dynamic linkage, but the problem is the way the user defines
the functions that exist in the D code.
I'd like it if the users would just write the prototypes, they'd be easily
readable, simple to create by cutting and pasting straight from C code. And
when statically linking, it would just work, the module hook-up mixin does
nothing in this configuration.
In the case of dynamic linkage, a single hook-up mixin in the file
somewhere could scan the module for these prototypes and generate the
stubs, function pointers, and the boot-up code that would connect them
(while validating their signatures against the extern import table, etc).

This approach isn't supported though. What I do instead:

mixin( ImportFunction!( "functionName", int function( int arg1, float arg2,
ref in SomeStruct arg3 ), "pure nothrow" ) );
mixin( ImportFunction!( "functionName2", int function() ) );
mixin( ImportFunction!( "functionName3", int function( int x, int y ),
"nothrow" ) );
etc etc

These templates produce, from the information provided, either a prototype
for static linkage, or the { stub, func pointer, initialisation info } for
dynamic linkage.

I really don't like doing it this way for a number of reasons:
  *** This results in hundreds of mixins, which quickly lead to intolerable
compile times (to the point where D is losing it's appeal as a viable
choice for our needs). If done my preferred way, I could do the magic with
a single mixin at the bottom of the file.
  * It's barely readable.
  * Much more annoying to write and maintain when the counterpart API
changes, and is more error-prone.
  * IDE features don't work properly; syntax highlighting, hover info,
go-to-definition, etc.

I also have numerous more advanced cases of the same problem, and becomes
even more unsightly when used in structs to emulate dynamic linkage to
static methods of C++ classes.

The solution is seemingly trivial; allow function prototypes and
definitions to exist in the same file, like in C/C++.


Go on, tear me apart... :)
Sep 25 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Manu:

 I have a fairly comprehensive binding solution which automates 
 the work in
 the case of dynamic linkage, but the problem is the way the 
 user defines the functions that exist in the D code.
Maybe there are better ways to solve your problems (even changing D language in some ways), and keep avoiding the need of free floating ghosts of functions. Bye, bearophile
Sep 25 2012
parent Manu <turkeyman gmail.com> writes:
On 25 September 2012 15:21, bearophile <bearophileHUGS lycos.com> wrote:

 Manu:


  I have a fairly comprehensive binding solution which automates the work in
 the case of dynamic linkage, but the problem is the way the user defines
 the functions that exist in the D code.
Maybe there are better ways to solve your problems (even changing D language in some ways), and keep avoiding the need of free floating ghosts of functions.
Can you suggest a more direct approach? Declaring prototypes seems completely natural, supports all the expected IDE features, and in the simple/common case (static linkage) requires absolutely no magic voodoo.
Sep 25 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 25 Sep 2012 07:53:17 -0400, Manu <turkeyman gmail.com> wrote:

 So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can  
 not
 appear in the same file in D (as it can in C/C++)
Doing this is not illegal.
 Eg,

 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
   ... do stuff
 }
This compiles. Do you have a better case to show the problem? -Steve
Sep 25 2012
parent reply Manu <turkeyman gmail.com> writes:
On 25 September 2012 17:25, Steven Schveighoffer <schveiguy yahoo.com>wrote:

 On Tue, 25 Sep 2012 07:53:17 -0400, Manu <turkeyman gmail.com> wrote:

  So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not
 appear in the same file in D (as it can in C/C++)
Doing this is not illegal. Eg,
 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
   ... do stuff
 }
This compiles. Do you have a better case to show the problem?
void blah(); void blah() { int x = 0; } void f() { blah(); // <- call it } W:\project\main\sourcedata\plugins\remedy\modules\test_module.d(38):Error: function remedy.testmodule.blah called with argument types: (()) matches both: remedy.testmodule.blah() and: remedy.testmodule.blah() Obviously, one is just a prototype, and the symbol is resolved within the local file.
Sep 25 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 25 Sep 2012 10:40:41 -0400, Manu <turkeyman gmail.com> wrote:

 On 25 September 2012 17:25, Steven Schveighoffer  
 <schveiguy yahoo.com>wrote:

 On Tue, 25 Sep 2012 07:53:17 -0400, Manu <turkeyman gmail.com> wrote:

  So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not
 appear in the same file in D (as it can in C/C++)
Doing this is not illegal. Eg,
 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
   ... do stuff
 }
This compiles. Do you have a better case to show the problem?
void blah(); void blah() { int x = 0; } void f() { blah(); // <- call it } W:\project\main\sourcedata\plugins\remedy\modules\test_module.d(38):Error: function remedy.testmodule.blah called with argument types: (()) matches both: remedy.testmodule.blah() and: remedy.testmodule.blah()
Oh, that is funny. I simply compiled the functions and didn't call them, assuming if that compiled it was legal. This is definitely a bug. In fact you can implement a function *twice* and this isn't an error. Check this out: testme2.d: module testme2; import std.stdio; void foo() { writeln("first"); } void foo() { writeln("second"); } testme2.di: module testme2; void foo(); testme.d: import testme2; void main() { foo(); } Compile like this: dmd -c testme2.d dmd testme.d testme2.o links, and when I run, it displays: first So clearly there isn't something right here, that should definitely be an error. I think there are two errors here. First, the spec does not say you cannot prototype a function before declaring it. All it says is: Functions without bodies: int foo(); that are not declared as abstract are expected to have their implementations elsewhere, and that implementation will be provided at the link step. This enables an implementation of a function to be completely hidden from the user of it, and the implementation may be in another language such as C, assembler, etc. from: http://dlang.org/function.html I don't see any rules that would preclude pre-declaring a prototype, even if it's not promoted to do this (after all, forward references should always work, right?). Second, you should not be able to compile two identically prototyped functions with bodies into an object file, I have no idea how that even works. -Steve
Sep 25 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-09-25 13:53, Manu wrote:

 I really don't like doing it this way for a number of reasons:
    *** This results in hundreds of mixins, which quickly lead to
 intolerable compile times (to the point where D is losing it's appeal as
 a viable choice for our needs). If done my preferred way, I could do the
 magic with a single mixin at the bottom of the file.
I guess you already figured this out but a single mixin with a lot of code is a lot faster than several mixins with little code. Although this will decrease the readability even further. -- /Jacob Carlborg
Sep 25 2012
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 25/09/2012 13:53, Manu a écrit :
 So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not appear in the same file in D (as it can in C/C++)
 Eg,

 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
    ... do stuff
 }

 I really need this. Why is it illegal? Is there chance of having this
 supported? What are the problems?

 My problem is essentially to do with supporting both static or dynamic
 linkage optionally, but it also shows up in situations where I want to
 perform comprehensive magic code generation, but want clear-readable
 user declarations.
 The simplest case:
    I have an extern that I may want to statically or dynamically link.
      In the case of static linkage, one just produces a prototype, and
 it links, no problem.
      In the case of dynamic linkage, one must produce a stub for the
 function, a function pointer to call through, and perhaps some code to
 hook-up the function pointer at init.

 I have a fairly comprehensive binding solution which automates the work
 in the case of dynamic linkage, but the problem is the way the user
 defines the functions that exist in the D code.
 I'd like it if the users would just write the prototypes, they'd be
 easily readable, simple to create by cutting and pasting straight from C
 code. And when statically linking, it would just work, the module
 hook-up mixin does nothing in this configuration.
 In the case of dynamic linkage, a single hook-up mixin in the file
 somewhere could scan the module for these prototypes and generate the
 stubs, function pointers, and the boot-up code that would connect them
 (while validating their signatures against the extern import table, etc).

 This approach isn't supported though. What I do instead:

 mixin( ImportFunction!( "functionName", int function( int arg1, float
 arg2, ref in SomeStruct arg3 ), "pure nothrow" ) );
 mixin( ImportFunction!( "functionName2", int function() ) );
 mixin( ImportFunction!( "functionName3", int function( int x, int y ),
 "nothrow" ) );
 etc etc

 These templates produce, from the information provided, either a
 prototype for static linkage, or the { stub, func pointer,
 initialisation info } for dynamic linkage.

 I really don't like doing it this way for a number of reasons:
    *** This results in hundreds of mixins, which quickly lead to
 intolerable compile times (to the point where D is losing it's appeal as
 a viable choice for our needs). If done my preferred way, I could do the
 magic with a single mixin at the bottom of the file.
    * It's barely readable.
    * Much more annoying to write and maintain when the counterpart API
 changes, and is more error-prone.
    * IDE features don't work properly; syntax highlighting, hover info,
 go-to-definition, etc.

 I also have numerous more advanced cases of the same problem, and
 becomes even more unsightly when used in structs to emulate dynamic
 linkage to static methods of C++ classes.

 The solution is seemingly trivial; allow function prototypes and
 definitions to exist in the same file, like in C/C++.


 Go on, tear me apart... :)
This is code duplication and is generally considered as a bad practice. I'm not convinced that the language should be modified to allow something that is known as bad practice. What you need here is a more robust di generator IMO.
Sep 25 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Tuesday, 25 September 2012 at 17:48:46 UTC, deadalnix wrote:
 This is code duplication and is generally considered as a bad 
 practice. I'm not convinced that the language should be 
 modified to allow something that is known as bad practice.

 What you need here is a more robust di generator IMO.
This is neither a code duplication (there is certain distinction between prototype and body) nor a bad practice - this is a common pattern in C and C++. It is surprising that D cannot do such a simple thing which in addition is not harmless, so there is no sense in depreciating it.
Sep 25 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 25/09/2012 20:57, Maxim Fomin a écrit :
 On Tuesday, 25 September 2012 at 17:48:46 UTC, deadalnix wrote:
 This is code duplication and is generally considered as a bad
 practice. I'm not convinced that the language should be modified to
 allow something that is known as bad practice.

 What you need here is a more robust di generator IMO.
This is neither a code duplication (there is certain distinction between prototype and body) nor a bad practice - this is a common pattern in C and C++. It is surprising that D cannot do such a simple thing which in addition is not harmless, so there is no sense in depreciating it.
This is code duplication. And this has been considered a problem in C/C++ for a while now.
Sep 25 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 25 Sep 2012 15:23:50 -0400, deadalnix <deadalnix gmail.com> wrot=
e:

 Le 25/09/2012 20:57, Maxim Fomin a =C3=A9crit :
 On Tuesday, 25 September 2012 at 17:48:46 UTC, deadalnix wrote:
 This is code duplication and is generally considered as a bad
 practice. I'm not convinced that the language should be modified to
 allow something that is known as bad practice.

 What you need here is a more robust di generator IMO.
This is neither a code duplication (there is certain distinction betw=
een
 prototype and body) nor a bad practice - this is a common pattern in =
C
 and C++. It is surprising that D cannot do such a simple thing which =
in
 addition is not harmless, so there is no sense in depreciating it.
This is code duplication. And this has been considered a problem in =
 C/C++ for a while now.
No, it's a prototype. Note that it's *required* if you want to hide implementation using .di = files. There is no code involved, it's just generating a symbol reference in th= e = object file. -Steve
Sep 25 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, September 25, 2012 15:48:11 Steven Schveighoffer wrote:
 On Tue, 25 Sep 2012 15:23:50 -0400, deadalnix <deadalnix gmail.com> wrote:
 Le 25/09/2012 20:57, Maxim Fomin a écrit :
 On Tuesday, 25 September 2012 at 17:48:46 UTC, deadalnix wrote:
 This is code duplication and is generally considered as a bad
 practice. I'm not convinced that the language should be modified to
 allow something that is known as bad practice.
 
 What you need here is a more robust di generator IMO.
This is neither a code duplication (there is certain distinction between prototype and body) nor a bad practice - this is a common pattern in C and C++. It is surprising that D cannot do such a simple thing which in addition is not harmless, so there is no sense in depreciating it.
This is code duplication. And this has been considered a problem in C/C++ for a while now.
No, it's a prototype. Note that it's *required* if you want to hide implementation using .di files. There is no code involved, it's just generating a symbol reference in the object file.
It's still code duplication, because you've now listed the function signature twice. Yes, it's minimal code duplication, but it's still duplicating code. It's necessary for stuff like .di files (which are code duplication by definition, because they're duplicating a module - or at least part of it), but most everyone I know has thought (where it's come anyway) that prototypes were a _bad_ thing about C/C++. So, eliminating them as much as possible would generally be good, and even when it comes to .di files, given their limitations (e.g. disabling inlining and CTFE), we arguably should have a better solution for interface files anyway (e.g. having a binary file with the partially compiled code and generated documentation alongside it giving the API), in which case we wouldn't even need prototypes for interface files anymore. If anything, I'd argue that the fact that prototypes are part of the language is a sign of a deficiency in the language (especially if they're necessary). - Jonathan M Davis
Sep 25 2012
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 25 Sep 2012 16:07:51 -0400, Jonathan M Davis <jmdavisProg gmx.co=
m>  =

wrote:

 On Tuesday, September 25, 2012 15:48:11 Steven Schveighoffer wrote:
 On Tue, 25 Sep 2012 15:23:50 -0400, deadalnix <deadalnix gmail.com>  =
 wrote:
 Le 25/09/2012 20:57, Maxim Fomin a =C3=A9crit :
 On Tuesday, 25 September 2012 at 17:48:46 UTC, deadalnix wrote:
 This is code duplication and is generally considered as a bad
 practice. I'm not convinced that the language should be modified =
to
 allow something that is known as bad practice.

 What you need here is a more robust di generator IMO.
This is neither a code duplication (there is certain distinction =
 between
 prototype and body) nor a bad practice - this is a common pattern =
in =
 C
 and C++. It is surprising that D cannot do such a simple thing whi=
ch =
 in
 addition is not harmless, so there is no sense in depreciating it.=
 This is code duplication. And this has been considered a problem in=
 C/C++ for a while now.
No, it's a prototype. Note that it's *required* if you want to hide implementation using .d=
i
 files.

 There is no code involved, it's just generating a symbol reference in=
=
 the
 object file.
It's still code duplication, because you've now listed the function =
 signature
 twice. Yes, it's minimal code duplication, but it's still duplicating =
=
 code.
I misunderstood, I was thinking in terms of generated code. But in any case, it's still not duplicated code. What you are doing is = = defining an interface, then attaching the implementation of the interfac= e = to the declaration by repeating its name. Would you say repeating the function signature of an interface in an = implementing class is code duplication? Would you say that typing the = name of a variable that you already declared so you could access it is = code duplication? Duplicated or not, it's still valid under the spec as far as I can tell.=
 It's necessary for stuff like .di files (which are code duplication by=
 definition, because they're duplicating a module - or at least part of=
=
 it), but
 most everyone I know has thought (where it's come anyway) that  =
 prototypes were
 a _bad_ thing about C/C++.
The main reason for having prototypes in C/C++ was so you could declare = a = symbol that you weren't defining yet. In some cases, this was necessary, because C/C++ does not have forward = references. So there is indeed very little reason in D to declare a = function, then implement it in the same file. But I think what Manu is trying to do is not exactly just "repeat the = signature", he is using the signature of the original to generate the = signature of the auto-generated function. Essentially, it's not = duplicated code on either the source or the compiled level, so disabling= = the ability to declare a function and then implement it later would = prevent this possibility. I don't think it makes sense to do that. -Steve
Sep 25 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 25/09/2012 22:43, Steven Schveighoffer a écrit :
 But I think what Manu is trying to do is not exactly just "repeat the
 signature", he is using the signature of the original to generate the
 signature of the auto-generated function. Essentially, it's not
 duplicated code on either the source or the compiled level, so disabling
 the ability to declare a function and then implement it later would
 prevent this possibility. I don't think it makes sense to do that.
This is why I suggested to improve the di generator instead of allowing that in the language in a first place.
Sep 26 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-09-25 22:07, Jonathan M Davis wrote:

 I'd argue that the fact that prototypes are part of the language is
 a sign of a deficiency in the language (especially if they're necessary).
They're necessary for linking with C functions. But except from that I agree with you. -- /Jacob Carlborg
Sep 25 2012
prev sibling next sibling parent "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
On Tuesday, 25 September 2012 at 11:52:38 UTC, Manu wrote:
 So I have this recurring pattern, it's really starting to annoy 
 me.
 It stems from the fact that a function prototype and the 
 definition can not
 appear in the same file in D (as it can in C/C++)
 [...]
 Go on, tear me apart... :)
I'm not sure I understand what benefit you are giving, I'll explain a situation I went through. tldr: I like having a clean "header" file for static linking. It would be nice to build off that to dynamically link. I wanted to load up a DLL (C++ with C interface). Found this nifty file on stackoverflow http://stackoverflow.com/questions/3818229/loading-plugins-dlls-on-the-fly Didn't want to write all those mixins myself. I already had the "header" file for my DLL and didn't want to write all those mixins. I created an array with all the function names, then created a function which took iterated this array and asked for the function type as I'd imported the "header." I ran into a bunch of runtime errors with this setup, probably didn't like the duplication of function names. Or something completely different. Finally I went to static linking. Since I had a nice clean header I didn't need to do anything fancy, pragma(lib) my .lib file and disable the defFunctions mixin.
Sep 25 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/25/2012 01:53 PM, Manu wrote:
 So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not appear in the same file in D (as it can in C/C++)
 Eg,

 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
    ... do stuff
 }

 I really need this. Why is it illegal? Is there chance of having this
 supported? What are the problems?
 ...
It is illegal because nobody has written code to support it. It should be possible to support it. I don't think there are any problems with the concept.
Sep 25 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/26/2012 01:29 AM, Timon Gehr wrote:
 On 09/25/2012 01:53 PM, Manu wrote:
 So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not appear in the same file in D (as it can in C/C++)
 Eg,

 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
    ... do stuff
 }

 I really need this. Why is it illegal? Is there chance of having this
 supported? What are the problems?
 ...
It is illegal because nobody has written code to support it. It should be possible to support it. I don't think there are any problems with the concept.
(The implementation faces some challenges, the following is easy to get wrong: module module_; void foo(); alias foo alias1; static if(is(typeof(alias1))){ void foo(){} alias foo alias2; } static assert(__traits(isSame, alias1, alias2)); static assert(__traits(allMembers, module_).length == 3); // 2 alias, 1 function definition )
Sep 25 2012
parent reply Manu <turkeyman gmail.com> writes:
On 26 September 2012 02:35, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 09/26/2012 01:29 AM, Timon Gehr wrote:

 On 09/25/2012 01:53 PM, Manu wrote:

 So I have this recurring pattern, it's really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not appear in the same file in D (as it can in C/C++)
 Eg,

 void func(int x); // <-- declaration of function, informs type and
 associated names, args, ...

 //later
 void func(int x) // <-- may be generated with magic (and may use the
 prototype declaration for type information as declared by the prototype
 above)
 {
    ... do stuff
 }

 I really need this. Why is it illegal? Is there chance of having this
 supported? What are the problems?
 ...
It is illegal because nobody has written code to support it. It should be possible to support it. I don't think there are any problems with the concept.
(The implementation faces some challenges, the following is easy to get wrong: module module_; void foo(); alias foo alias1; static if(is(typeof(alias1))){ void foo(){} alias foo alias2; } static assert(__traits(isSame, alias1, alias2)); static assert(__traits(allMembers, module_).length == 3); // 2 alias, 1 function definition )
I'm not sure I understand the point being illustrated here. I don't see how the aliases are relevant? Is an alias to a prototype somehow different than an alias to a definition? Shouldn't the discovery of a function definition within the same file as a pre-declared prototype just promote the prototype to a full definition? They are the same symbol, just that one instance adds the definition.
Sep 26 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 26/09/2012 10:14, Manu a écrit :
 On 26 September 2012 02:35, Timon Gehr <timon.gehr gmx.ch
 <mailto:timon.gehr gmx.ch>> wrote:

     On 09/26/2012 01:29 AM, Timon Gehr wrote:

         On 09/25/2012 01:53 PM, Manu wrote:

             So I have this recurring pattern, it's really starting to
             annoy me.
             It stems from the fact that a function prototype and the
             definition can
             not appear in the same file in D (as it can in C/C++)
             Eg,

             void func(int x); // <-- declaration of function, informs
             type and
             associated names, args, ...

             //later
             void func(int x) // <-- may be generated with magic (and may
             use the
             prototype declaration for type information as declared by
             the prototype
             above)
             {
                 ... do stuff
             }

             I really need this. Why is it illegal? Is there chance of
             having this
             supported? What are the problems?
             ...


         It is illegal because nobody has written code to support it. It
         should be possible to support it. I don't think there are any
         problems
         with the concept.


     (The implementation faces some challenges, the following is easy to
     get wrong:

     module module_;

     void foo();

     alias foo alias1;
     static if(is(typeof(alias1))){
          void foo(){}
          alias foo alias2;
     }

     static assert(__traits(isSame, alias1, alias2));
     static assert(__traits(allMembers, module_).length == 3); // 2
     alias, 1 function definition
     )


 I'm not sure I understand the point being illustrated here. I don't see
 how the aliases are relevant?
From a compiler perspective, the example above is hell. That was his point. In other terms, supporting such a feature add complexity to the compiler, and it should come with a sufficient benefice to make sense to implement.
Sep 26 2012
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 26 September 2012 13:09, deadalnix <deadalnix gmail.com> wrote:

 Le 26/09/2012 10:14, Manu a =C3=A9crit :

 On 26 September 2012 02:35, Timon Gehr <timon.gehr gmx.ch
 <mailto:timon.gehr gmx.ch>> wrote:

     On 09/26/2012 01:29 AM, Timon Gehr wrote:

         On 09/25/2012 01:53 PM, Manu wrote:

             So I have this recurring pattern, it's really starting to
             annoy me.
             It stems from the fact that a function prototype and the
             definition can
             not appear in the same file in D (as it can in C/C++)
             Eg,

             void func(int x); // <-- declaration of function, informs
             type and
             associated names, args, ...

             //later
             void func(int x) // <-- may be generated with magic (and may
             use the
             prototype declaration for type information as declared by
             the prototype
             above)
             {
                 ... do stuff
             }

             I really need this. Why is it illegal? Is there chance of
             having this
             supported? What are the problems?
             ...


         It is illegal because nobody has written code to support it. It
         should be possible to support it. I don't think there are any
         problems
         with the concept.


     (The implementation faces some challenges, the following is easy to
     get wrong:

     module module_;

     void foo();

     alias foo alias1;
     static if(is(typeof(alias1))){
          void foo(){}
          alias foo alias2;
     }

     static assert(__traits(isSame, alias1, alias2));
     static assert(__traits(allMembers, module_).length =3D=3D 3); // 2
     alias, 1 function definition
     )


 I'm not sure I understand the point being illustrated here. I don't see
 how the aliases are relevant?
From a compiler perspective, the example above is hell. That was his poin=
t.
 In other terms, supporting such a feature add complexity to the compiler,
 and it should come with a sufficient benefice to make sense to implement.
I can't imagine why the example above is hell, but I know nothing about the compiler. I have no idea how the existing bug was implemented, but it needs to be fixed one way or another. It sounds fairly trivial to me to promote a prototype to a definition if a definition is found later in the same module.
Sep 26 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-09-26 12:19, Manu wrote:

 I can't imagine why the example above is hell, but I know nothing about
 the compiler.

 I have no idea how the existing bug was implemented, but it needs to be
 fixed one way or another.
 It sounds fairly trivial to me to promote a prototype to a definition if
 a definition is found later in the same module.
If the definition is found first, just ignore the prototype? -- /Jacob Carlborg
Sep 26 2012
parent Manu <turkeyman gmail.com> writes:
On 26 September 2012 14:21, Jacob Carlborg <doob me.com> wrote:

 On 2012-09-26 12:19, Manu wrote:

  I can't imagine why the example above is hell, but I know nothing about
 the compiler.

 I have no idea how the existing bug was implemented, but it needs to be
 fixed one way or another.
 It sounds fairly trivial to me to promote a prototype to a definition if
 a definition is found later in the same module.
If the definition is found first, just ignore the prototype?
Indeed.
Sep 26 2012
prev sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 26 September 2012 at 10:09:14 UTC, deadalnix wrote:
 In other terms, supporting such a feature add complexity to the 
 compiler, and it should come with a sufficient benefice to make 
 sense to implement.
It seems to be just opposite: creating ambiguity between function body and its declaration is a language complexity.
Sep 26 2012
prev sibling parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 25.09.2012 13:53, Manu wrote:> So I have this recurring pattern, it's 
really starting to annoy me.
 It stems from the fact that a function prototype and the definition can
 not appear in the same file in D (as it can in C/C++)
 Eg,
[...]
 I also have numerous more advanced cases of the same problem, and
 becomes even more unsightly when used in structs to emulate dynamic
 linkage to static methods of C++ classes.

 The solution is seemingly trivial; allow function prototypes and
 definitions to exist in the same file, like in C/C++.
I think this should be allowed, aswell as implementing forward declared enums and structs (IIRC the compiler even has some error messages that suggest that it is intended). As a workaround, you could put your prototypes into a struct and generate the declarations for the static linking and the stubs for dynamic linking from their declarations and run your magic on the members of "prototypes": struct prototypes { void fun1(int a, int b); void fun2(int a, int b); } mixin(magic([__traits(allMembers, prototypes)]) That way you don't put the symbols into the same scope as the prototypes, and you will not add new symbols to the same scope that you are iterating over.
Sep 26 2012
parent Manu <turkeyman gmail.com> writes:
On 26 September 2012 20:28, Rainer Schuetze <r.sagitario gmx.de> wrote:

 I think this should be allowed, aswell as implementing forward declared
 enums and structs (IIRC the compiler even has some error messages that
 suggest that it is intended).

 As a workaround, you could put your prototypes into a struct and generate
 the declarations for the static linking and the stubs for dynamic linking
 from their declarations and run your magic on the members of "prototypes":

 struct prototypes
 {
         void fun1(int a, int b);
         void fun2(int a, int b);
 }

 mixin(magic([__traits(**allMembers, prototypes)])


 That way you don't put the symbols into the same scope as the prototypes,
 and you will not add new symbols to the same scope that you are iterating
 over.
Good idea! I'll give that a shot. So it seems like there is fairly general consensus on this then, is there a next step? Should I log a bug? (I think I did log one months ago)
Sep 27 2012