On Monday, 3 September 2012 at 19:49:14 UTC, monarch_dodra wrote:
On Monday, 3 September 2012 at 18:45:42 UTC, Jonathan M Davis wrote:
On Monday, September 03, 2012 14:13:10 monarch_dodra wrote:
I was playing around with a very big struct, and told myself I
wanted it allocated on the heap. This meant I was now
manipulating S* instead of an S.

I thought "this should have zero impact, because in D, because
"." is supposed to deference for you if needed."

I find it strange though that when trying to call a function with a pointer, the pointer isn't automatically dereferenced if needed:

----
struct S
{
  void foo();
}
void bar(S);
void main()
{
  auto r = new S;
  r.foo();
  bar(r);  //derp
  r.bar(); //derp
};
----
I find it strange, because I thought the entire point was to
abstract way something was allocated to the way it was used: EG. From a caller perspective, I don't care if r is on the stack or on the heap: I just want to call the method bar on the object in
question.

Why does one consider a "free standing" function more ambiguous
than a member function?

Things get even stranger if you mix in uniform call syntax.
"r.foo()" works, but "r.bar()" doesn't?

Am I really forced into:
----
struct S
{
  void foo();
}
void bar(S);
void main()
{
  auto r = new S;
  r.foo();
  bar(*r);    //Groan
  (*r).bar(); //Super Groan.
};
----
I feel as if I'm just back at square 1...

All that UFCS does is make it so that if the first parameter of a function is a given type, you can call that function on that type as if it were a member
function. It's purely syntactic convenience.

void bar(S) {}

takes an S, not as S*, so I wouldn't expect UFCS to work with it and an S*.

. dereferences a pointer when accessing a member function or variable, because it works quite nicely to have it work that way and generally negates the need for a second operator (->). It's certainly _not_ true that the automatic dereferencing with . allows you to forget that something is a pointer. An operation which _could_ be on the pointer (e.g ==) will operate on the pointer, forcing you to dereference it. It's just that adding -> on top of .
is unnecessary and complicates the language.

The choice to have . automatically dereference pointers when access members predates the idea of UFCS considerably, and I don't think that it was ever really considered how they two would interact. The automatic dereferencing of a pointer doesn't really have anything to do with UFCS except for similarites of syntax. It's simply that if a variable is a pointer, and it points to a type which has a member with the same name as what's on the right-hand side of the dot, then that member function gets called. And technically, it doesn't even dereference the pointer, because the member function takes a pointer (as the invisible this pointer). If there is no such member function, then free functions are checked to see if they take the variable's type as their first argument. If there's such a function with the right name and number of arguments, then it's used. For there to be any dereferencing involved would require special casing pointers, which doesn't currently happen.

I think that the way that it currently works is completely consistent. It's a
perfectly valid enhancement request to want

void func(S s, int i) {...}

to be be callable with S*, given that normally function calls on an S* don't require you to dereference anything. But it's not like what we have is broken. It's just that there's a corner case which forces you to deal with pointers specially (which isn't exactly new, because things like == and assignment already require you to treat pointer specially). So, feel free to create an enhancement request. You've found a corner case that I suspect was never fully though through, and Walter may very well think that the change is worth
making.

However, one thing to remember that complicates this a bit is that it's perfectly possible to declare a function which is overloaded with one function
taking a pointer and one not.

void func(S* s, int i) {...}
void func(S s, int i) {...}

in which case, there's an ambiguity, and I would then expect UFCS to _not_ compile when using S*, or you'd risk function call hijacking. That's not
necessarily a big deal, but it _does_ complicate things a bit.

- Jonathan M Davis

TY for the reply, I'll consider asking for it.

In the mean time, is there a way to access that variable with value semantics? I mean, in the scope where my pointer was declared, I *know* it is non null.

In C++, I often did it with iterators:
----
for(it ...)
{
    int& val = *it;
    //now, we can access it with value semantics through val.
}
----

?

Good question, I've proceeded in the same way in C++ many times. I hope there's a way, but I think it likely there is not, except by passing *it to a function with a reference parameter.


Reply via email to