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.
}
----
?