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 -- What are you when you run out of Monet? Baroque.