[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2022-12-17 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=3008

Iain Buclaw  changed:

   What|Removed |Added

   Priority|P2  |P3

--


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2019-09-27 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=3008

RazvanN  changed:

   What|Removed |Added

 CC||razvan.nitu1...@gmail.com

--- Comment #23 from RazvanN  ---
Andrei recently made a PR to the spec to clarify the definition of
rvalues/lvalues, the result of which can be seen here [1]. It clearly states:

"Definition ("Lvalue"): [...]

a variable or the result of the DotIdentifier grammatical construct . (left
side may be missing) when the rightmost side of the dot is a variable, field
(direct or static), function name, or invocation of a function that returns by
reference;"

Acoording to these rules, this bug report is invalid.

[1] https://dlang.org/spec/expression.html

--


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-31 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #22 from Steven Schveighoffer schvei...@yahoo.com  2009-07-31 
06:11:34 PDT ---
(In reply to comment #20)
 (In reply to comment #18)
   It's not going away because MyNiftyPointerTo!(C).getValue is an lvalue.
  
  MyNiftyPointerTo!(C) does not have a function called getValue, it is the 
  return
  type from getValue
  
 
 Ah, sorry.  I was confused because the meaning of getValue changed and foo was
 never defined in MyNiftyPointerTo!(T).

Yes, I probably could have made that clearer, but the type was supposed to be a
functional replacement for C in that it hooks all calls to the underlying type.

 
   But I'm going to answer the question anyways ...
  
  Incidentally, I can type quite fast and I have never EVER wanted to save
  keystrokes when it sacrifices clarity.  My protests have nothing to do with
  saving keystrokes, they have to do with generic code -- writing code that 
  works
  whether something is a builtin or a custom wrapper type.
 
 So MyNiftyPointerTo!(T) may grab all of the compile-time reflection info from 
 T
 and forward all of its functions and such.  Then it becomes a reference to 
 some
 T, but not a reference in a sense the compiler knows about.  

Yes.  That is a good way of explaining it.

 I think I can see now where you're going with this.  
 
 I suppose to really make everyone happy, there would need to be some way to
 annotate struct definitions and say, Hey, this thing can be mutated as an
 rvalue, it's all under control.  That probably doesn't make Walter happy
 though :(

Due to the nature of the problem, I don't think there's any way to solve it, as
it reduces to the halting problem as BCS says.  And limiting it makes the
language less powerful than languages that don't forbid it (such as C# and
C++).  Without this ability, it will be a sticking point for people who don't
want to convert :)  I think we can pick better battles.

However, annotating such structs might be OK.  I am unsure how often this
annoyance would surface, so I'm unsure how much annotation is required.  If you
have to annotate more than 25% of structs just to get them to work correctly,
then I don't think it's worth it.

 
 Still, without any major change to the language, we can at least forbid the
 assignment to members of rvalues as BCS suggested in comment #11, correct?

Yes, I think that should solve quite a few mistakes that people often make,
such as the Widget/Rectangle error.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #5 from Chad Joan chadj...@gmail.com  2009-07-30 01:50:28 PDT ---
(In reply to comment #4)
 
 I think you are right that it can be determined in simple cases, but for sure
 there will be cases that the compiler cannot diagnose, such as:
 
 int _global;
 
 struct S
 {
   int _x;
   version(noop)
 void x(int n) { _x = n;}
   else
 void x(int n) { _global = n;}
 }
 
 struct S2
 {
   S foo() { return S(5);}
 }
 
 void main()
 {
   S2 s2;
   s2.foo.x = 5;
 }
 
 How does the compiler know when compiling with noop that the s2.foo.x = 5
 doesn't do anything?  Especially if the module containing main is using a di
 file to define S and S2.
 
 The result is, I don't think the compiler can diganose the complex cases, and
 most of the time, the cases are complex.

It's easy for the compiler to know that s2.foo.x = 5 does nothing.  When
compiling with noop, the void x(int n) { _global = n;} version just does not
get compiled.  Period.  When s2.foo.x = 5; is being analysed, the compiler
will walk the syntax tree for void x(int n) { _x = n;} and discover that
s2.foo is an rvalue.  This is what it already does, minus the discover that
s2.foo is an rvalue part.  

Of course, s2.foo().x(5) violates the principle at play here.  At this point,
the whole version(noop) thing is just fluff, and here is the meat of the
matter.  In this example, s2.foo.x = 5; does actually do something and is
reasonable code.  However, naively forbidding an rvalue on the lhs of an assign
expression will make that code fail to compile.  I don't feel that code like
this is terribly common or that much better than the alternatives, so it is
probably worth losing some corner cases like these for the sake of preventing
nasty bugs.  

.di files change absolutely nothing.  They are .d files that just happen to be
mostly definitions because dmd generated that way.  There is nothing in the
spec saying that they even need to exist.  More importantly, Walter was
intentional about omitting them from the spec.

D interface files bear some analogous similarities to C++ header files. But
they are not required in the way that C++ header files are, and they are not
part of the D language. They are a feature of the compiler, and serve only as
an optimization of the build process.
http://www.digitalmars.com/d/2.0/dmd-linux.html#interface_files

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #6 from Chad Joan chadj...@gmail.com  2009-07-30 02:09:09 PDT ---
On the newsgroup KennyTM~ pointed out that opDot() also suffers from this
problem:

struct S {
  int s;
}

class X {
  S opDot() { S temp; temp.s = 6; return temp; }
}

X z = new X;
assert(z.s == 6);
z.s = 3;
assert(z.s == 6);

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #8 from BCS shro8...@vandals.uidaho.edu  2009-07-30 09:23:10 PDT 
---
(In reply to comment #5)
 
 It's easy for the compiler to know that s2.foo.x = 5 does nothing.  When
 compiling with noop, the void x(int n) { _global = n;} version just does not
 get compiled.  Period.  When s2.foo.x = 5; is being analysed, the compiler
 will walk the syntax tree for void x(int n) { _x = n;} and discover that
 s2.foo is an rvalue.  This is what it already does, minus the discover that
 s2.foo is an rvalue part.

This assumes that the body of x is available for analysis and is simple enough
to be analysed. 

The first will not be true of any C function, any function that calls a C
function (etc.), any closed source lib or any function that calls into a closed
source lib (etc.). 

The second will not be true in general because it can devolve into the halting
problem. 

To keep things consistent, the rules used have to be defined in the spec,
practicely ruling out powerful heuristics and computation logic systems, and
have to act the same regardless of accessability to source, strongly ruling out
anything that uses inter-procedural analysis (Walter has several times stated
that semantic rules that require analysis of non local code are not going to
happen).

 .di files change absolutely nothing.

Technically, yes. .di files don't actually /add/ any problems here because the
problems at issue can be caused by a .d file as well.

 They are .d files that just happen to be
 mostly definitions because dmd generated that way.  There is nothing in the
 spec saying that they even need to exist.

Any implementation that doesn't give the same functionality as .di files
(no-source symbol decelerations) effectively eliminates the ability to have
closed source D libraries. Therefor, the feature causing problems effectively
is part of the spec.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #9 from Chad Joan chadj...@gmail.com  2009-07-30 10:38:44 PDT ---
(In reply to comment #7)
 (In reply to comment #5)
 
  Of course, s2.foo().x(5) violates the principle at play here.  At this 
  point,
  the whole version(noop) thing is just fluff, and here is the meat of the
  matter.  In this example, s2.foo.x = 5; does actually do something and is
  reasonable code.  However, naively forbidding an rvalue on the lhs of an 
  assign
  expression will make that code fail to compile.  I don't feel that code like
  this is terribly common or that much better than the alternatives, so it is
  probably worth losing some corner cases like these for the sake of 
  preventing
  nasty bugs.  
 
 You are killing the entire feature of making user-defined builtin types, 
 such
 as a custom pointer type.  Since those would undoubtedly be structs, and
 therefore returned as rvalues, you could not use them for anything without
 first creating lvalues out of them.  If we are to have such constructs, they
 should be on par with native pointers.  At the very least, we should have a 
 way
 to mark such structs as allow rvalue operations.  I would be ok with that.

You make it sound like we wouldn't be able to use structs anymore!

Not the case.  

struct S
{
  int _x;
  version(noop)
void x(int n) { _x = n;}
  else
void x(int n) { _global = n;}
}

struct S2
{
  S foo() { return S(5);}
}

void main()
{
S2 s2;

s2.foo.x = 5; // not good.

int bar = s2.foo.x + 42; // fine, rvalue is not mutated, only read.

auto s = s2.foo;
s.x = 5; // fine

S s1;
s1.x = 5; // fine
s1._x; // fine, it was declared public.
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #10 from Chad Joan chadj...@gmail.com  2009-07-30 10:46:27 PDT ---
(In reply to comment #8)
 (In reply to comment #5)
  
  It's easy for the compiler to know that s2.foo.x = 5 does nothing.  When
  compiling with noop, the void x(int n) { _global = n;} version just does 
  not
  get compiled.  Period.  When s2.foo.x = 5; is being analysed, the compiler
  will walk the syntax tree for void x(int n) { _x = n;} and discover that
  s2.foo is an rvalue.  This is what it already does, minus the discover that
  s2.foo is an rvalue part.
 
 This assumes that the body of x is available for analysis and is simple enough
 to be analysed. 
 
 The first will not be true of any C function, any function that calls a C
 function (etc.), any closed source lib or any function that calls into a 
 closed
 source lib (etc.). 
 
 The second will not be true in general because it can devolve into the halting
 problem. 
 
 To keep things consistent, the rules used have to be defined in the spec,
 practicely ruling out powerful heuristics and computation logic systems, and
 have to act the same regardless of accessability to source, strongly ruling 
 out
 anything that uses inter-procedural analysis (Walter has several times stated
 that semantic rules that require analysis of non local code are not going to
 happen).
 

Oh my, I made it sound like the body of the thing would be analysed.  Poor
wording.

No that's not the case, I was mostly just referring to the declaration.  

The only thing that matters there is that it looks at foo's return type, finds
an rvalue, and thinks hmmm, that might mess up someone's day.

My point was that it doesn't matter whether it looks at the noop version or the
non-noop version, either way it finds the same rvalue in the return and decides
to the negative.

  .di files change absolutely nothing.
 
 Technically, yes. .di files don't actually /add/ any problems here because the
 problems at issue can be caused by a .d file as well.
 
  They are .d files that just happen to be
  mostly definitions because dmd generated that way.  There is nothing in the
  spec saying that they even need to exist.
 
 Any implementation that doesn't give the same functionality as .di files
 (no-source symbol decelerations) effectively eliminates the ability to have
 closed source D libraries. Therefor, the feature causing problems effectively
 is part of the spec.

.di files and bodyless function declarations, these are two different things. 
While I'm at a loss to find bodyless function declarations defined anywhere in
the spec, they do seem to be /used/ in the spec:
http://www.digitalmars.com/d/2.0/function.html#parameters

Of course, I was not by any means doing a thorough search.  I only checked the
obvious tabs Functions and Declarations.  (The spec seems hard to search :/
... needs more targeted search feature and liberal application of metadata.)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #11 from BCS shro8...@vandals.uidaho.edu  2009-07-30 10:59:32 PDT 
---

(In reply to comment #10)
 (In reply to comment #8)
  
  This assumes that the body of x is available for analysis and is simple 
  enough to be analysed. 
 
 Oh my, I made it sound like the body of the thing would be analysed.  Poor
 wording.
 
 No that's not the case, I was mostly just referring to the declaration.  
 
 The only thing that matters there is that it looks at foo's return type, finds
 an rvalue, and thinks hmmm, that might mess up someone's day.
 
 My point was that it doesn't matter whether it looks at the noop version or 
 the non-noop version, either way it finds the same rvalue in the return and 
 decides to the negative.
 

OK then that's another (potentially worse) problem because I can think of
several cases where I want to return a struct (by value) and invoke functions
on it. Based on your rule, I'd always have to store it in a local to do that. I
don't see that flying.

The only cases I can see being banned is member variable assignment on a struct
return.

  Any implementation that doesn't give the same functionality as .di files
  (no-source symbol decelerations) effectively eliminates the ability to have
  closed source D libraries. Therefor, the feature causing problems 
  effectively is part of the spec.
 
 .di files and bodyless function declarations, these are two different things. 

Well, as I pointed out, one or the other is needed so, either way, there side
effect have to be dealt with.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #12 from Steven Schveighoffer schvei...@yahoo.com  2009-07-30 
11:12:25 PDT ---
(In reply to comment #9)
 You make it sound like we wouldn't be able to use structs anymore!
 
 Not the case.  

What I mean is this:

original:

class C
{
  void foo();
}

struct S
{
   C getValue() {...}  
}

void main()
{
   S s;
   s.getValue.foo(); // should be allowed, getValue does not return an rvalue
}

new version (assume C is the same):

struct MyNiftyPointerTo(T)
{
  ...
}

struct S
{
   MyNiftyPointerTo!(C) getValue() {...}
}

void main()
{
  S s;
  s.getValue.foo(); // oops, compiler says MyNiftyPointerTo!(C) is an rvalue
because it's a struct.
}

What I'm saying is you have no ability to make wrapper or extended builtin
types because they are now always treated as rvalues even though their
semantics are entirely lvalue-ish.  Maybe MyNiftyPointerTo!(C) connects to a
remote object on a server, and invokes methods there.  You're saying this isn't
a valuable enough extension to the type system for D to allow it?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #13 from Chad Joan chadj...@gmail.com  2009-07-30 12:46:33 PDT ---
(In reply to comment #11)
 
 OK then that's another (potentially worse) problem because I can think of
 several cases where I want to return a struct (by value) and invoke functions
 on it. Based on your rule, I'd always have to store it in a local to do that. 
 I
 don't see that flying.
 
 The only cases I can see being banned is member variable assignment on a 
 struct
 return.
 

That'd be a start.

The problem then is that variable assignment is equivalent to function calls
with 1 parameter due to the omitable parentheses rule.  

Thus if we banned member variable assignment on struct returns, this happens:

struct Foo
{
int x;
int y(int val) { return x = val; }
}

Foo foo()
{
Foo f;
return f;
}

void main()
{
foo.x = 5; // compile error, member assignment on returned struct
foo.y = 5; // compiles just fine, function invoked on returned struct
   //   (but is a bug waiting to happen)
}

So yes, getting rid of the former is a step in the right direction.
That latter is still quite undesirable.

  
  .di files and bodyless function declarations, these are two different 
  things. 
 
 Well, as I pointed out, one or the other is needed so, either way, there side
 effect have to be dealt with.

Why does it matter for rvalues though?  We aren't analysing the function body, 
just the declaration, and that's something the compiler has to do anyways to
ensure type safety.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #14 from BCS shro8...@vandals.uidaho.edu  2009-07-30 13:02:20 PDT 
---

(In reply to comment #13)
 That'd be a start.
 
 The problem then is that variable assignment is equivalent to function calls
 with 1 parameter due to the omitable parentheses rule.  
 
 Thus if we banned member variable assignment on struct returns, this happens:
 
 struct Foo
 {
 int x;
 int y(int val) { return x = val; }
 }
 
 Foo foo()
 {
 Foo f;
 return f;
 }
 
 void main()
 {
 foo.x = 5; // compile error, member assignment on returned struct
 foo.y = 5; // compiles just fine, function invoked on returned struct
//   (but is a bug waiting to happen)
 }

While I can see where you are coming from, I have no problem at all with that.

  
  Well, as I pointed out, one or the other is needed so, either way, there 
  side
  effect have to be dealt with.
 
 Why does it matter for rvalues though?  We aren't analysing the function 
 body, 
 just the declaration, and that's something the compiler has to do anyways to
 ensure type safety.

See above. Without analyzing the function bodies, Applying all this to
functions will also ban things I'm not willing to give up.

As an example: should this be alowed:

struct S { void M(int arg) { ... } ... }
S fn() { ... }
fn().M = 5;

how about (the equivalent):

fn().M(5);

how about if I rename it:

struct OutputHandle { void Output(int arg) { ... } ... }
OutputHandle GetProcessOutput() { ... }
GetProcessOutput().Output(5);

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #16 from Chad Joan chadj...@gmail.com  2009-07-30 13:13:40 PDT ---
(In reply to comment #14)
 
 See above. Without analyzing the function bodies, Applying all this to
 functions will also ban things I'm not willing to give up.
 
 As an example: should this be alowed:
 
 struct S { void M(int arg) { ... } ... }
 S fn() { ... }
 fn().M = 5;
 
 how about (the equivalent):
 
 fn().M(5);
 
 how about if I rename it:
 
 struct OutputHandle { void Output(int arg) { ... } ... }
 OutputHandle GetProcessOutput() { ... }
 GetProcessOutput().Output(5);

ref returns.  They are awesome.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #17 from BCS shro8...@vandals.uidaho.edu  2009-07-30 13:26:32 PDT 
---

(In reply to comment #16)
 (In reply to comment #14)
  
  See above. Without analyzing the function bodies, Applying all this to
  functions will also ban things I'm not willing to give up.
  
  As an example: should this be alowed:
  
  struct S { void M(int arg) { ... } ... }
  S fn() { ... }
  fn().M = 5;
  
  how about (the equivalent):
  
  fn().M(5);
  
  how about if I rename it:
  
  struct OutputHandle { void Output(int arg) { ... } ... }
  OutputHandle GetProcessOutput() { ... }
  GetProcessOutput().Output(5);
 
 ref returns.  They are awesome.

You assume that the above is a bug and what I really wanted was to return a
reference. Take another look while assuming that I actual do want return by
value and the return by reference would be a bug.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #18 from Steven Schveighoffer schvei...@yahoo.com  2009-07-30 
13:40:56 PDT ---
(In reply to comment #15)
 Incorrect.
 
 s is an lvalue (it isn't being returned)
 s.getValue is an lvalue (pointer to some C's data, AKA a reference type)

*struct* MyNiftyPointerTo(T)

...

MyNiftyPointerTo!(C) getValue()

Read that carefully about 5 times

getValue returns a struct.  getValue returns an rvalue.  Please recognize this
before commenting again.

 It's not going away because MyNiftyPointerTo!(C).getValue is an lvalue.

MyNiftyPointerTo!(C) does not have a function called getValue, it is the return
type from getValue

 But I'm going to answer the question anyways ...

Incidentally, I can type quite fast and I have never EVER wanted to save
keystrokes when it sacrifices clarity.  My protests have nothing to do with
saving keystrokes, they have to do with generic code -- writing code that works
whether something is a builtin or a custom wrapper type.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #19 from Chad Joan chadj...@gmail.com  2009-07-30 14:00:29 PDT ---
(In reply to comment #17)
 
 You assume that the above is a bug and what I really wanted was to return a
 reference. Take another look while assuming that I actual do want return by
 value and the return by reference would be a bug.

I suppose what caught me is that it's easily possibly to write
GetProcessOutput() such that a ref return isn't a bug.  Just make sure the
reference doesn't point to an OutputHandle that's already in use.  I feel like
having a value return there is unnecessary.  

What I will give here though is that forbidding such function calls would
prevent the use of the caller's stack frame as a source of memory storage, but
only while using 1 liners to make the call.  It's complicated by the fact that
the function writer has to make the verbosity/efficiency tradeoff for the
caller.  

Then again...

ref OutputHandle GetProcessOutput( OutputHandle* buffer = null ) {...}

So it's possible to allow the caller to optionally provide stack space if they
want to, and still return ref.  If efficiency isn't an issue, it's still a
one-liner on the call side.

I'll admit that in the given circumstances this is not as clean.  Being able to
call off of rvalues allows both efficiency and brevity in this case.

I'd still rather have something that is a bit more verbose in some cases but
nearly impossible to unintentionally create bugs with.  It's not like actual
functionality is being removed.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #20 from Chad Joan chadj...@gmail.com  2009-07-30 14:16:00 PDT ---
(In reply to comment #18)
 (In reply to comment #15)
  Incorrect.
  
  s is an lvalue (it isn't being returned)
  s.getValue is an lvalue (pointer to some C's data, AKA a reference type)
 
 *struct* MyNiftyPointerTo(T)
 
 ...
 
 MyNiftyPointerTo!(C) getValue()
 
 Read that carefully about 5 times
 
 getValue returns a struct.  getValue returns an rvalue.  Please recognize this
 before commenting again.
 
  It's not going away because MyNiftyPointerTo!(C).getValue is an lvalue.
 
 MyNiftyPointerTo!(C) does not have a function called getValue, it is the 
 return
 type from getValue
 
  But I'm going to answer the question anyways ...
 
 Incidentally, I can type quite fast and I have never EVER wanted to save
 keystrokes when it sacrifices clarity.  My protests have nothing to do with
 saving keystrokes, they have to do with generic code -- writing code that 
 works
 whether something is a builtin or a custom wrapper type.

(In reply to comment #18)
 (In reply to comment #15)
  Incorrect.
  
  s is an lvalue (it isn't being returned)
  s.getValue is an lvalue (pointer to some C's data, AKA a reference type)
 
 *struct* MyNiftyPointerTo(T)
 
 ...
 
 MyNiftyPointerTo!(C) getValue()
 
 Read that carefully about 5 times
 
 getValue returns a struct.  getValue returns an rvalue.  Please recognize this
 before commenting again.
 
  It's not going away because MyNiftyPointerTo!(C).getValue is an lvalue.
 
 MyNiftyPointerTo!(C) does not have a function called getValue, it is the 
 return
 type from getValue
 

Ah, sorry.  I was confused because the meaning of getValue changed and foo was
never defined in MyNiftyPointerTo!(T).

  But I'm going to answer the question anyways ...
 
 Incidentally, I can type quite fast and I have never EVER wanted to save
 keystrokes when it sacrifices clarity.  My protests have nothing to do with
 saving keystrokes, they have to do with generic code -- writing code that 
 works
 whether something is a builtin or a custom wrapper type.

So MyNiftyPointerTo!(T) may grab all of the compile-time reflection info from T
and forward all of its functions and such.  Then it becomes a reference to some
T, but not a reference in a sense the compiler knows about.  

I think I can see now where you're going with this.  

I suppose to really make everyone happy, there would need to be some way to
annotate struct definitions and say, Hey, this thing can be mutated as an
rvalue, it's all under control.  That probably doesn't make Walter happy
though :(

Still, without any major change to the language, we can at least forbid the
assignment to members of rvalues as BCS suggested in comment #11, correct?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-30 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #21 from BCS shro8...@vandals.uidaho.edu  2009-07-30 14:35:05 PDT 
---
(In reply to comment #19)
 (In reply to comment #17)
  
  You assume that the above is a bug and what I really wanted was to return a
  reference. Take another look while assuming that I actual do want return by
  value and the return by reference would be a bug.
 
 I suppose what caught me is that it's easily possibly to write
 GetProcessOutput() such that a ref return isn't a bug.  Just make sure the
 reference doesn't point to an OutputHandle that's already in use.  I feel like
 having a value return there is unnecessary.  
 

In most cases you are probably correct but, while I can't enumerate a specific
example, I can imagine a cases where the value return us wanted for it's
semantics rather than for memory usage reasons. For instance something in the
direction of  smart pointers or keeping track of distinct handles to a common
resource.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-29 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #4 from Steven Schveighoffer schvei...@yahoo.com  2009-07-29 
10:11:26 PDT ---
(In reply to comment #3)
 Actually the compiler wouldn't have to do anything special here.  If the 
 return
 of foo() were an rvalue, then *foo().a could still be an lvalue, not because 
 of
 any special rules, but because of how the dereference operator works.

Yes, that would be helpful.

I think you are right that it can be determined in simple cases, but for sure
there will be cases that the compiler cannot diagnose, such as:

int _global;

struct S
{
  int _x;
  version(noop)
void x(int n) { _x = n;}
  else
void x(int n) { _global = n;}
}

struct S2
{
  S foo() { return S(5);}
}

void main()
{
  S2 s2;
  s2.foo.x = 5;
}

How does the compiler know when compiling with noop that the s2.foo.x = 5
doesn't do anything?  Especially if the module containing main is using a di
file to define S and S2.

The result is, I don't think the compiler can diganose the complex cases, and
most of the time, the cases are complex.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 3008] Members of non-lvalues (rvalues) can be assigned to.

2009-07-28 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=3008


Jarrett Billingsley jarrett.billings...@gmail.com changed:

   What|Removed |Added

 CC||jarrett.billings...@gmail.c
   ||om




--- Comment #3 from Jarrett Billingsley jarrett.billings...@gmail.com  
2009-07-28 18:09:12 PDT ---
(In reply to comment #2)
 Consider this actually sensical case:
 
 struct S
 {
   int *a;
 }
 
 S foo() {...}
 
 *foo.a = 3;
 
 Clearly, you don't want structs to be non-modifyiable in all cases.  If S has
 member functions which modify both values of S and values S references, then
 you should able to call those functions also.  It might be very difficult for
 the compiler to distinguish all these cases.

Actually the compiler wouldn't have to do anything special here.  If the return
of foo() were an rvalue, then *foo().a could still be an lvalue, not because of
any special rules, but because of how the dereference operator works.

A more thorough explanation: DMD will diagnose no-op statements such as:

x + y;

Since such code is dead and possibly a typo (say you accidentally shifted your
assignment operator there).  Code like:

struct S { int a; }
S foo() { return S(5); }
foo().a++;

Should be nonsensical for the same reason.  foo() is an rvalue, and
rvalue.field yields an rvalue.  Similarly, in your example, foo().a = new
int; would be nonsensical, since again, rvalue.field yields an rvalue.  But as
soon as you use the dereference operator, foo().a becomes an lvalue.  (In fact
I think KR describe * and  in such terms (turning lvalues into rvalues and
vice versa).)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---