pointers, functions, and uniform call syntax
monarch_dodra
monarchdodra at gmail.com
Mon Sep 3 12:49:37 PDT 2012
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.
}
----
?
More information about the Digitalmars-d
mailing list