July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #10 from Chad Joan <chadjoan@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #11 from BCS <shro8822@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #12 from Steven Schveighoffer <schveiguy@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #13 from Chad Joan <chadjoan@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #14 from BCS <shro8822@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #15 from Chad Joan <chadjoan@gmail.com>  2009-07-30 13:10:29 PDT ---
(In reply to comment #12)
> (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.
> }
> 

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)
s.getValue.foo() function call on an lvalue.  fine.

It's the same logic as in Jarrett's comment (#3).  s may be a value type, but s.getValue returns a reference type (the class C).  It is the same thing as dereferencing a pointer, only it's hidden by saying that C is a "reference" type.  The only thing I'm unsure of is how hard it is to get the compiler to recognize this.

> 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?

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

But I'm going to answer the question anyways.  Even if this were a problem, I'd say no.  Just type the extra line of code.  Being a little less lazy here will pay off.  You are a programmer.  Unless you are mentally handicapped or had an unfortunate accident that crippled your hands, you type REALLY FAST.  Even on a bad day full of nasty symbols that require you to hold shift repeatedly you still type really fast!  You probably don't debug complicated code nearly as quickly.  So you can have a feature that will save you a fraction of a second here and there by requiring less typing, or you can have an absence of a feature that will save you a few hours here and there by preventing the existence of bugs.  Take your pick.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #16 from Chad Joan <chadjoan@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #17 from BCS <shro8822@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #18 from Steven Schveighoffer <schveiguy@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: -------
July 30, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=3008





--- Comment #19 from Chad Joan <chadjoan@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: -------