@property - take it behind the woodshed and shoot it?

Dmitry Olshansky dmitry.olsh at gmail.com
Fri Jan 25 12:41:51 PST 2013


25-Jan-2013 22:39, H. S. Teoh пишет:
> On Thu, Jan 24, 2013 at 12:34:42AM -0800, Walter Bright wrote:
>> This has turned into a monster. We've taken 2 or 3 wrong turns
>> somewhere.
>>
>> Perhaps we should revert to a simple set of rules.
>>
>> 1. Empty parens are optional. If there is an ambiguity with the
>> return value taking (), the () go on the return value.
>>
>> 2. the:
>>     f = g
>> rewrite to:
>>     f(g)
>> only happens if f is a function that only has overloads for () and
>> (one argument). No variadics.
>>
>> 3. Parens are required for calling delegates or function pointers.
>>
>> 4. No more @property.
>
> I've refrained so far from participating in this thread, but maybe it's
> time to say something.
>
> 1) @property and optional parentheses are orthogonal issues. Let's not
>     conflate them and cause more unnecessary confusion in what is already
>     a complex and convoluted discussion.
>
> 2) Personally, I don't like leaving out parentheses, but I don't really
>     care either way. In any case, this has nothing to do with @property.
>
> 3) So, as far as @property is concerned, let's forget about optional
>     parentheses or not.
>
> 3) @property is necessary for good abstraction. Yes, there have been
>     precedents of abuse (like .dup and .idup, which really should *not*
>     be properties but methods), and there are problems in the current
>     implementation of @property, but the _concept_ of @property itself is
>     a sound one. People have already mentioned the use case of a member
>     variable that needs to be replaced with a getter/setter method.
>     Conceptually speaking, the user of the class should not need to know
>     or care whether it's just a POD field or an abstract entity
>     manipulated by @property functions.
>
>     For example, an Array class has a .length property, and user code
>     should not need to know nor care if this length is an actual size_t
>     field, or something else. All it needs to know is you can get a
>     size_t out of it, and (optionally) change its value (if it's
>     non-const, or if there's a setter method).
>
>     Sometimes, you get into the situation where it's *possible* to
>     implement a @property as a plain old field, but not desirable because
>     of the SSOT (single source of truth) principle. It could be a
>     computed value based on implementation-specific parameters, for
>     example. It would not be nice if you had to store its value, then
>     change code everywhere to make sure that it's always updated when the
>     underlying parameters change. Lots of ugly, unnecessary, inefficient,
>     and fragile code.
>
>     Therefore, @property is necessary. If it causes a problem with the
>     syntax, well, that's a problem with the syntax, not with the concept
>     of @property itself.
>
> As far as syntax is concerned, it should be very straightforward. Given
> that the goal of @property is to simulate a variable, it should
> syntactically be identical to a variable, regardless of what it returns.
> So, given:
>
> 	struct S {
> 		@property T prop() { ... }
> 	}
> 	S s;
>
> Then:
>
> a) Writing s.prop returns a value of type T, for any type T (POD or
>     struct or class or delegate or whatever);
> b) Writing s.prop() invokes opCall on the *return value* (because .prop
>     behaves exactly as though it were an actual field);
> c) As a corollary, if T is not callable, then s.prop() is illegal;
> d) &s.prop returns a pointer to T (if .prop returns a ref).
> e) As for taking the address of the .prop function itself, my take on it
>     is that (i) from a user's POV, .prop should be indistinguishable from
>     a plain old field, so you shouldn't ever need to do this, and
>     therefore (ii) it's impossible, and (iii) if you *really* need to do
>     it, do this instead:
>
> 	struct S {
> 		@property T prop() { return this.propImpl(); }
>
> 		// You really only need to know about propImpl if you're
> 		// inside S's implementation anyway, so this is private.
> 		private T propImpl() { ... }
>
> 		void someMethod() {
> 			auto ptr = &propImpl;
> 			// There, now you have it.
> 		}
> 	}
>
> f) IOW, .prop cannot be distinguished from an actual field under normal
>     circumstances. If you *really* need to do this (e.g. in serialization
>     code), then use __traits.
>
> Consequently:
>
> - Assignment syntax like f=g should NOT be treated equivalently to f(g)
>    because conceptually it makes no sense. Writing writeln = "abc"; makes
>    no sense because writeln is not a value that you write to. Writing
>    s.prop = "abc" *does* make sense, because S.prop is a @property, and
>    therefore behaves like a variable. Writeln is a function, not a
>    @property, so this is illegal.
>
> - Syntax like s.prop++ should work automatically (equivalent to
>    s.prop(s.prop+1)), if .prop has both a getter and setter @property.
>    It should NOT be allowed for arbitrary methods m just because m has
>    both overloads of m() and m(T).
>
> - It's illegal to mark a function that takes 2 or more arguments as
>    @property, because it makes no sense.
>
> The bottom line is, if you mark a function as @property, then it should
> behave as if it were a variable of its return type. This has nothing to
> do with optional parentheses or not, and assignment syntax should be
> reserved for variables (and by extension @property, because @property
> means something behaves like a variable), not arbitrary functions.
>
>
> T
>

Good summary of what property should do. Let's just not forget that 
works like plain variable must clearly tackle contexts such as:

a.b.c.d = xyz;
//where b, c, d are properties

And things like:
a.prop += qwerty;

I can see how it must work from your proposal but listing some 
"canonical" re-writes won't hurt.

-- 
Dmitry Olshansky


More information about the Digitalmars-d mailing list