www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - C style 'static' functions

reply John Burton <john.burton jbmail.com> writes:
In C I can declare a function 'static' and it's only visible from 
within that implementation file. So I can have a static function 
'test' in code1.c and another non static function 'test' in 
utils.c and assuming a suitable prototype I can use 'test' in my 
program and the one in code1.c will not interfere.

In D it seems that declaring functions as static in a module does 
not affect visibility outside of a module. So if I declare a 
static function in one module with a specific name that is just 
used in internally for the implementation, and then define a 
function with the same name in another module that is intended to 
by 'exported' then in my main program they still conflict and I 
have to take steps to avoid this.

It looked as if I could use 'private' instead of static but 
although this prevents me from calling the "private" function, it 
still conflicts with the one I want to call.

In C++ I could use static or an anonymous namespace for 
implementation functions, but there doesn't seem to be anything 
similar in D.
Is there any way to achieve what I want in D (Private 
implementation functions)
Jul 19
next sibling parent reply Gary Willoughby <dev nomad.so> writes:
On Wednesday, 19 July 2017 at 07:22:48 UTC, John Burton wrote:
 In C++ I could use static or an anonymous namespace for 
 implementation functions, but there doesn't seem to be anything 
 similar in D.
 Is there any way to achieve what I want in D (Private 
 implementation functions)
Try the package keyword: https://dlang.org/spec/attribute.html#visibility_attributes
Jul 19
parent John Burton <john.burton jbmail.com> writes:
On Wednesday, 19 July 2017 at 07:51:11 UTC, Gary Willoughby wrote:
 On Wednesday, 19 July 2017 at 07:22:48 UTC, John Burton wrote:
 In C++ I could use static or an anonymous namespace for 
 implementation functions, but there doesn't seem to be 
 anything similar in D.
 Is there any way to achieve what I want in D (Private 
 implementation functions)
Try the package keyword: https://dlang.org/spec/attribute.html#visibility_attributes
This appears to still have the same issue. I can't use the "package" function in the main program but it still conflicts with the one I can use from a different module. Unless I'm doing it wrong...
Jul 19
prev sibling next sibling parent EnterYourNameHere <myaddress email.com> writes:
On Wednesday, 19 July 2017 at 07:22:48 UTC, John Burton wrote:
 In C I can declare a function 'static' and it's only visible 
 from within that implementation file. So I can have a static 
 function 'test' in code1.c and another non static function 
 'test' in utils.c and assuming a suitable prototype I can use 
 'test' in my program and the one in code1.c will not interfere.

 In D it seems that declaring functions as static in a module 
 does not affect visibility outside of a module.
Indeed, static is not a visibility attribute and for a free function static is mostly a no-op. So far i've only seen a meaningful static free func once and it was used as template value parameter.
 So if I declare a static function in one module with a specific 
 name that is just used in internally for the implementation, 
 and then define a function with the same name in another module 
 that is intended to by 'exported' then in my main program they 
 still conflict and I have to take steps to avoid this.

 It looked as if I could use 'private' instead of static but 
 although this prevents me from calling the "private" function, 
 it still conflicts with the one I want to call.

 In C++ I could use static or an anonymous namespace for 
 implementation functions, but there doesn't seem to be anything 
 similar in D.
 Is there any way to achieve what I want in D (Private 
 implementation functions)
If what you want is an overload that has the same signature, which is not really possible, then you'd rather use a function template: enum Internal { no, yes } void foo(Internal Itr = Internal.no)() { static if (Itr) {} else {} } That should do the trick, although i don't know the context.
Jul 19
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-07-19 09:22, John Burton wrote:
 In C I can declare a function 'static' and it's only visible from within 
 that implementation file. So I can have a static function 'test' in 
 code1.c and another non static function 'test' in utils.c and assuming a 
 suitable prototype I can use 'test' in my program and the one in code1.c 
 will not interfere.
 
 In D it seems that declaring functions as static in a module does not 
 affect visibility outside of a module. So if I declare a static function 
 in one module with a specific name that is just used in internally for 
 the implementation, and then define a function with the same name in 
 another module that is intended to by 'exported' then in my main program 
 they still conflict and I have to take steps to avoid this.
 
 It looked as if I could use 'private' instead of static but although 
 this prevents me from calling the "private" function, it still conflicts 
 with the one I want to call.
 
 In C++ I could use static or an anonymous namespace for implementation 
 functions, but there doesn't seem to be anything similar in D.
 Is there any way to achieve what I want in D (Private implementation 
 functions)
I think it would be easier if you provide a small code example of what you want to achieve. -- /Jacob Carlborg
Jul 19
parent reply John Burton <john.burton jbmail.com> writes:
On Wednesday, 19 July 2017 at 11:31:32 UTC, Jacob Carlborg wrote:
 On 2017-07-19 09:22, John Burton wrote:
 In C I can declare a function 'static' and it's only visible 
 from within that implementation file. So I can have a static 
 function 'test' in code1.c and another non static function 
 'test' in utils.c and assuming a suitable prototype I can use 
 'test' in my program and the one in code1.c will not interfere.
 
 In D it seems that declaring functions as static in a module 
 does not affect visibility outside of a module. So if I 
 declare a static function in one module with a specific name 
 that is just used in internally for the implementation, and 
 then define a function with the same name in another module 
 that is intended to by 'exported' then in my main program they 
 still conflict and I have to take steps to avoid this.
 
 It looked as if I could use 'private' instead of static but 
 although this prevents me from calling the "private" function, 
 it still conflicts with the one I want to call.
 
 In C++ I could use static or an anonymous namespace for 
 implementation functions, but there doesn't seem to be 
 anything similar in D.
 Is there any way to achieve what I want in D (Private 
 implementation functions)
I think it would be easier if you provide a small code example of what you want to achieve.
Here is an artificial example of what I mean. The point is that I can break main.d from compiling by adding what is meant to be a purely internal implementation detail inside of lib1. - In C I can make internal functions static to avoid this... Im D, none of static, package, private etc seem to do this. They prevent it from being called but don't hide the existence of the function from the module importing it. If there is no way to achieve this it's not a big problem, I'm just curious now :) ---- lib1.d ---- private void init() { // init function used only as an implementation detail } void mything() { init(); } ---- lib2.d ----- void init() { // init function meant to be used as part of the module interface } ---- main.d ---- import lib1; import lib2; void main() { init(); // This is meant to call lib2.init because it's the only // function of that name. lib1.init() is supposed to be // an entirely internal implementation detail of lib1 // Even though I can't call lib1.init() because it's private // this call still shows up as ambigous. // // In C I'd write "static void init()" in lib1.d to indicate // that the function was entirely local to that file. However static // does not appear to have that same effect in D }
Jul 19
next sibling parent reply Kagamin <spam here.lot> writes:
Try a newer compiler, this was fixed recently.
Jul 19
parent reply John Burton <john.burton jbmail.com> writes:
On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Jul 19
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 19 July 2017 at 12:11:38 UTC, John Burton wrote:
 On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Ah, great!
Jul 19
parent reply John Burton <john.burton jbmail.com> writes:
On Wednesday, 19 July 2017 at 12:15:05 UTC, Mike Parker wrote:
 On Wednesday, 19 July 2017 at 12:11:38 UTC, John Burton wrote:
 On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Ah, great!
Looks like it's https://wiki.dlang.org/DIP22 that changed this
Jul 19
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 19 July 2017 at 12:16:46 UTC, John Burton wrote:

 Looks like it's https://wiki.dlang.org/DIP22 that changed this
Specifically, it was fixed in DMD 2.071.0 released in April of last year: http://dlang.org/changelog/2.071.0.html#dip22
Jul 19
prev sibling next sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Wednesday, 19 July 2017 at 12:11:38 UTC, John Burton wrote:
 On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Just for the record, private is the analog of C's static. All private free and member functions are callable only from the module they are defined in. This is in contrast with C++, Java, C# where private members are visible only the class they are defined in.
Jul 19
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/19/17 8:16 AM, Petar Kirov [ZombineDev] wrote:
 On Wednesday, 19 July 2017 at 12:11:38 UTC, John Burton wrote:
 On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Just for the record, private is the analog of C's static. All private free and member functions are callable only from the module they are defined in. This is in contrast with C++, Java, C# where private members are visible only the class they are defined in.
I'm not so sure of that. Private functions still generate symbols. I think in C, there is no symbol (at least in the object file) for static functions or variables. You could still call a private function in a D module via the mangled name I believe. -Steve Note: not 100% sure of all this, but this is always the way I've looked at it.
Jul 19
next sibling parent Johannes Pfau <nospam example.com> writes:
On Wednesday, 19 July 2017 at 15:28:50 UTC, Steven Schveighoffer 
wrote:
 On 7/19/17 8:16 AM, Petar Kirov [ZombineDev] wrote:
 On Wednesday, 19 July 2017 at 12:11:38 UTC, John Burton wrote:
 On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Just for the record, private is the analog of C's static. All private free and member functions are callable only from the module they are defined in. This is in contrast with C++, Java, C# where private members are visible only the class they are defined in.
I'm not so sure of that. Private functions still generate symbols. I think in C, there is no symbol (at least in the object file) for static functions or variables. You could still call a private function in a D module via the mangled name I believe. -Steve Note: not 100% sure of all this, but this is always the way I've looked at it.
That's correct. We unfortunately can't do certain optimizations because of this (executable size related: removing unused or inlined only functions, ...). The reason we can't make private functions object local are templates. A public template can access private functions, but the template instance may be emitted to another object. And as templates can't be checzked speculatively we don't even know if there's a template accessing a private function. Dlls on Windows face a similar problem. Once we get the export templates proposed in earlier Dll discussions we can make non-exported, private functions object local.
Jul 19
prev sibling next sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Wednesday, 19 July 2017 at 15:28:50 UTC, Steven Schveighoffer 
wrote:
 On 7/19/17 8:16 AM, Petar Kirov [ZombineDev] wrote:
 On Wednesday, 19 July 2017 at 12:11:38 UTC, John Burton wrote:
 On Wednesday, 19 July 2017 at 12:05:09 UTC, Kagamin wrote:
 Try a newer compiler, this was fixed recently.
Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd not realized this machine had not been updated. Sorry for wasting everyones' time if that's so, and thanks for the help.
Just for the record, private is the analog of C's static. All private free and member functions are callable only from the module they are defined in. This is in contrast with C++, Java, C# where private members are visible only the class they are defined in.
I'm not so sure of that. Private functions still generate symbols. I think in C, there is no symbol (at least in the object file) for static functions or variables. You could still call a private function in a D module via the mangled name I believe. -Steve Note: not 100% sure of all this, but this is always the way I've looked at it.
You're probably right about the current implementation, but I was talking about the intended semantics. I believe that with DIP45, only functions and global variables annotated with the export storage class would necessary have externally visible symbols. Also, consider this enhancement request (which I think Walter and Andrei approve of) - https://issues.dlang.org/show_bug.cgi?id=13567 - which would be doable only if private functions don't have externally visible symbols. See also: https://issues.dlang.org/show_bug.cgi?id=9893.
Jul 19
parent reply Johannes Pfau <nospam example.com> writes:
Am Wed, 19 Jul 2017 17:25:18 +0000
schrieb Petar Kirov [ZombineDev] <petar.p.kirov gmail.com>:


 Note: not 100% sure of all this, but this is always the way 
 I've looked at it.  
You're probably right about the current implementation, but I was talking about the intended semantics. I believe that with DIP45, only functions and global variables annotated with the export storage class would necessary have externally visible symbols.
Yes, this DIP is the solution to have true C-like static functions. Non-exported private will then be equivalent to C static.
 Also, consider this enhancement request (which I think Walter and 
 Andrei approve of) - 
 https://issues.dlang.org/show_bug.cgi?id=13567 - which would be 
 doable only if private functions don't have externally visible 
 symbols.
Can you explain why _object-level visibility_ would matter in this case? -- Johannes
Jul 19
parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Wednesday, 19 July 2017 at 18:49:32 UTC, Johannes Pfau wrote:
 Can you explain why _object-level visibility_ would matter in 
 this case?
(I'm sure you have more experience with shared libraries than me, so correct me if I'm wrong) We can't do attribute inference for exported functions because changing the function body may easily change the function signature (-> name mangling) and break clients of the (shared) library. Therefore, it follows that attribute inference can only be done for non-exported functions.
Jul 19
parent Johannes Pfau <nospam example.com> writes:
Am Wed, 19 Jul 2017 19:18:03 +0000
schrieb Petar Kirov [ZombineDev] <petar.p.kirov gmail.com>:

 On Wednesday, 19 July 2017 at 18:49:32 UTC, Johannes Pfau wrote:
 Can you explain why _object-level visibility_ would matter in 
 this case?  
(I'm sure you have more experience with shared libraries than me, so correct me if I'm wrong) We can't do attribute inference for exported functions because changing the function body may easily change the function signature (-> name mangling) and break clients of the (shared) library. Therefore, it follows that attribute inference can only be done for non-exported functions.
OK, I didn't think of the stable ABI argument, that indeed does make sense. Leads to the strange consequence though that private functions called from templates need to be exported and therefore can't use inference. OT: if a function private function is exported and called from a public template things are difficult either way. Such a function needs to be considered to be 'logically' public: As the template code instantiated in another library will not get updated when you update the library with the private function, you also have to ensure that the program logic is still valid when mixing a new implementation of the private function and an old implementation of the template function.... -- Johannes
Jul 19
prev sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 19 July 2017 at 15:28:50 UTC, Steven Schveighoffer 
wrote:
 I'm not so sure of that. Private functions still generate 
 symbols. I think in C, there is no symbol (at least in the 
 object file) for static functions or variables.
They generate hidden symbols. That's just how it implements private functions in C: you can't do anything else without mangling. You probably can't compile two C units into one object file if they have static functions with the same name - this would require mangling to make two symbols different.
Jul 19
parent Johannes Pfau <nospam example.com> writes:
Am Wed, 19 Jul 2017 17:37:48 +0000
schrieb Kagamin <spam here.lot>:

 On Wednesday, 19 July 2017 at 15:28:50 UTC, Steven Schveighoffer 
 wrote:
 I'm not so sure of that. Private functions still generate 
 symbols. I think in C, there is no symbol (at least in the 
 object file) for static functions or variables.  
They generate hidden symbols. That's just how it implements private functions in C: you can't do anything else without mangling.
This is not entirely correct. The symbols are local symbols in elf terminology, so local to an object file. Hidden symbols are local to an executable or shared library.
 You probably can't compile two C units into one object 
 file if they have static functions with the same name - this 
 would require mangling to make two symbols different.
1) C does have mangling for static variables: void foo() {static int x;} ==> .local x.1796 2) Object file? No, but you cant compile two translation units into one object file anyway or declare two functions with the same name in one translation file. For executables and libraries, ELF takes care of this. One major usecase of static functions is not polluting the global namespace. ------------------------------------------------------- static int foo(int a, int b) { return a + b + 42; } int bar(int a, int b) { return foo(a, b); } ------------------------------------------------------- nm => 0000000000000017 T bar 0000000000000000 t foo ------------------------------------------------------- static int foo(int a, int b) { return -42; } int bar(int a, int b); int main() { return bar(1, 2); } ------------------------------------------------------- nm => U bar 0000000000000000 t foo U _GLOBAL_OFFSET_TABLE_ 0000000000000011 T main nm a.out | grep foo => 000000000000063a t foo 0000000000000670 t foo Additionally, when compiling with optimizations both foos are gone: All calls are inlined, the functions are never referenced and therefore removed. This can reduce executable size a lot if you have many local helper functions, so D may benefit from this optimization as well. -- Johannes
Jul 19
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2017-07-19 14:11, John Burton wrote:

 Hmm it turns out this machine has 2.0.65 on which is fairly ancient. I'd 
 not realized this machine had not been updated.
 
 Sorry for wasting everyones' time if that's so, and thanks for the help.
I suspected something like this :). Nice to hear that you sorted it out. -- /Jacob Carlborg
Jul 19
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 19 July 2017 at 11:52:09 UTC, John Burton wrote:
 ---- lib1.d ----

 private void init()
 {
     // init function used only as an implementation detail
 }

 void mything()
 {
     init();
 }


 ---- lib2.d -----

 void init()
 {
     // init function meant to be used as part of the module 
 interface
 }

 ---- main.d ----

 import lib1;
 import lib2;

 void main()
 {
     init();  // This is meant to call lib2.init because it's 
 the only
              // function of that name. lib1.init() is supposed 
 to be
              // an entirely internal implementation detail of 
 lib1
              // Even though I can't call lib1.init() because 
 it's private
              // this call still shows up as ambigous.
  	     //
              // In C I'd write "static void init()" in lib1.d 
 to indicate
              // that the function was entirely local to that 
 file. However static
              // does not appear to have that same effect in D
 }
This should work as you expect, as that's what private in module scope is supposed to do. And it does work for me 2.074.1. There was a bug with the visibility of module-private symbols in the D frontend that was fixed a couple of releases back (can't recall off hand which version). So if you're using an older version of DMD, or a version of LDC or GDC that uses an older version of the frontend, then you'll still encounter the bug. The workaround (until you get a compiler with a more recent frontend) is to use the fully qualified name (FQN) of the function you want to call, in this case: lib2.init();
Jul 19