D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3254 - [module] Module member visibility depends on declaration order
Summary: [module] Module member visibility depends on declaration order
Status: REOPENED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other Windows
: P1 regression
Assignee: No Owner
URL:
Keywords: pull, rejects-valid
: 5422 19080 21829 23397 23991 24388 (view as issue list)
Depends on:
Blocks: 340
  Show dependency treegraph
 
Reported: 2009-08-16 18:53 UTC by Sergey Gromov
Modified: 2024-12-13 17:50 UTC (History)
10 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Sergey Gromov 2009-08-16 18:53:50 UTC
The following code compiles:

--a.d---------
import b;
void main() {
  foo(0);
}
--------------

--b.d---------
void foo(int x) {}
private void foo(float x) {}
--------------

> dmd -c -o- a.d
>

But swap function declarations in b.d, and it breaks:

--b.d---------
private void foo(float x) {}
void foo(int x) {}
--------------

> dmd -c -o- a.d
a.d: module a b.foo is private
Comment 1 Stewart Gordon 2009-08-17 16:19:16 UTC
(DMD 1.046 Windows)

If b.d is changed to
----------
private void foo(int x) {}
void foo(float x) {}
----------
then it doesn't compile either way round:
----------
bz3254a.d: Error: module bz3254a bz3254b.foo is private
bz3254a.d(3): Error: function bz3254b.foo is not accessible from bz3254a
----------
The first of these errors disappears if they're swapped over.

But I'm not sure whether this is meant to work or not.  Are function calls meant to be matched over all overloads, or only those that are accessible?
Comment 2 anonymous4 2009-08-18 00:42:15 UTC
From bug 314
> Access protection is defined to happen after lookup and overload resolution.
So the correct behavior seems to match foo(int) first, then look for its access attribute. Though I don't understand this scheme too.
Comment 3 Stewart Gordon 2009-08-18 02:08:23 UTC
(In reply to comment #2)
> From bug 314
> > Access protection is defined to happen after lookup and overload resolution.

Defined where in the spec?

> So the correct behavior seems to match foo(int) first, then look for its access
> attribute. Though I don't understand this scheme too.

Basically, all overloads of a function name are looked at, regardless of their protection attributes, in order to pick an overload.  Then the call is validated on the protection attribute of the one that's been picked.

My guess is that the point is to protect against accidental behaviour changes if some code is moved between modules.  But maybe it's better to avoid having a private function and a public function with the same name in the same scope.

But the current behaviour does seem to be overdoing it.  If a module imports two modules each of which defines a symbol, but in one of them it's private, an import conflict is reported.  It's been my view for a while that private symbols should not be imported at all.  Maybe the best policy is to see whether _all_ overloads are private and, if so, the module will keep the symbol to itself; otherwise, invoke the the current behaviour.
Comment 4 anonymous4 2009-08-20 00:03:27 UTC
(In reply to comment #3)
> My guess is that the point is to protect against accidental behaviour changes
> if some code is moved between modules.
The code moved, it moved from one module to another. The accidental behavior change still can happen in the module the code moved to. If there was public foo(int), the module used to call it, then private foo(float) appears and the module silently starts to call it.
Comment 5 Sergey Gromov 2009-08-20 06:27:26 UTC
> > From bug 314
> > > Access protection is defined to happen after lookup and
> > > overload resolution.
> Defined where in the spec?

That was Walter's comment.  This exact comment made me experiment with module-level protection attributes and led to this bug report.

Well, I think the "overload before protection" rule has its merit for classes.  Class methods *hide* methods of the same name in base classes to protect from overload set hijacking.  It probably would be confusing if hiding rules worked differently depending on whether your function is in the same module with the class or not.

But module members cannot hide anything.  Any name collision is an error, and any conflict resolution is explicit.  Therefore I think overload resolution should be changed for modules, too.  Consider:

module a;
class A {}
void foo(A a) {}

module b;
class B {}
void foo(B b) {}

module c;
import a, b;
private alias a.foo foo;
private alias b.foo foo;
void bar() {
  foo(new A);
  foo(new B);
}

So far so good.  But now:

module d;
import a, c;
void baz() {
  foo(new A); // error ?!!
}

a.foo conflicts with c.foo ?  But I don't know about c.foo.  There is no documentation for c.foo.  There is no c.foo.  Still, this phantom messes up overloading.
Comment 6 Martin Nowak 2012-02-12 09:08:06 UTC
*** Issue 5422 has been marked as a duplicate of this issue. ***
Comment 7 Martin Nowak 2012-02-12 09:14:01 UTC
I think that disallowing mixed protections within one overload set could work
out very well.
Comment 8 github-bugzilla 2016-03-05 14:16:23 UTC
Commit pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/e527108f9153cedab2ca658d053b2ac81610e55d
fix Issue 3254 - Module member visibility depends on declaration order
Comment 9 FeepingCreature 2022-02-25 09:02:27 UTC
This exact bug has reappeared.
Comment 10 FeepingCreature 2022-02-25 09:04:38 UTC
Oh, I misread the original report: it's now in reverse; foo(0.0f) compiles, even though it calls a private function. Should I open a new bug?
Comment 11 RazvanN 2022-09-08 06:48:57 UTC
*** Issue 21829 has been marked as a duplicate of this issue. ***
Comment 12 RazvanN 2022-10-10 03:33:15 UTC
*** Issue 23397 has been marked as a duplicate of this issue. ***
Comment 13 Dlang Bot 2022-12-18 19:03:08 UTC
@ibuclaw created dlang/dmd pull request #14713 "fix Issue 3254 - [module] Module member visibility depends on declaration order" fixing this issue:

- fix Issue 3254 - [module] Module member visibility depends on declaration order

https://github.com/dlang/dmd/pull/14713
Comment 14 RazvanN 2023-06-19 09:31:17 UTC
*** Issue 23991 has been marked as a duplicate of this issue. ***
Comment 15 Iain Buclaw 2024-02-11 20:18:24 UTC
*** Issue 19080 has been marked as a duplicate of this issue. ***
Comment 16 Paul Backus 2024-02-12 18:53:09 UTC
*** Issue 24388 has been marked as a duplicate of this issue. ***
Comment 17 dlangBugzillaToGithub 2024-12-13 17:50:34 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18058

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB