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.

Reply via email to