www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Function overloading concern

reply Sean Kelly <sean f4.ca> writes:
While I appreciate the simple overloading rules in D, the recent 
template improvements have me wondering how to solve cases where fully 
qualifying names is impossible.  Here's an example using plain old 
functions:

Module A:

     module a;

     void swap( inout int i1, inout int i2 )
     {
         int t = i1; i1 = i2; i2 = t;
     }

Module B:

     module b;

     struct S {}

     void swap( inout S s1, inout S s2 )
     {
         S t = s1; s1 = s2; s2 = t;
     }

Main:

     import a;
     import b;

     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             swap( t1, t2 );
         }
     }

     void main()
     {
         int i = 1, j = 2;
         func( i, j );
     }

C:\code\d>dmd test a b
a.d(3): function a.swap conflicts with b.swap at b.d(5)
test.d(15): template instance test.func!(int) error instantiating

While I haven't run up against this situation yet, I can see it being an 
obstacle for large projects.  How would I resolve something like this? 
And I expect the overloading rules will be the same for template 
functions as they are for normal functions?  Finally, is there a more 
D-oriented approach that might address this without language changes?

I suppose one language change that might help would be to support the 
externally defined method syntax for primitives, so func could be 
rewritten as:

     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             t1.swap( t2 );
         }
     }

and the specialized swap for struct S could be placed within its own 
scope.  However, this still doesn't address all situations, and I'm not 
entirely certain that it wouldn't introduce new overloading problems 
where none existed before.


Sean
Mar 09 2006
next sibling parent Sean Kelly <sean f4.ca> writes:
I mulled this over a bit more, and I think the existing rules will work 
so long as template code is carefully designed with it in mind.  For 
example, where a template might rely on another overloaded template in 
C++, it might be prudent to parameterize it in D.  And with classes as 
reference types in D, there's a much smaller need for specialized swap 
functions.  My only remaining concern is traits templates in D, as they 
basically rely on cross-module overloading.  But perhaps this is 
something best sorted out by experimentation--DTL will likely have to 
deal with it sooner or later in any case ;-)

Sean
Mar 09 2006
prev sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Sean Kelly escribió:
 While I appreciate the simple overloading rules in D, the recent 
 template improvements have me wondering how to solve cases where fully 
 qualifying names is impossible.  Here's an example using plain old 
 functions:
 
 Module A:
 
     module a;
 
     void swap( inout int i1, inout int i2 )
     {
         int t = i1; i1 = i2; i2 = t;
     }
 
 Module B:
 
     module b;
 
     struct S {}
 
     void swap( inout S s1, inout S s2 )
     {
         S t = s1; s1 = s2; s2 = t;
     }
 
 Main:
 
     import a;
     import b;
 
     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             swap( t1, t2 );
         }
     }
 
     void main()
     {
         int i = 1, j = 2;
         func( i, j );
     }
 
 C:\code\d>dmd test a b
 a.d(3): function a.swap conflicts with b.swap at b.d(5)
 test.d(15): template instance test.func!(int) error instantiating
 
 While I haven't run up against this situation yet, I can see it being an 
 obstacle for large projects.  How would I resolve something like this? 
 And I expect the overloading rules will be the same for template 
 functions as they are for normal functions?  Finally, is there a more 
 D-oriented approach that might address this without language changes?
 
 I suppose one language change that might help would be to support the 
 externally defined method syntax for primitives, so func could be 
 rewritten as:
 
     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             t1.swap( t2 );
         }
     }
 
 and the specialized swap for struct S could be placed within its own 
 scope.  However, this still doesn't address all situations, and I'm not 
 entirely certain that it wouldn't introduce new overloading problems 
 where none existed before.
 
 
 Sean

Does this work? import a; import b; alias a.swap swap; alias b.swap swap; template func( T ) { void func( inout T t1, inout T t2 ) { swap( t1, t2 ); } } void main() { int i = 1, j = 2; func( i, j ); } -- Carlos Santander Bernal
Mar 09 2006
parent reply Sean Kelly <sean f4.ca> writes:
Carlos Santander wrote:
 
 Does this work?
 
     import a;
     import b;
 
     alias a.swap swap;
     alias b.swap swap;

It does. alias is just too darn flexible for its own good :-) Sean
Mar 09 2006
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Sean Kelly wrote:
 Carlos Santander wrote:
 Does this work?

     import a;
     import b;

     alias a.swap swap;
     alias b.swap swap;

It does. alias is just too darn flexible for its own good :-)

By the way, the more complex C++ examples don't work in D anyway, because D is module-based. For example, it's more likely func would be defined in a third module like so: Module C: module c; import b; // let's say b is the default implementation template func( T ) { void func( inout T t1, inout T t2 ) { swap( t1, t2 ); } } Main: import a; import c; void main() { int i = 1, j = 2; func( s, t ); } However, this doesn't work in D even without overloading. So perhaps it's not much of an issue here anyway. Sean
Mar 09 2006
next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Sean Kelly escribió:
 
 By the way, the more complex C++ examples don't work in D anyway, 
 because D is module-based.  For example, it's more likely func would be 
 defined in a third module like so:
 
 Module C:
 
     module c;
     import b; // let's say b is the default implementation
 
     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             swap( t1, t2 );
         }
     }
 
 Main:
 
     import a;
     import c;
 
     void main()
     {
         int i = 1, j = 2;
         func( s, t );
     }
 
 However, this doesn't work in D even without overloading.  So perhaps 
 it's not much of an issue here anyway.
 
 
 Sean

This one, I don't understand. I don't have DMD to try the code, but I think the call sequence would be something like: main -> c.func -> b.swap The main module imports a, but it's never used. The only thing that I can think of is that you want c.func to use a.swap because it was imported in main, but it doesn't make much sense (for me, anyway) because c never knew about a. I don't know if C++ allows that, but I would say it's not a very good design. There should be another way. IMHO. -- Carlos Santander Bernal
Mar 09 2006
parent reply Sean Kelly <sean f4.ca> writes:
Carlos Santander wrote:
 Sean Kelly escribió:
 By the way, the more complex C++ examples don't work in D anyway, 
 because D is module-based.  For example, it's more likely func would 
 be defined in a third module like so:

 Module C:

     module c;
     import b; // let's say b is the default implementation

     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             swap( t1, t2 );
         }
     }

 Main:

     import a;
     import c;

     void main()
     {
         int i = 1, j = 2;
         func( s, t );
     }

 However, this doesn't work in D even without overloading.  So perhaps 
 it's not much of an issue here anyway.


 Sean

This one, I don't understand. I don't have DMD to try the code, but I think the call sequence would be something like: main -> c.func -> b.swap The main module imports a, but it's never used.

The above example doesn't really make sense in D but it's quite common in C++, whose current import mechanism is little more than a structured copy/paste during preprocessing (recall that module A defines the overload that Main wants to be used by module C). But this is semantically meaningless in D, which was my only point--that perhaps C++ overload resolution really isn't necessary in D after all.
 The only thing that I can think of is that you want c.func to use a.swap 
 because it was imported in main, but it doesn't make much sense (for me, 
 anyway) because c never knew about a. I don't know if C++ allows that, 
 but I would say it's not a very good design. There should be another 
 way. IMHO.

It's not a good design, but the C/C++ people are stuck with it :-) There's been a recent push to adopt a module import scheme for C++, but I think the huge mass of legacy code like the above will make the scheme very difficult to use. Sean
Mar 09 2006
parent reply "Walter Bright" <newshound digitalmars.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:duqh7n$1l6c$1 digitaldaemon.com...
 There's been a recent push to adopt a module import scheme for C++, but I 
 think the huge mass of legacy code like the above will make the scheme 
 very difficult to use.

I've seen that scheme. It strikes me as excessively complicated. Furthermore, there are no implementations of it, so nobody knows if it is implementable (see "export"), or if it is actually usable (see "namespace").
Mar 09 2006
parent reply Mike Capp <mike.capp gmail.com> writes:
In article <dur2g6$29us$1 digitaldaemon.com>, Walter Bright says...
"Sean Kelly" <sean f4.ca> wrote in message 
news:duqh7n$1l6c$1 digitaldaemon.com...
 There's been a recent push to adopt a module import scheme for C++, but I 
 think the huge mass of legacy code like the above will make the scheme 
 very difficult to use.


The proposal is actually pretty good about backward compatibility. The transition would be messy, yes, but transitions always are.
I've seen that scheme. It strikes me as excessively complicated. 
Furthermore, there are no implementations of it, so nobody knows if it is 
implementable (see "export"), or if it is actually usable (see "namespace"). 

In fairness, the proposal is by Daveed Vandevoorde of EDG, who AFAIK are the only people on the planet who *have* implemented "export". I don't think he's chucking this stuff out of the window of some ivory tower. My main concern about the proposal as it currently stands is that I can't see how build tools like "make" can possibly work with it. The model is no longer "compile a bunch of separate objects and throw them at the linker". To compile a source file you need to have compiled all source files it depends on, and all source files *they* depend on, and so on. I'm increasing worried that the whole module concept may not be workable in a language that doesn't allow references to undeclared symbols at compile time. cheers Mike
Mar 10 2006
next sibling parent Sean Kelly <sean f4.ca> writes:
Mike Capp wrote:
 
 My main concern about the proposal as it currently stands is that I can't see
 how build tools like "make" can possibly work with it. The model is no longer
 "compile a bunch of separate objects and throw them at the linker". To compile
a
 source file you need to have compiled all source files it depends on, and all
 source files *they* depend on, and so on. I'm increasing worried that the whole
 module concept may not be workable in a language that doesn't allow references
 to undeclared symbols at compile time.

This is my concern as well. Just how far will they truly be able to abstract themselves from the include model? However, I haven't yet read the proposal so perhaps I should do so before speculating further. Sean
Mar 10 2006
prev sibling parent reply "Walter Bright" <newshound digitalmars.com> writes:
"Mike Capp" <mike.capp gmail.com> wrote in message 
news:durud0$109b$1 digitaldaemon.com...
 In article <dur2g6$29us$1 digitaldaemon.com>, Walter Bright says...
I've seen that scheme. It strikes me as excessively complicated.
Furthermore, there are no implementations of it, so nobody knows if it is
implementable (see "export"), or if it is actually usable (see 
"namespace").

the only people on the planet who *have* implemented "export". I don't think he's chucking this stuff out of the window of some ivory tower.

I have the greatest admiration and respect for Daveed. But nobody is smart enough to reliably predict how useful such a complex addition will be in practice, or what all the corner cases will be, or how difficult it is to implement on any compiler other than his own, etc., all based on a paper proposal. Bottom line: the committee's track record on invention of complex new features is poor when they got standardized with no existing implementation experience (see namespace and export). The committee's record on standardizing functionality that *has* been extensively tried out is reasonably good (see STL).
 My main concern about the proposal as it currently stands is that I can't 
 see
 how build tools like "make" can possibly work with it. The model is no 
 longer
 "compile a bunch of separate objects and throw them at the linker". To 
 compile a
 source file you need to have compiled all source files it depends on, and 
 all
 source files *they* depend on, and so on. I'm increasing worried that the 
 whole
 module concept may not be workable in a language that doesn't allow 
 references
 to undeclared symbols at compile time.

I.e., it's a design for something that is complicated and quite unique among programming languages. It will *fundamentally* change the way C++ programs are built, probably in unanticipated ways. There's no implementation experience to see how it will work in a real project. The risk is that if it gets standardized without being tried, and then people find out that it is either unworkable, unusable, or has little benefit in the real world, then it cannot be taken out again (like export).
Mar 10 2006
next sibling parent Mike Capp <mike.capp gmail.com> writes:
In article <dusk1e$24pt$1 digitaldaemon.com>, Walter Bright says...

[various good points with with I fully agree]

I.e., it's a design for something that is complicated and quite unique among 
programming languages. It will *fundamentally* change the way C++ programs 
are built, probably in unanticipated ways. There's no implementation 
experience to see how it will work in a real project.

I think that statement is a little extreme. Daveed is arguably just trying to standardize and generalize the concept of precompiled headers, of which there's quite a lot of implementation experience. (Most of it bad, from where I've been standing.) Modules are a very different beast, granted, but not an entirely new one. cheers Mike
Mar 10 2006
prev sibling parent Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
Walter Bright wrote:
 "Mike Capp" <mike.capp gmail.com> wrote in message 
 news:durud0$109b$1 digitaldaemon.com...
 In article <dur2g6$29us$1 digitaldaemon.com>, Walter Bright says...
 I've seen that scheme. It strikes me as excessively complicated.
 Furthermore, there are no implementations of it, so nobody knows if it is
 implementable (see "export"), or if it is actually usable (see 
 "namespace").

the only people on the planet who *have* implemented "export". I don't think he's chucking this stuff out of the window of some ivory tower.

I have the greatest admiration and respect for Daveed. But nobody is smart enough to reliably predict how useful such a complex addition will be in practice, or what all the corner cases will be, or how difficult it is to implement on any compiler other than his own, etc., all based on a paper proposal. Bottom line: the committee's track record on invention of complex new features is poor when they got standardized with no existing implementation experience (see namespace and export). The committee's record on standardizing functionality that *has* been extensively tried out is reasonably good (see STL).
 My main concern about the proposal as it currently stands is that I can't 
 see
 how build tools like "make" can possibly work with it. The model is no 
 longer
 "compile a bunch of separate objects and throw them at the linker". To 
 compile a
 source file you need to have compiled all source files it depends on, and 
 all
 source files *they* depend on, and so on. I'm increasing worried that the 
 whole
 module concept may not be workable in a language that doesn't allow 
 references
 to undeclared symbols at compile time.

I.e., it's a design for something that is complicated and quite unique among programming languages. It will *fundamentally* change the way C++ programs are built, probably in unanticipated ways. There's no implementation experience to see how it will work in a real project. The risk is that if it gets standardized without being tried, and then people find out that it is either unworkable, unusable, or has little benefit in the real world, then it cannot be taken out again (like export).

Isn't this a design that Java, C#, and even D (to a slighty lesser degree) do? To compile a .d source file, the compiler must parse all other .d files that the original one references (in the form of modules), so isn't it the same? What's the whole new different paradigm? -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 11 2006
prev sibling next sibling parent reply "Walter Bright" <newshound digitalmars.com> writes:
D doesn't allow overloading of ordinary functions with template functions. 
C++ does, but I don't see a compelling reason for it, and it is the source 
of some complicated corner cases. 
Mar 09 2006
parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 D doesn't allow overloading of ordinary functions with template functions. 
 C++ does, but I don't see a compelling reason for it, and it is the source 
 of some complicated corner cases. 

Yup, and I agree that this is a good thing. My example used normal functions because template overloading is incomplete. Sean
Mar 09 2006
parent "Walter Bright" <newshound digitalmars.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:dur5fn$2g79$1 digitaldaemon.com...
 My example used normal functions because template overloading is 
 incomplete.

That'll get fixed.
Mar 09 2006
prev sibling parent "Bob W" <nospam aol.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:duq8gt$1cav$1 digitaldaemon.com...

 By the way, the more complex C++ examples don't work in D anyway, because 
 D is module-based.  For example, it's more likely func would be defined in 
 a third module like so:

 Module C:

     module c;
     import b; // let's say b is the default implementation

     template func( T )
     {
         void func( inout T t1, inout T t2 )
         {
             swap( t1, t2 );
         }
     }

 Main:

     import a;
     import c;

     void main()
     {
         int i = 1, j = 2;
         func( s, t );
     }

 However, this doesn't work in D even without overloading.

I doubt that this would work in any programming language ;-)
Mar 10 2006
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
On Thu, 09 Mar 2006 13:36:25 -0800, Sean Kelly wrote:

 Carlos Santander wrote:
 
 Does this work?
 
     import a;
     import b;
 
     alias a.swap swap;
     alias b.swap swap;

It does. alias is just too darn flexible for its own good :-)

Walter - to explicitly disambiguate identifiers that reside in different modules. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 10/03/2006 9:20:29 AM
Mar 09 2006
prev sibling parent "Walter Bright" <newshound digitalmars.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:duq74p$1aoo$1 digitaldaemon.com...
 Carlos Santander wrote:
 Does this work?

     import a;
     import b;

     alias a.swap swap;
     alias b.swap swap;

It does. alias is just too darn flexible for its own good :-)

Actually, alias was specifically designed so that will work. It enables one to select which groups of functions one wants to overload with, rather than doing C++ style ADL.
Mar 09 2006