| |
| Posted by Manfred Nowak | PermalinkReply |
|
Manfred Nowak
| http://www.digitalmars.com/d/declaration.html, [cited 11.01.04]:
| class C : B {
| int foo( int a ) { return 3; }
| alias B.foo foo;
| }
This looks like a bug to me. At least it fells into the categories `unused variable, unreachable code, x=x' and therefore a maintenance problem.
The declaration `class C : B' denotes, that C inherets every function of B by definition. Therefore the alias declaration in this code is at least completely superfluous.
The feeling that it should be a bug stems from the fact, that B.foo is
a set of functions, namely B.foo and A.foo, which is inhereted into B,
and therefore A.foo is reintroduced into the current scope, despite of
the fact that it has been just overloaded. But then I read the
introductory words again:
| Aliases can also 'import' a set of overloaded functions, that can
| be overloaded with functions in the current scope
This seems to mean, that alias declarations are of lower priority and that the textual order of aliasing/overloading does not matter. If so, then it imposes a recognition problem: after reading some overloading the maintainer eventually reaches an alias declaration that 'imports' overloadable functions. Those functiomns, that are not already overloaded expand the current scope at least temporarily. Therefore a maintainer must recall all already declared functions in the current scope to determine which of the functions introduced by the alias are really expanding the current scope. This holds for every newly found alias declaration.
To avoid this the alias declarations must come first, because they are of lower priority, than the declarations in the current scope.
But first have a look at the current implementation, when A.foo is
overloaded in B:
<code>
class A {
int foo(int a) { return 1; }
}
class B : A {
int foo(int a) { return 4; } // A.foo overloaded
int foo( int a, uint b ) { return 2; }
}
class C : B {
int foo( int a ) { return 3; }
alias B.foo foo;
}
class D : C {
}
void test()
{
D b = new D();
int i;
i = b.foo(1, 2u); // calls B.foo
printf("%d\n",i);
}
void main()
{
test();
}
</code>
The code compiles and the printing consists of the expected number `2'.
But oops, the call of `i = b.foo(1);' was lost. Reintroducing it:
<code> [...]
void test()
{
D b = new D();
int i;
i = b.foo(1, 2u); // calls B.foo
i = b.foo(1); // lost code reintroduced here
printf("%d\n",i);
}
[...] </code>
yields the compiler error:
| test.d(25): function foo overloads int(int a) and int(int a) both
| match argumentlist for foo
This is inacceptable. Usually the class designers are not identical with the users of the class. Therefore this behaviour of the compiler is equivalent to a qualitiy control by the consumer. And in addition, there should be no error message at all, because the questionable function was overloaded in the current 'importing' scope.
Now lets change the textual order of the alias and the overloading.
<code> [...]
class C : B {
alias B.foo foo;
int foo( int a ) { return 3; }
}
[...]</code>
This yields the compiler error:
| test.d(6): function foo conflicts with C.foo at test.d(12)
B.foo(int) conflicts with its overloading function C.foo(int)? According to the introductuary words this should not happen at all, but the error message is presented before the actual call of the consumer and that is clearly better.
Conclusion: the actual behaviour of the compiler is inconsistent with the supposed meaning of the documentation.
IMO the supposed meaning of the documentation should guide the implementation.
Moreover, if the supposed meaning takes the lead, then D would have a
nice method of contructing new classes. Example:
<code>
class A1 {
int foo(int a){return 1;};
}
class A2 : A1 {
int foo(int a, uint b){return 2;}
}
class B1 {
uint bar(int a){return 3;};
}
class B2 : B1 {
int bar(int a, uint b){return 4;}
}
class C {
alias A2.foo xxx;
alias B2.bar xxx; //A2.foo conflicts with B2.bar
int xxx(int a, uint b){return 5;} //conflict resolved by overloading
} //C contains A1.foo, B1.bar, C.xxx
class D : C {
}
void test()
{
D b = new D();
int i;
i = b.xxx(1, 2u); // calls C.xxx
printf("%d\n",i);
}
void main()
{
test();
}
</code>
But currently the compiler message is:
| test.d(14): function bar conflicts with C.xxx at test.d(21)
I.e. B2.bar conflicts with C.xxx. And when omitting the overloading the underlying conflict is only detected when a consumer tries to call the conflictuary function. :-(
So long.
--
Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/ 2EA56D6D4DC41ABA311615946D3248A1
|