September 04, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis |
On 9/4/2011 10:54 PM, Jonathan M Davis wrote:
>
> It's a bug in dmd. string literals aren't lvalues
Yes, they are, because one can take the address of them.
What they are not are *modifiable* lvalues.
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Sunday, September 04, 2011 23:34:58 Walter Bright wrote:
> On 9/4/2011 10:54 PM, Jonathan M Davis wrote:
> > It's a bug in dmd. string literals aren't lvalues
>
> Yes, they are, because one can take the address of them.
>
> What they are not are *modifiable* lvalues.
It still baffles me why anything other than a variable would be an lvalue or why you would ever be able to take the address of anything other than a variable or a function. But what is is, I guess.
In any case, if that's what's going on, string literals really should be typed as immutable strings and not be accepted by a function which takes ref string.
- Jonathan M Davis
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Mon, Sep 5, 2011 at 4:34 PM, Walter Bright <walter at digitalmars.com> wrote:
>
>
> On 9/4/2011 10:54 PM, Jonathan M Davis wrote:
>>
>> It's a bug in dmd. string literals aren't lvalues
>
> Yes, they are, because one can take the address of them.
>
> What they are not are *modifiable* lvalues.
Is this really a useful distinction? All you can do with const lvalues is pass them by const ref, and string literals will need to be special cased to be const only when required. The same applies to struct literals etc as well. Why can't we just make all literals rvalues and fix auto ref to fill in the holes?
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Mon, Sep 5, 2011 at 4:41 PM, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
>
> It still baffles me why anything other than a variable would be an lvalue or why
> you would ever be able to take the address of anything other than a variable
> or a function. But what is is, I guess.
>
> In any case, if that's what's going on, string literals really should be typed as immutable strings and not be accepted by a function which takes ref string.
>
> - Jonathan M Davis
The problem with immutable(string[]) is auto variables will end up
with that type.
Not to mention a couple of bugs that would allow you to pass it by ref anyway.
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis |
On 9/4/2011 11:41 PM, Jonathan M Davis wrote:
>
> It still baffles me why anything other than a variable would be an lvalue
*p is also an lvalue.
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Monday, September 05, 2011 00:27:05 Walter Bright wrote: > On 9/4/2011 11:41 PM, Jonathan M Davis wrote: > > It still baffles me why anything other than a variable would be an lvalue > > *p is also an lvalue. Good point, but that's essentially the same as setting the return value of a function that returns by ref, which essentially is a variable. But I guess that it does come down to an address more than a variable. What I really don't get is the temporaries such as when you construct a struct in place - e.g. S(1) - functioning as lvalues. The result is that if you have an opEquals which takes const ref like it's supposed to (or any function which takes a const ref, but opEquals is a good example), then you can pass it S(1) but not a the result of a function that returns S(1). struct S { bool opEquals(const ref S rhs) { return val == rhs.val; } int val; } S func() { return S(1); } void main() { auto s = S(1); assert(s == S(1)); //compiles assert(s == func()); //doesn't compile } Obviously, this is a complicated issue, but the situation above is downright confusing to many people (e.g. http://stackoverflow.com/questions/6986175/const-ref-and-rvalue-in-d ). It seems completely inconsistent. Even if C++ treats stuff as lvalues or not in exactly the same way in D, it's not an issue in the same way in C++, since const S& will take a temporary in C++, whereas const ref S won't take a temporary in D. - Jonathan M Davis |
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 5 September 2011 09:35, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> On Monday, September 05, 2011 00:27:05 Walter Bright wrote:
>> On 9/4/2011 11:41 PM, Jonathan M Davis wrote:
>> > It still baffles me why anything other than a variable would be an lvalue
>>
>> *p is also an lvalue.
>
> Good point, but that's essentially the same as setting the return value of a function that returns by ref, which essentially is a variable. But I guess that it does come down to an address more than a variable. What I really don't get is the temporaries such as when you construct a struct in place - e.g. S(1) - functioning as lvalues. The result is that if you have an opEquals which takes const ref like it's supposed to (or any function which takes a const ref, but opEquals is a good example), then you can pass it S(1) but not a the result of a function that returns S(1).
>
> struct S
> {
> ? ?bool opEquals(const ref S rhs)
> ? ?{
> ? ? ? ?return val == rhs.val;
> ? ?}
>
> ? ?int val;
> }
>
> S func()
> {
> ? ?return S(1);
> }
>
> void main()
> {
> ? ?auto s = S(1);
> ? ?assert(s == S(1)); //compiles
> ? ?assert(s == func()); //doesn't compile
> }
>
> Obviously, this is a complicated issue, but the situation above is downright confusing to many people (e.g. http://stackoverflow.com/questions/6986175/const-ref-and-rvalue-in-d ). It seems completely inconsistent. Even if C++ treats stuff as lvalues or not in exactly the same way in D, it's not an issue in the same way in C++, since const S& will take a temporary in C++, whereas const ref S won't take a temporary in D.
It's not merely confusing. AFAIK there is no possible signature of
opEquals which actually works.
I think two different issues may be being conflated here, though.
I think there's more of a problem with the semantics of 'const ref'
and 'auto ref', than with literals being lvalues.
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | On Monday, September 05, 2011 09:46:02 Don Clugston wrote:
> On 5 September 2011 09:35, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> > On Monday, September 05, 2011 00:27:05 Walter Bright wrote:
> >> On 9/4/2011 11:41 PM, Jonathan M Davis wrote:
> >> > It still baffles me why anything other than a variable would be an lvalue
> >>
> >> *p is also an lvalue.
> >
> > Good point, but that's essentially the same as setting the return value of a function that returns by ref, which essentially is a variable. But I guess that it does come down to an address more than a variable. What I really don't get is the temporaries such as when you construct a struct in place - e.g. S(1) - functioning as lvalues. The result is that if you have an opEquals which takes const ref like it's supposed to (or any function which takes a const ref, but opEquals is a good example), then you can pass it S(1) but not a the result of a function that returns S(1).
> >
> > struct S
> > {
> > bool opEquals(const ref S rhs)
> > {
> > return val == rhs.val;
> > }
> >
> > int val;
> > }
> >
> > S func()
> > {
> > return S(1);
> > }
> >
> > void main()
> > {
> > auto s = S(1);
> > assert(s == S(1)); //compiles
> > assert(s == func()); //doesn't compile
> > }
> >
> > Obviously, this is a complicated issue, but the situation above is downright confusing to many people (e.g. http://stackoverflow.com/questions/6986175/const-ref-and-rvalue-in-d ). It seems completely inconsistent. Even if C++ treats stuff as lvalues or not in exactly the same way in D, it's not an issue in the same way in C++, since const S& will take a temporary in C++, whereas const ref S won't take a temporary in D.
>
> It's not merely confusing. AFAIK there is no possible signature of
> opEquals which actually works.
> I think two different issues may be being conflated here, though.
> I think there's more of a problem with the semantics of 'const ref'
> and 'auto ref', than with literals being lvalues.
Well, at present you can declare a second version of opEquals which takes its argument by value, and it works. But opEquals isn't really the issue. It's the fact that const ref works with literals but not the return values of functions - both of which are temporaries. Sure, sorting out auto ref will help, but unless const ref starts taking any temporary as in C++ (which Andrei is dead set against), then the fact that literals are considered lvalues but function return values aren't is going to cause confusion with any functions which take const ref.
- Jonathan M Davis
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 5 September 2011 10:15, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> On Monday, September 05, 2011 09:46:02 Don Clugston wrote:
>> On 5 September 2011 09:35, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
>> > On Monday, September 05, 2011 00:27:05 Walter Bright wrote:
>> >> On 9/4/2011 11:41 PM, Jonathan M Davis wrote:
>> >> > It still baffles me why anything other than a variable would be an lvalue
>> >>
>> >> *p is also an lvalue.
>> >
>> > Good point, but that's essentially the same as setting the return value of a function that returns by ref, which essentially is a variable. But I guess that it does come down to an address more than a variable. What I really don't get is the temporaries such as when you construct a struct in place - e.g. S(1) - functioning as lvalues. The result is that if you have an opEquals which takes const ref like it's supposed to (or any function which takes a const ref, but opEquals is a good example), then you can pass it S(1) but not a the result of a function that returns S(1).
>> >
>> > struct S
>> > {
>> > ? ?bool opEquals(const ref S rhs)
>> > ? ?{
>> > ? ? ? ?return val == rhs.val;
>> > ? ?}
>> >
>> > ? ?int val;
>> > }
>> >
>> > S func()
>> > {
>> > ? ?return S(1);
>> > }
>> >
>> > void main()
>> > {
>> > ? ?auto s = S(1);
>> > ? ?assert(s == S(1)); //compiles
>> > ? ?assert(s == func()); //doesn't compile
>> > }
>> >
>> > Obviously, this is a complicated issue, but the situation above is downright confusing to many people (e.g. http://stackoverflow.com/questions/6986175/const-ref-and-rvalue-in-d ). It seems completely inconsistent. Even if C++ treats stuff as lvalues or not in exactly the same way in D, it's not an issue in the same way in C++, since const S& will take a temporary in C++, whereas const ref S won't take a temporary in D.
>>
>> It's not merely confusing. AFAIK there is no possible signature of
>> opEquals which actually works.
>> I think two different issues may be being conflated here, though.
>> I think there's more of a problem with the semantics of 'const ref'
>> and 'auto ref', than with literals being lvalues.
>
> Well, at present you can declare a second version of opEquals which takes its argument by value, and it works.
I've never been able to get that to work. Although you can get those two to work, it fails in other cases. Eg, as in the code below. Have you been able to do this successfully?
struct S
{
bool opEquals(const ref S rhs) const
{
return val == rhs.val;
}
bool opEquals(S rhs) const
{
return val == rhs.val;
}
int val;
}
S func()
{
return S(1);
}
void main()
{
auto s = S(1);
assert(s == S(1)); //compiles, const ref
assert(s == func()); // compiles, value
immutable s2 = S(1);
assert(s==s2); // fails, ambiguous
}
|
September 05, 2011 [phobos] [D-Programming-Language/phobos] 601c75: Improve parsing error handling | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | On Monday, September 05, 2011 11:20:57 Don Clugston wrote:
> On 5 September 2011 10:15, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> > On Monday, September 05, 2011 09:46:02 Don Clugston wrote:
> >> On 5 September 2011 09:35, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> >> > On Monday, September 05, 2011 00:27:05 Walter Bright wrote:
> >> >> On 9/4/2011 11:41 PM, Jonathan M Davis wrote:
> >> >> > It still baffles me why anything other than a variable would
> >> >> > be an
> >> >> > lvalue
> >> >>
> >> >> *p is also an lvalue.
> >> >
> >> > Good point, but that's essentially the same as setting the return value of a function that returns by ref, which essentially is a variable. But I guess that it does come down to an address more than a variable. What I really don't get is the temporaries such as when you construct a struct in place - e.g. S(1) - functioning as lvalues. The result is that if you have an opEquals which takes const ref like it's supposed to (or any function which takes a const ref, but opEquals is a good example), then you can pass it S(1) but not a the result of a function that returns S(1).
> >> >
> >> > struct S
> >> > {
> >> > bool opEquals(const ref S rhs)
> >> > {
> >> > return val == rhs.val;
> >> > }
> >> >
> >> > int val;
> >> > }
> >> >
> >> > S func()
> >> > {
> >> > return S(1);
> >> > }
> >> >
> >> > void main()
> >> > {
> >> > auto s = S(1);
> >> > assert(s == S(1)); //compiles
> >> > assert(s == func()); //doesn't compile
> >> > }
> >> >
> >> > Obviously, this is a complicated issue, but the situation above is downright confusing to many people (e.g. http://stackoverflow.com/questions/6986175/const-ref-and-rvalue-in -d ). It seems completely inconsistent. Even if C++ treats stuff as lvalues or not in exactly the same way in D, it's not an issue in the same way in C++, since const S& will take a temporary in C++, whereas const ref S won't take a temporary in D.
> >>
> >> It's not merely confusing. AFAIK there is no possible signature of
> >> opEquals which actually works.
> >> I think two different issues may be being conflated here, though.
> >> I think there's more of a problem with the semantics of 'const ref'
> >> and 'auto ref', than with literals being lvalues.
> >
> > Well, at present you can declare a second version of opEquals which takes its argument by value, and it works.
>
> I've never been able to get that to work. Although you can get those two to work, it fails in other cases. Eg, as in the code below. Have you been able to do this successfully?
>
> struct S
> {
> bool opEquals(const ref S rhs) const
> {
> return val == rhs.val;
> }
> bool opEquals(S rhs) const
> {
> return val == rhs.val;
> }
>
> int val;
> }
>
> S func()
> {
> return S(1);
> }
>
> void main()
> {
> auto s = S(1);
> assert(s == S(1)); //compiles, const ref
> assert(s == func()); // compiles, value
> immutable s2 = S(1);
> assert(s==s2); // fails, ambiguous
> }
Probably not. I don't think that I've tried though. I'm not sure how often I've used immutable structs in a context that ended up using an equality check.
Regardless, opEquals obviously needs to be sorted out. You shouldn't need two definitions like that to get it to work even if they did work in all cases.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation