www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - UFCS and overloading

reply "Szymon Gatner" <noemail gmail.com> writes:
Hi,

I am surprised that this doesn't work:

class Foo
{
   void bar(string) {}
}

void bar(Foo foo, int i)
{
}

auto foo = new Foo();
foo.bar(123); // <=== error

causing compilation error:

main.d(24): Error: function main.Foo.bar (string _param_0) is not 
callable using argument types (int)

does UFCS now work with method overloading? I know it is not a 
syntax error because changing the name of int version of bar to 
bar2 and calling foo.bar2(123) works fine.
Apr 06 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/6/15 12:23 PM, Szymon Gatner wrote:
 Hi,

 I am surprised that this doesn't work:

 class Foo
 {
    void bar(string) {}
 }

 void bar(Foo foo, int i)
 {
 }

 auto foo = new Foo();
 foo.bar(123); // <=== error

 causing compilation error:

 main.d(24): Error: function main.Foo.bar (string _param_0) is not
 callable using argument types (int)

 does UFCS now work with method overloading? I know it is not a syntax
 error because changing the name of int version of bar to bar2 and
 calling foo.bar2(123) works fine.
You can't do this. UFCS cannot add overloads, it can only add whole overload sets (if not already present). -Steve
Apr 06 2015
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Monday, 6 April 2015 at 17:53:13 UTC, Steven Schveighoffer 
wrote:
 On 4/6/15 12:23 PM, Szymon Gatner wrote:
 Hi,

 I am surprised that this doesn't work:

 class Foo
 {
   void bar(string) {}
 }

 void bar(Foo foo, int i)
 {
 }

 auto foo = new Foo();
 foo.bar(123); // <=== error

 causing compilation error:

 main.d(24): Error: function main.Foo.bar (string _param_0) is 
 not
 callable using argument types (int)

 does UFCS now work with method overloading? I know it is not a 
 syntax
 error because changing the name of int version of bar to bar2 
 and
 calling foo.bar2(123) works fine.
You can't do this. UFCS cannot add overloads, it can only add whole overload sets (if not already present). -Steve
Why is that? The use case is to provide a set of convenience "extension methods" to a basic interface. Say, given: interface Subject { void add(SomeInterface obj); } // and then void add(Subject a, Type1 v1) { a.add(convertToSomeInterface(v1)); } void add(Subject a, Type2 v2) { a.add(convertToSomeInterface(v2)); } this way client can just implement Subject interface and still use it with types Type1 and Type2. C# allows that, why D does not?
Apr 06 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/6/15 2:00 PM, Szymon Gatner wrote:
 On Monday, 6 April 2015 at 17:53:13 UTC, Steven Schveighoffer wrote:
 On 4/6/15 12:23 PM, Szymon Gatner wrote:
 Hi,

 I am surprised that this doesn't work:

 class Foo
 {
   void bar(string) {}
 }

 void bar(Foo foo, int i)
 {
 }

 auto foo = new Foo();
 foo.bar(123); // <=== error

 causing compilation error:

 main.d(24): Error: function main.Foo.bar (string _param_0) is not
 callable using argument types (int)

 does UFCS now work with method overloading? I know it is not a syntax
 error because changing the name of int version of bar to bar2 and
 calling foo.bar2(123) works fine.
You can't do this. UFCS cannot add overloads, it can only add whole overload sets (if not already present).
Why is that? The use case is to provide a set of convenience "extension methods" to a basic interface. Say, given: interface Subject { void add(SomeInterface obj); } // and then void add(Subject a, Type1 v1) { a.add(convertToSomeInterface(v1)); } void add(Subject a, Type2 v2) { a.add(convertToSomeInterface(v2)); } this way client can just implement Subject interface and still use it with types Type1 and Type2. C# allows that, why D does not?
In D, the symbol itself is used to find the appropriate "overload set" and then the parameters are used within the set to figure out the specific overload to use. Overload sets have different precedence, with I think members having the highest precedent, and likely UFCS having the lowest. But once an overload set is found, anything defined outside that set is not seen. This is done in part to prevent hijacking of functions. For example, if you wanted to change the meaning of some code by defining a better overload match. This doesn't mean it couldn't be changed, but it is definitely implemented as designed. -Steve
Apr 06 2015
prev sibling parent reply "cym13" <cpicard openmailbox.org> writes:
On Monday, 6 April 2015 at 18:00:46 UTC, Szymon Gatner wrote:
 Why is that? The use case is to provide a set of convenience 
 "extension methods" to a basic interface. Say, given:
This is not the only use case, another (maybe even more common) use is to allow pipeline programming. Example from one of Andrei's talks ( http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/D ): import std.algorithm, std.stdio, std.range, std.conv; void main() { stdin .byLine .filter!(s => !s.empty && s.front != '#’) // Filter with this lambda function .map!(s => s.to!double) // Map the strings to doubles .array // Sorting needs random access .sort!((a, b) => a < b) // Another lambda .take(10) // Applyable to any range .writeln; } With such constructs, it is important to be able to call a method and not the function as there are ways to explicitely call the function but not the method (AFAIK). As this style of programming is actively encouraged by both Andrei and Walter, I think the design is coherent.
Apr 07 2015
parent reply "cym13" <cpicard openmailbox.org> writes:
EDIT: mis-formatted previous snippet

import std.algorithm, std.stdio, std.range, std.conv;
void main()
{
     stdin
         .byLine
         .filter!(s => !s.empty && s.front != '#’) // Filter with 
this lambda function
         .map!(s => s.to!double) // Map the strings to doubles
         .array // Sorting needs random access
         .sort!((a, b) => a < b) // Another lambda
         .take(10) // Applyable to any range
         .writeln;
}
Apr 07 2015
parent "Szymon Gatner" <noemail gmail.com> writes:
On Tuesday, 7 April 2015 at 14:46:52 UTC, cym13 wrote:
 EDIT: mis-formatted previous snippet

 import std.algorithm, std.stdio, std.range, std.conv;
 void main()
 {
     stdin
         .byLine
         .filter!(s => !s.empty && s.front != '#’) // Filter 
 with this lambda function
         .map!(s => s.to!double) // Map the strings to doubles
         .array // Sorting needs random access
         .sort!((a, b) => a < b) // Another lambda
         .take(10) // Applyable to any range
         .writeln;
 }
Yup, I get that, still does not explain why UFCS can't extend overload set. Especially if there would be no conflict wrt to overload of method vs free function.
Apr 07 2015