Why can't we make reference variables?
Tommi
tommitissari at hotmail.com
Thu Aug 30 22:24:28 PDT 2012
On Thursday, 30 August 2012 at 17:50:47 UTC, Jonathan M Davis
wrote:
> On Thursday, August 30, 2012 15:30:15 Tommi wrote:
>> Yes, but to me the ambiguity of that example is in whether or
>> not
>> implicit deferencing of pointers has precedence over uniform
>> function call syntax. Apparently it does, but it's not that
>> obvious that it would.
>
> It _can't_ work any other way, because there's no way to tell
> the compiler to
> use the member function specifically. You can use the full
> import path for the
> free function, so you can tell the compiler to use the free
> function. There's
> no such syntax for member variables.
>
>> struct MyStruct
>> {
>> int _value = 0;
>>
>> void increment()
>> {
>> ++_value;
>> }
>> }
>>
>> void increment(ref MyStruct* ptr)
>> {
>> ++ptr;
>> }
>>
>> void main()
>> {
>> MyStruct* ptrMyStruct = new MyStruct();
>>
>> // Are we incrementing the pointer using UFCS or
>> // are we calling the member function in MyStruct?
>> ptrMyStruct.increment();
>> }
>
> For instance, if you do
>
> increment(ptrMyStruct);
>
> or
>
> .increment(ptrMyStruct);
>
> or if increment had a longer import path
>
> path.to.increment(ptrMyStruct);
>
> then you can tell the compiler to use the free function. But
> how would you do
> that with the member function? You can't. So, there's really no
> other choice
> but to choose the member function whenever there's a conflict.
> It also prevents
> function hijacking so that something like var.increment()
> doesn't suddenly
> start using using a free function instead of the member
> function when you add
> an import which has an increment free function.
>
> - Jonathan M Davis
But this is not about member function vs. free function. This is
about implicit pointer dereferencing vs. UFCS. The question is:
"what does member access operator do, when it operates on a
pointer?". There are two options, and I think they are both valid
options the language could have chosen:
// S is a struct:
auto ptr = new S();
// What to do with this?
ptr.fun(); // or ptr.fun;
Option #1:
Rewrite the expression as (*ptr).fun()
Option #2:
If .fun(S*) exists: call the free function .fun(ptr)
Else: rewrite the expression as (*ptr).fun()
...But, actually it seems that the language is a bit broken,
because it doesn't follow neither one of those two options. What
it actually does is this:
Option #3:
If S.init.fun() exists: call the member (*ptr).fun()
Else if .fun(S*) exists: call the free function .fun(ptr)
Else give a compile time error
Here's the details:
struct S1
{
int _value = 42;
void fun()
{
++_value;
}
}
void fun(ref S1 s1)
{
s1._value += 1000;
}
void fun(ref S1* ptr1)
{
++ptr1;
}
/////////////////////////////
struct S2
{
int _value = 42;
}
void fun(ref S2 s2)
{
++s2._value;
}
void fun(ref S2* ptr2)
{
++ptr2;
}
/////////////////////////////
struct S3
{
int _value = 42;
}
void fun(ref S3 s3)
{
++s3._value;
}
void main()
{
auto ptr1 = (new S1[2]).ptr;
ptr1.fun(); // calls (*ptr1).fun()
writeln(ptr1._value); // prints 43
auto arr2 = new S2[2];
auto ptr2 = arr2.ptr;
arr2[1]._value = 12345;
ptr2.fun(); // calls .fun(ptr2)
writeln(ptr2._value); // prints 12345
auto ptr3 = (new S3[2]).ptr;
ptr3.fun(); // Error: function main.fun (ref S3 s3) is
// not callable using argument types (S3*)
}
I think, if we want to have implicit pointer dereferencing (I'm
not even sure it's a good thing), then option #1 would be the
best choice.
More information about the Digitalmars-d
mailing list