On Wed, 29 Jul 2009 18:27:09 -0400, Chad J <chadj...@__spam.is.bad__gmail.com> wrote:

Steven Schveighoffer wrote:
On Wed, 29 Jul 2009 15:01:47 -0400, Chad J
<chadj...@__spam.is.bad__gmail.com> wrote:

So we could have semantics that actually work, but you don't want them
because, oh man, my code might have to do a few more assignments. A few
assignments.  Really?!

Hold on a second, don't we already have semantics that work?  I mean we
can already write

auto tmp = a.b;
tmp.c = 5;
a.b = tmp;

So what is the big deal?  If your widget.position is a struct with
fields, then the compiler should be able to detect the error (not yet?)
and tell you "no, it's an rvalue."

Why should the compiler make assumptions about the logic of code when
they may be incorrect, and might be better optimized by a person?

I would think that macros would be a better fit for this.

Assignments aren't even that expensive!  They are one of the easiest
operations your CPU can perform!  It's like you'll have a few more MOV
operations laying around in the worst case.

It's not the assignments, its the idea that the compiler should
workaround the poor design of the code by writing possibly incorrect
code.  I'd rather be in charge of the design of my code, thanks.  If the
compiler help prevent me from making obvious *provable* mistakes, then
fine.  If it makes decisions that might be based on incomplete
information, I don't want that.

-Steve

Ah, well that argument has some weight.

I'd like to know though, what assumptions does this make about the code?
 Why might they be incorrect?

Simply that the compiler assumes it's simply setting a value. However, setters are functions and can execute any code they wish. You may get into weird states that you don't want to or perform unneeded actions that you aren't expecting.

The example given later in this thread is perfect -- setting the width and height individually may re-render the widget when you only should re-render once.

Another example is something like this:

class C
{
  int x;
}
struct S
{
  C c;
}

struct S2
{
  C c;
  S s() { return S(c); }
  void s(S s) {c = s.c;}
}

void main()
{
  S2 s2;
  s2.c = new C;
  s2.s.c.x = 5;
}

If the compiler rewrites that last line as:

auto tmp = s2.s;
s2.c.x = 5;
s2.s = tmp;

Then it is completely unnecessary, and could cause problems if the setter does something else besides setting.

If the compiler /knows/ that something being used is a property, I just
don't understand how that information is incomplete.

First, because the problem of determining what code does is an NP-complete problem -- the compiler can't know what code is going to do except by running it. It's just like trying to write a program that detects infinite loops. So it must make some assumptions.

Second, because D allows opaque function declarations, so the compiler might not even be able to *look* at what a property does. It can only assume, and the assumption you would have it make is that a property is a simple setter that has no other side effects.

Also macros aren't a good fit for this because they aren't going to
exist in D2, or necessarily ever.  Well, properties may not pop up in D2
either, but if they're going to happen it'd be nicer if they did.

I think you can solve this problem (and solve it correctly) with some sort of fancy template magic, but not without some extra baggage (such as an extra type that might not be optimized). I envision something like this:

with(Setter!(widget.location)) // don't know if this works
{
   width = 50;
   height = 100;
// at scope end, Setter sets widget.location to it's internal representation via a finalizer
}

The reason I said macros is because they have the power to rewrite the code exactly like you said the compiler should. At least with a macro you would have some indication that it is exactly what the user wants, and you can have the power to do your optimizations.

-Steve

Reply via email to