www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ouch: return values as lvalue

reply Lionello Lunesu <lio lunesu.remove.com> writes:
Consider this home-made const:

struct Task {
   char[] ID;
}
private Task _CurrentTask; //mutable
public Task CurrentTask() { return _CurrentTask; } //const

public void StopTask() {
   CurrentTask.ID = null;
}

Notice the bug? That last line should read "_CurrentTask.ID = null;"

Isn't there something the compiler can do to help me catch these bugs?

L.
Jan 30 2007
next sibling parent reply "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
Lionello Lunesu wrote:
 Consider this home-made const:
 
 struct Task {
   char[] ID;
 }
 private Task _CurrentTask; //mutable
 public Task CurrentTask() { return _CurrentTask; } //const
 
 public void StopTask() {
   CurrentTask.ID = null;
 }
 
 Notice the bug? That last line should read "_CurrentTask.ID = null;"
 
 Isn't there something the compiler can do to help me catch these bugs?

const will take care of it. The code above fetches a member of an rvalue, which is an lvalue. Andrei
Jan 30 2007
next sibling parent reply "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Andrei Alexandrescu (See Website For Email)" 
<SeeWebsiteForEmail erdani.org> wrote in message 
news:45BF7C8B.3080506 erdani.org...
 Lionello Lunesu wrote:
 Consider this home-made const:

 struct Task {
   char[] ID;
 }
 private Task _CurrentTask; //mutable
 public Task CurrentTask() { return _CurrentTask; } //const

 public void StopTask() {
   CurrentTask.ID = null;
 }

 Notice the bug? That last line should read "_CurrentTask.ID = null;"

 Isn't there something the compiler can do to help me catch these bugs?

const will take care of it. The code above fetches a member of an rvalue, which is an lvalue.

Yeah, I know, but it's odd: it's setting a member in a struct that's about to be deleted. It's like writing "{ int id=4; }". Wouldn't it be possible for the compiler to warn about "code without side-effect" or something? L.
Jan 30 2007
next sibling parent "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
Lionello Lunesu wrote:
 "Andrei Alexandrescu (See Website For Email)" 
 <SeeWebsiteForEmail erdani.org> wrote in message 
 news:45BF7C8B.3080506 erdani.org...
 Lionello Lunesu wrote:
 Consider this home-made const:

 struct Task {
   char[] ID;
 }
 private Task _CurrentTask; //mutable
 public Task CurrentTask() { return _CurrentTask; } //const

 public void StopTask() {
   CurrentTask.ID = null;
 }

 Notice the bug? That last line should read "_CurrentTask.ID = null;"

 Isn't there something the compiler can do to help me catch these bugs?

which is an lvalue.

Yeah, I know, but it's odd: it's setting a member in a struct that's about to be deleted. It's like writing "{ int id=4; }". Wouldn't it be possible for the compiler to warn about "code without side-effect" or something?

Probably it could, but sometimes the object will be used: foo(bar().baz += 1); But that can be detected, too. But in generic code you can't rely on one specific expectation. And Walter hates warnings :o). Andrei
Jan 30 2007
prev sibling parent reply "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
Lionello Lunesu wrote:
 "Andrei Alexandrescu (See Website For Email)" 
 <SeeWebsiteForEmail erdani.org> wrote in message 
 news:45BF7C8B.3080506 erdani.org...
 Lionello Lunesu wrote:
 Consider this home-made const:

 struct Task {
   char[] ID;
 }
 private Task _CurrentTask; //mutable
 public Task CurrentTask() { return _CurrentTask; } //const

 public void StopTask() {
   CurrentTask.ID = null;
 }

 Notice the bug? That last line should read "_CurrentTask.ID = null;"

 Isn't there something the compiler can do to help me catch these bugs?

which is an lvalue.

Yeah, I know, but it's odd: it's setting a member in a struct that's about to be deleted. It's like writing "{ int id=4; }". Wouldn't it be possible for the compiler to warn about "code without side-effect" or something?

It's a long discussion. I agree that non-templated code without effect should issue a compile-time error (not warning) _____as long as under no change of type definitions etc., the code could make sense_____. Consider: struct RealLock { ... } struct DummyLock { ... } alias DummyLock Lock; { Lock lock; ... } DummyLock doesn't do anything. The idea is that the user would replace the alias with RealLock in a multithreaded application. The compiler shouldn't issue an error, even though the code appears to do nothing interesting. Andrei
Jan 30 2007
next sibling parent reply "Joel C. Salomon" <JoelCSalomon Gmail.com> writes:
Andrei Alexandrescu (See Website For Email) wrote:
 It's a long discussion. I agree that non-templated code without effect 
 should issue a compile-time error (not warning) _____as long as under no 
 change of type definitions etc., the code could make sense_____.

while(func() == 0) ; — or do you only mean that extremely short-lived (effect-less) /assignments/ should be errors? --Joel
Jan 30 2007
parent reply "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 It's a long discussion. I agree that non-templated code without effect 
 should issue a compile-time error (not warning) _____as long as under 
 no change of type definitions etc., the code could make sense_____.

while(func() == 0) ; — or do you only mean that extremely short-lived (effect-less) /assignments/ should be errors?

Code in general. Consider: 1 + 1 == 2; The code above isn't an error but it also doesn't do anything. It should be flagged as an error. The empty statement in your example is not "code" the way I meant it above. Andrei
Jan 30 2007
parent reply "Joel C. Salomon" <JoelCSalomon Gmail.com> writes:
Andrei Alexandrescu (See Website For Email) wrote:
 Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 It's a long discussion. I agree that non-templated code without 
 effect should issue a compile-time error (not warning) _____as long 
 as under no change of type definitions etc., the code could make 
 sense_____.

while(func() == 0) ; — or do you only mean that extremely short-lived (effect-less) /assignments/ should be errors?

Code in general. Consider: 1 + 1 == 2; The code above isn't an error but it also doesn't do anything. It should be flagged as an error. The empty statement in your example is not "code" the way I meant it above.

And the lack of a preprocessor means statements like that are unlikely to happen “by accident”. (I’m afraid I’m still thinking in C.) Unless this is the sort of thing a code generator might write. --Joel
Jan 30 2007
parent reply "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 It's a long discussion. I agree that non-templated code without 
 effect should issue a compile-time error (not warning) _____as long 
 as under no change of type definitions etc., the code could make 
 sense_____.

while(func() == 0) ; — or do you only mean that extremely short-lived (effect-less) /assignments/ should be errors?

Code in general. Consider: 1 + 1 == 2; The code above isn't an error but it also doesn't do anything. It should be flagged as an error. The empty statement in your example is not "code" the way I meant it above.

And the lack of a preprocessor means statements like that are unlikely to happen “by accident”. (I’m afraid I’m still thinking in C.) Unless this is the sort of thing a code generator might write.

Which is exactly what templates do. But, as I show in another post, all you really need is an alias. Andrei
Jan 30 2007
parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Andrei Alexandrescu (See Website For Email) wrote:
 Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 It's a long discussion. I agree that non-templated code without 
 effect should issue a compile-time error (not warning) _____as long 
 as under no change of type definitions etc., the code could make 
 sense_____.

while(func() == 0) ; — or do you only mean that extremely short-lived (effect-less) /assignments/ should be errors?

Code in general. Consider: 1 + 1 == 2; The code above isn't an error but it also doesn't do anything. It should be flagged as an error. The empty statement in your example is not "code" the way I meant it above.

And the lack of a preprocessor means statements like that are unlikely to happen “by accident”. (I’m afraid I’m still thinking in C.) Unless this is the sort of thing a code generator might write.

Which is exactly what templates do. But, as I show in another post, all you really need is an alias. Andrei

so a template *could* theoretically generate code like that for some input. Then .. if the compiler issued an error for it .. don't you think the situation would be "the compiler is getting in your way"?
Jan 30 2007
parent Lionello Lunesu <lio lunesu.remove.com> writes:
Hasan Aljudy wrote:
 
 
 Andrei Alexandrescu (See Website For Email) wrote:
 Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 Joel C. Salomon wrote:
 Andrei Alexandrescu (See Website For Email) wrote:
 It's a long discussion. I agree that non-templated code without 
 effect should issue a compile-time error (not warning) _____as 
 long as under no change of type definitions etc., the code could 
 make sense_____.

while(func() == 0) ; — or do you only mean that extremely short-lived (effect-less) /assignments/ should be errors?

Code in general. Consider: 1 + 1 == 2; The code above isn't an error but it also doesn't do anything. It should be flagged as an error. The empty statement in your example is not "code" the way I meant it above.

And the lack of a preprocessor means statements like that are unlikely to happen “by accident”. (I’m afraid I’m still thinking in C.) Unless this is the sort of thing a code generator might write.

Which is exactly what templates do. But, as I show in another post, all you really need is an alias. Andrei

so a template *could* theoretically generate code like that for some input. Then .. if the compiler issued an error for it .. don't you think the situation would be "the compiler is getting in your way"?

Yes, that's probably why Walter is opposed to warnings. See his post. L.
Jan 30 2007
prev sibling parent Walter Bright <newshound digitalmars.com> writes:
Andrei Alexandrescu (See Website For Email) wrote:
 The compiler shouldn't issue an error, even though the code appears to 
 do nothing interesting.

I agree that the language should be very careful about issuing errors for code that doesn't do anything.
Jan 30 2007
prev sibling parent reply "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Andrei Alexandrescu (See Website For Email)" 
<SeeWebsiteForEmail erdani.org> wrote in message 
news:45BF7C8B.3080506 erdani.org...
 Lionello Lunesu wrote:
 Consider this home-made const:

 struct Task {
   char[] ID;
 }
 private Task _CurrentTask; //mutable
 public Task CurrentTask() { return _CurrentTask; } //const

 public void StopTask() {
   CurrentTask.ID = null;
 }

 Notice the bug? That last line should read "_CurrentTask.ID = null;"

 Isn't there something the compiler can do to help me catch these bugs?

const will take care of it. The code above fetches a member of an rvalue, which is an lvalue.

I've been thinking about this some more. Why exactly is a member of an rvalue, an lvalue? struct S { int i; } //foo returns a struct, which is placed on stack/register, somewhere anyway S foo(); foo() = myS; // not allowed foo().i = 2; // suddenly allowed! Why? // func returns an int, which is also placed somewhere, // physically, stack/register doesn't matter int func(); func() = 2; // I can't write this... why? What exactly is the difference between setting the whole thing, or only one of its members? In the case of S above, there's no real difference, yet they behave differently? L.
Jan 30 2007
parent "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
Lionello Lunesu wrote:
 "Andrei Alexandrescu (See Website For Email)" 
 <SeeWebsiteForEmail erdani.org> wrote in message 
 news:45BF7C8B.3080506 erdani.org...
 Lionello Lunesu wrote:
 Consider this home-made const:

 struct Task {
   char[] ID;
 }
 private Task _CurrentTask; //mutable
 public Task CurrentTask() { return _CurrentTask; } //const

 public void StopTask() {
   CurrentTask.ID = null;
 }

 Notice the bug? That last line should read "_CurrentTask.ID = null;"

 Isn't there something the compiler can do to help me catch these bugs?

which is an lvalue.

I've been thinking about this some more. Why exactly is a member of an rvalue, an lvalue? struct S { int i; } //foo returns a struct, which is placed on stack/register, somewhere anyway S foo(); foo() = myS; // not allowed foo().i = 2; // suddenly allowed! Why? // func returns an int, which is also placed somewhere, // physically, stack/register doesn't matter int func(); func() = 2; // I can't write this... why? What exactly is the difference between setting the whole thing, or only one of its members? In the case of S above, there's no real difference, yet they behave differently?

I think that's a good point, but I wouldn't put a lot of faith in it. An rvalue accepts member function calls, which in turn can return things like pointers (now) or lvalues (later). Probably calling certain members should be disallowed on rvalue objects, but right now D does not give such flexibility. Andrei
Jan 30 2007
prev sibling parent reply Oth Erou <Oth erou.ch> writes:
Lionello Lunesu Wrote:

 Notice the bug?

real res = 0.01; while(res < 0,1) { if (res >= 0.1) printf("shooting over: %f\n", res), printf("Increasing.\n"); res*=1+1e-10; } }
Jan 30 2007
parent reply "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Oth Erou" <Oth erou.ch> wrote in message 
news:epodno$1lvp$1 digitaldaemon.com...
 Lionello Lunesu Wrote:

 Notice the bug?

real res = 0.01; while(res < 0,1) { if (res >= 0.1) printf("shooting over: %f\n", res), printf("Increasing.\n"); res*=1+1e-10; } }

The , ? :) Nice one!
Jan 30 2007
parent Oth Erou <oth erou.ch> writes:
Lionello Lunesu Wrote:
 The , ? :) Nice one! 

In fact there are two bugs according to typos, which have changed a single character and go undetected by the compiler.
Jan 31 2007