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