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

Adam Wilson flyboynw at gmail.com
Fri Jan 25 11:10:56 PST 2013


On Fri, 25 Jan 2013 10:39:50 -0800, H. S. Teoh <hsteoh at quickfur.ath.cx>  
wrote:

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

++

-- 
Adam Wilson
IRC: LightBender
Project Coordinator
The Horizon Project
http://www.thehorizonproject.org/


More information about the Digitalmars-d mailing list