January 25, 2013
On Fri, Jan 25, 2013 at 08:46:51PM +0100, mist wrote:
> On Friday, 25 January 2013 at 19:30:26 UTC, Jonathan M Davis wrote:
> >...
> 
> I am not going to argue anything, I am just asking _how_ they are
> supposed to work, what are exact semantic. I have added various
> syntax cases to wiki:
> http://wiki.dlang.org/Property_Discussion_Wrap-up#.40property_on_free_functions
> 
> What I am going to argue is if all of those example are supposed to work. We can't define property semantics to be "just like data" when property symbol can't be just interchanged with data symbol.
> 
> From the syntax point of view no issues there.

>From my stance that @property should make the function behave like a
variable, all of the examples in the above link can be resolved thus:


>	struct Type
>	{
>	    @property void native(int);
>	}

This should behave as though you wrote this:

	struct Type
	{
	    // const because there is no setter
	    const int native;
	}


>	@property void external1(int);       // valid? (no assignment context)

Valid, this is equivalent to defining a module-level variable:

	int external1;


>	@property void external2(Type, int); // valid? (extra parameter comparing to typical setter)

Valid, because UFCS lets you use it as though it were a member variable of Type.


>	void main()
>	{
>	    Type t;
>	    t.native = 42;    // typical
>	    external1 = 42;   // allowed or not?

Allowed, because external1 behaves like a module-level variable.


>	    42.external1;     // allowed or not?

Not allowed, because the following isn't allowed either:

	int x;
	void main() {
		1.x;  // Error: nonsensical syntax
	}

IOW, @property functions must be treated as variables externally, NOT as normal functions.


>	    t.external2 = 42; // allowed or not?
>	}

Allowed, because external2, via UFCS, behaves as though it were a member variable of Type.

All of the confusing/unclear/ambiguous cases come from an incomplete implementation of @property and an unnecessary conflation with normal functions. A @property function should not be treated like a normal function. It turns the function into a variable-like entity that *no longer acts like a function to the outsider*. Neither should normal functions for whatever strange reasoning be conflated with @property functions, because functions are not variables.

It's actually very straightforward once you remove all the unnecessary conflations, and disregard, for the time being, the problems in the current implementation.


T

-- 
There is no gravity. The earth sucks.
January 25, 2013
Am Fri, 25 Jan 2013 14:59:58 -0500
schrieb Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:

> I agree with all of the above. There has been a fair amount of rationalization and appeal to emotion on all sides. It would be great to get back to reason and clearly compartmentalize objective arguments (of which there have been a few very profound ones) and personal preference.

Do that on this wiki page: http://wiki.dlang.org/Property_Discussion_Wrap-up

> There's more "@property" to be seen with "save" and "back". Subjectively that just didn't work well for me. It adds clutter to an otherwise simple and straightforward API, and penalizes usage for benefits that I could never reap.

I think it actually makes sense. I even tried writing ranges for std.digest where front was not a property but a field and was surprised it didn't work.

(isInputRange shouldn't check for property. It
should check for "can be used like a field" which means
field+property.).

> I understand how some people are
> glad to put that in everywhere, and find meaning in requiring parens
> with popFront and popBack but not the others. Yet for me it was
> liberating (see 1 above too) I could just write "r.popFront" without
> the parens and have it do its deed. It is the right semantics for a
> simple syntax.

Please read the wiki page. popFront or popFront() is orthogonal to the
property discussion.

> 
> 3. Whatever we do going forward should be _simple_ but not _simplistic_. Right now it's easy to forget that we're all close to the subject. We have it in working memory (at least it's what I think about all the time) and any incremental complexity is an easy cost to absorb intellectually.
> 
> But when we need to teach this to newcomers or even approach it again with a "cold cache", any undue complexity will be jarring.

Wiki page, wiki page ;-)
> 
> 4. Whether we like it or not, backward compatibility is an issue. The parens or no parens aspect upon a function call is too ubiquitous to write off as an obscure circumstance. So I don't think the obscurity argument applies.
> 
> Granted, there are several ways to approach the compatibility issue, all with their specific tradeoffs. All I'm saying is that careful considerations of compatibility must be integral to whatever we do about this.

The approach described on the wiki does break some code, but that code shouldn't compile anyway: @property functions with wrong number of arguments and similar stuff.

Only controversial thing is taking the address of a property, but I can't think of a solution which would work well with generic code so I'd just say forbid that.
> 
> 5. This is a matter in which reasonable people may disagree. For better or worse Walter and to a lesser extent myself are in the position to decide. We're doing the best to gather, mind, and integrate opinions and suggestions but clearly no decision that would please everyone.

Would be nice if the arguments for the final decision are added to the wiki page :-)

January 25, 2013
On Friday, 25 January 2013 at 20:10:01 UTC, Nick Sabalausky wrote:
> What really got me upset about it was that here we have one of my favorite modern language features, properties, and then all of a sudden *both* the top #1 and #2 people behind D start trying to
> gut it if not outright remove it from the language entirely

Amen.
January 25, 2013
On Friday, 25 January 2013 at 20:10:01 UTC, Nick Sabalausky wrote:
> What really got me upset about it was that here we have one of my
> favorite modern language features, properties, and then all of a sudden
> *both* the top #1 and #2 people behind D start trying to gut it if not
> outright remove it from the language entirely, instead of enacting, or
> at least promising to *eventually* enact, the long overdue fixes I've
> been anxiously awaiting.

If I correctly understand Walters proposal and Andrei's view point, neither are proposing to fully axe property-like behavior. I stand to be corrected, but they both seem to think that enforcement through @property is not required, and that's the main point being put on the chopping block.

Walter and Andrei may want to clarify since I cannot speak for them.

--rt
January 25, 2013
On Fri, Jan 25, 2013 at 09:06:44PM +0100, Johannes Pfau wrote:
> Am Fri, 25 Jan 2013 10:39:50 -0800
> schrieb "H. S. Teoh" <hsteoh@quickfur.ath.cx>:
> 
> 
> > - It's illegal to mark a function that takes 2 or more arguments as
> >   @property, because it makes no sense.
> > 
> 
> 3 or more arguments. UFCS properties have 2 arguments:
> 
> @property void age(Person p, int value); //OK, bad example, but you
> get the idea
[...]

Good point, so it's 2 or more arguments for member functions, and 3 or more for module-level functions.

Another thing I forgot to mention: once a function has been declared @property, you cannot call it like a normal function anymore. So if you declare at the module level:

	@property void age(Person p, int value);

then:

	void main() {
		Person p;
		//age(p, 123);	// Error: cannot call age like a normal function
		//p.age(123);	// ditto
		p.age = 123;	// OK
	}

The second case (p.age(123)) is valid only if age() returns a delegate.
Again, @property turns the function into a variable-like entity that
does not behave like a normal function to the outside world.


T

-- 
Lottery: tax on the stupid. -- Slashdotter
January 25, 2013
On Friday, 25 January 2013 at 19:59:59 UTC, Andrei Alexandrescu wrote:
> 2. I have tried to add @property appropriately in Phobos, in particular for ranges:

These are examples of why I'm firmly in the pro-optional parenthesis camp. With them, stuff like this becomes irrelevant; it works either way.

But, remember, the problem @property needs to solve is none of this. There's no pressing reason to put it on range functions.


My view is @property maybe somewhat rare in usage: if in doubt, do NOT use it. But there's cases where there is no doubt, and we don't want to throw the baby out with the bathwater there.


One example where I'd love property: a dynamic object. Suppose we extend Variant to work Javascript style:

Variant v;

v.prop = function() { };

v.prop(); // we expect this to call the function, not return a reference to it


That would be an @property.... range.popFront doesn't need to be. It works fine with the existing optional parenthesis rule.
January 25, 2013
Am Fri, 25 Jan 2013 12:12:55 -0800
schrieb "H. S. Teoh" <hsteoh@quickfur.ath.cx>:

> 
> 
> >	struct Type
> >	{
> >	    @property void native(int);
> >	}
> 
> This should behave as though you wrote this:
> 
> 	struct Type
> 	{
> 	    // const because there is no setter
> 	    const int native;
> 	}

Only if the getter is marked as const. We can discuss if that should be required, but in the code above, native isn't necessarily const.

> 
> All of the confusing/unclear/ambiguous cases come from an incomplete implementation of @property and an unnecessary conflation with normal functions. A @property function should not be treated like a normal function. It turns the function into a variable-like entity that *no longer acts like a function to the outsider*. Neither should normal functions for whatever strange reasoning be conflated with @property functions, because functions are not variables.
> 
Please add you proposed changes to Proposal 1 in this wiki page or add another proposal to it: http://wiki.dlang.org/Property_Discussion_Wrap-up
January 25, 2013
Am Fri, 25 Jan 2013 21:28:34 +0100
schrieb Johannes Pfau <nospam@example.com>:

> Am Fri, 25 Jan 2013 12:12:55 -0800
> schrieb "H. S. Teoh" <hsteoh@quickfur.ath.cx>:
> 
> > 
> > 
> > >	struct Type
> > >	{
> > >	    @property void native(int);
> > >	}
> > 
> > This should behave as though you wrote this:
> > 
> > 	struct Type
> > 	{
> > 	    // const because there is no setter
> > 	    const int native;
> > 	}
> 
> Only if the getter is marked as const. We can discuss if that should be required, but in the code above, native isn't necessarily const.

Ah you fooled me! There is only a setter in the first example!
January 25, 2013
On Friday, January 25, 2013 10:39:50 H. S. Teoh wrote:
> I've refrained so far from participating in this thread, but maybe it's time to say something.
[snip]

Another issue that you didn't mention (and which hasn't come up in this particular discussion, I don't believe) is what to do about disambiguating property functions that conflict. You can't use the full import path for a function when using the property syntax, so there's not currently a way to disambiguate property functions which conflict. So, we'll need to find a solution for that.

- Jonathan M Davis
January 25, 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