Miles wrote:
dsimcha wrote:
I figure the vast majority of cases are going to be primitive types anyhow
(mostly
ints),
Yes, this is very true.
and if someone defines operator overloads such that foo += 1 produces
totally different observable behavior than foo = foo + 1, that's just too
ridiculously bad a design to even take seriously.
Sure. It is bad coding style, it is ugly and the programmer who does
this should be called for a meeting with his boss. But there are still
ways to have sane behavior, even in such situations. See below.
What do you think? Is it worth
ignoring a few hard cases in exchange for solving most cases simply and
elegantly
and without adding any new constructs?
Instead, I think it is more sane to use temporaries.
----------
{
auto tmp = __get_foo();
tmp += 1;
__set_foo(foo);
}
----------
It is the safest this way, principle of least surprise. If the caller
does foo += 1, it will get that; if it does foo = foo + 1, it will still
get that; if it does foo.call(), again, the behavior is still sane.
We must first attack the semantics. This have sane semantics. Then let
the compiler optimize that as far as possible. The compiler inlines the
getter and setter calls, then optimizes away the temporary, etc.
Or the compiler could prevent properties from returning mutable structs?
class MyClass {
private MyStruct _a;
private MyStruct _b;
public property a {
const get { return _a; } // legal
}
public property a {
get { return _b; } // compile-time error
}
}
On the flip-side, the compiler could intervene at the call site,
preventing modification of structs when directly accessed via a property
invocation. Though I think the first solution is better.
--benji