On Monday, 21 April 2014 at 14:10:08 UTC, Steven Schveighoffer
wrote:
[...]
module m1;
import std.stdio;
class C {}
void foo(C c)
{
writeln("C.foo");
}
void bar(C c)
{
writeln("C.bar");
}
module m2;
import m1;
import std.stdio;
void foo(T)(T t)
{
writeln("m2.foo");
}
void bar(T)(T t, int x)
{
writeln("m2.bar");
}
void main()
{
auto c = new C;
c.foo(); // "m2.foo";
//c.bar(); // error if uncommented!
}
Basically, I've inadvertently overridden C.foo, without
intending to. With bar, I've somehow hidden the inherent
functionality of C!
Wow, I didn't know that. I thought the most specialised function
would always be selected, regardless of which module it's defined
in. What you've demonstrated feels wrong, somehow.
4. It enforces the "method call" syntax. I.e. you cannot use
foo(obj) call. This may be important for readability.
Some would argue that giving users the choice between typing
foo(obj) and obj.foo() is a Good Thing, because it doesn't
impose your preferences on them. I'm not going to do that,
though. ;)
You may recall that I am a big proponent of explicit properties
because I think the ways of calling functions have strong
implications to the reader, regardless of the functions. This
is the same thing. I look at foo(x) much differently than
x.foo().
And you may recall that I was on the same side as you in the
properties debate, though less vocal about it. (In fact, I think
we didn't go far enough with properties -- we should also forbid
taking their address. But that's another discussion.) The point
is, I lean towards the same view as you when it comes to UFCS,
and only brought up the opposing view for the sake of the
discussion.
I tend to use UFCS only for a few select cases (array range
functions, range chaining, etc.), and to otherwise use the
"normal" function call syntax. If someone sees this in my code:
obj.foo();
I want them to know where to look for further information about
foo(), namely in the class documentation/code.