www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - On DIP 23

reply Robert <jfanatiker gmx.at> writes:
Well first what I like about it: The approach function symbols are
handled, it is a pretty clear concept:

void f() {
}

f;

f is a function, you can take the address of it and call it and that's
it. So if you just write it down, it makes sense that it gets called.
Not so for delegates, function objects, ... Sounds sane to me, I like
it.

About properties:

In short, I died a little reading it.

I know we have UFCS, but  properties are meant to emulate a field, so
the semantics should be as close to a field as possible. Ideally,
identical.

Especially the part about module level properties made me crazy:
 property double fun(int x, double y) { assert(x == 42 && y == 43);
return y; }
    42.fun = 43;

reads to me: The integer 42 has a property called fun, which gets
assigned 43???

If we special case properties, we might as well disallow UFCS for them,
which makes sense, because you can not define a field external to an
object either.

So the proposal for module level properties, would be right exactly the
other way round (emulating global variables):
private int myCoolSetting_;
 property int myCoolSetting() {
	return myCoolSetting_;
}
 property void myCoolSetting(int setting) {
	enforce(setting>0 && setting<10, "Invalid setting!");
	myCoolSetting_=setting;
}

myCoolSetting=8; // Ok.

That is what properties are all about. 

The part, about taking the address of a property, is fine as long as we
allow fields to be declared with  property as I already suggested, with
the following semantics:

 property int a;

would be lowered to:

private int __a;

 property void a(int a_) {
	__a=a_;
}

 property int a() {
	return __a;
}

in order to ensure that  property declared fields and properties
declared as functions do really have the same semantics.

If you don't think about properties as fields, than I understand Walters
suggestion about removing  property completely and we could as well do
it.

UFCS with properties, makes little to no sense. Because well the name
already suggests: "Uniform Function Calling Syntax", properties are not
about calling functions. Allowing UFCS would offer the possibility of
adding some kind of dynamic properties/fields to an object, but the code
samples with integers and especially the problem with module level
properties suggests that this causes more problems than it is worth.

properties -> no UFCS and we have a sane world!

Best regards,

Robert

P.S.: Things like  
int a = 4.2.truncated;

do make sense, but UFCS and optional parentheses would do the trick too,
so no need to abuse properties there.
Feb 06 2013
next sibling parent reply "eles" <eles eles.com> writes:
On Wednesday, 6 February 2013 at 22:10:29 UTC, Robert wrote:
   properties are meant to emulate a field

You're in the wrong spot of the world. Everywhere else outside the D community, the above assertion is held for true. In the D community, it is not. Yes, there are places like that, and you are trapped into one of those. For your sake, during your future staying in this place, think of " properties" as functions with calling particularities.
Feb 07 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/7/13 9:44 AM, eles wrote:
 On Wednesday, 6 February 2013 at 22:10:29 UTC, Robert wrote:
  properties are meant to emulate a field

You're in the wrong spot of the world. Everywhere else outside the D community, the above assertion is held for true. In the D community, it is not. Yes, there are places like that, and you are trapped into one of those. For your sake, during your future staying in this place, think of " properties" as functions with calling particularities.

I think the sarcasm is uncalled for. We're doing our best here and our intent is indeed to have properties emulate fields. Properties emulate fields, but they can't behave 100% like fields because if they did they'd be fields. Andrei
Feb 07 2013
next sibling parent FG <home fgda.pl> writes:
On 2013-02-07 19:05, Robert wrote:
 taking the address of the ref return value of a property is of no
 value at all. If you want someone to be able to take the address
 of a field, you should make it simply public (without  property),
 because the  property accessor methods won't gain you anything in
 this case.

Once again. Ref returns are commonly used in ranges. I'd say that being able to take address of someRange.front is good for example for interoperability with external C libraries. Temporarily using a pointer here should be fine.
 Having said this, I think the solution to the & operator is pretty
 straight forward, it takes the address of the accessor function [...]
 Tada. Problem solved :-)

Didn't solve the one mentioned above. So either I am wrong, you are wrong or range.front shouldn't be a property?
Feb 07 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/7/13 2:13 PM, Steven Schveighoffer wrote:
 On Thu, 07 Feb 2013 13:05:50 -0500, Robert <jfanatiker gmx.at> wrote:

 Properties provide a means of access control to fields. (Range checks,
 only readable, only writable, triggering a signal on change, ...)

 So as posted a few times, taking the address of the ref return value of
 a property is of no value at all. If you want someone to be able to take
 the address of a field, you should make it simply public (without
  property), because the  property accessor methods won't gain you
 anything in this case.

property ref T front(T[] arr) { return arr[0];} Not being able to take an address of an array's front element is not a viable solution. The array range's business is not to restrict access to the first element, it's simply to conform to a certain API.

I think the point we're making here with T* vs ref T is that most good work could and should be done with references that have provable scoping. Needing the actual address of something should not be casual. Andrei
Feb 07 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/7/13 4:07 PM, Steven Schveighoffer wrote:
 Most certainly, we should not outlaw taking the address of ref
 parameters because it's "hard" to solve the problem of getting property
 delegates (but only as long as people insist that adding to __traits is
 taboo). That was MY point. Your "solving" a problem by ignoring it, and
 also causing 10 problems elsewhere.

I agree that shouldn't be a motivator. To me it's like, "hey, a perk!" Andrei
Feb 07 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/07/2013 10:28 PM, Robert wrote:
 On Thu, 2013-02-07 at 16:08 -0500, Steven Schveighoffer wrote:
 int delegate()[] arr;

 arr.front();

That's part of the mess we are trying to clean up here?

Of course.
 As of DIP 23, you would have to do arr.front()() in order to actually call the
 delegate.

I prefer DIP24.
 The current behaviour is also that you have to do arr.front()() in order
 to actually call the function. So with DIP23 in effect you would
 actually have to remove  property in order to be backwards compatible.

Nobody wants to be backwards compatible in this regard.
Feb 07 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/8/13 2:05 PM, Robert wrote:
 Look at the section "No module-level properties". Why not?! That's a
 perfectly valid use of properties. The proposal disallows module-level
 properties, but instead allows:
 	42.fun = 43;
 which reads like: assign 43 to the fun property of 42. We get this
 really obscure feature but disallowing module-level properties? If that
 is not wrong, than I don't know what is.

There would be ambiguities with module level properties. A property with one argument may be either a setter for a module-level property or a getter for the property of a module-level object. Andrei
Feb 08 2013
prev sibling next sibling parent FG <home fgda.pl> writes:
On 2013-02-08 21:13, Steven Schveighoffer wrote:
 I can't find anything about that front has to be a property here:
 http://dlang.org/phobos/std_range.html#isInputRange

 all it states that you can get the current element by issuing:
     r.front
 which would still be possible with the optional parentheses of DIP23.

Technically this is true. But the expectation is that r.front is a property/field, not a function. That aspect is difficult to capture in a template, especially in the current implementation where property on a getter is essentially redundant info.

There may be nothing saying that r.front has to be a property, but don't forget setters. There are many examples of the following statement: r.front = val; Just look at the sources: grep -R "\.front = " ./src/phobos/ General agreement is that plain functions shouldn't be allowed to be called like setters, with assignment operator. So what now? Should all that code be changed to use r.front(val) instead? Or should void front(T val) remain a property, while ref T front() becomes a plain function?
Feb 08 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/10/2013 01:09 PM, Robert wrote:
 ...

 In my DIP a property is a function and they behave the same, except that
 prop=5; calls prop(5); if prop is a property.
...

Why does this justify a keyword? I think Walter's initial proposal of getting rid of property has more merit than this.
Feb 10 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/10/2013 01:53 PM, Robert wrote:
 On Sun, 2013-02-10 at 13:40 +0100, Timon Gehr wrote:
 Why does this justify a keyword? I think Walter's initial proposal of
 getting rid of  property has more merit than this.

Read the DIP?

Stop trolling.
 It is about encapsulation

Perfectly possible without DIP26 and encapsulation can be violated using property as given in DIP26 just as easily as without it.
 and making set functions
 callable with = in order to be compatible with ref returning functions:
 (Compatible from set function to ref returning function, not the other
 way round)

setter(2);
 and for the more expressive syntax:
 	a=something;

That's not more expressive.
 instead of

You mean as well as.
 	a(something);

 and so that tools can easily extract what's a property. (For enabling
 access from scripting languages for example, like Qt does.)

Use UDAs.
 The one reason why we can not drop it, is  that = calls the set function
 on properties.

So does ( ). And both are the case already.
 The reason why we should not, is that having such a cool
 straight forward feature for providing proper no-boilerplate

Boilerplate can be trivially automated.
 encapsulation seems valuable in an OOP enabled language.

Feb 10 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/7/13 10:55 AM, Dicebot wrote:
 On Thursday, 7 February 2013 at 14:44:36 UTC, eles wrote:
 On Wednesday, 6 February 2013 at 22:10:29 UTC, Robert wrote:
  properties are meant to emulate a field

You're in the wrong spot of the world. Everywhere else outside the D community, the above assertion is held for true. In the D community, it is not. Yes, there are places like that, and you are trapped into one of those. For your sake, during your future staying in this place, think of " properties" as functions with calling particularities.

Heh, after that many topics and discussion I have started to think it would have been better if initial proposal to remove them altogether succeeded.

I felt we were getting somewhere. Andrei
Feb 07 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 7 February 2013 at 14:44:36 UTC, eles wrote:
 On Wednesday, 6 February 2013 at 22:10:29 UTC, Robert wrote:
  properties are meant to emulate a field

You're in the wrong spot of the world. Everywhere else outside the D community, the above assertion is held for true. In the D community, it is not. Yes, there are places like that, and you are trapped into one of those. For your sake, during your future staying in this place, think of " properties" as functions with calling particularities.

Heh, after that many topics and discussion I have started to think it would have been better if initial proposal to remove them altogether succeeded.
Feb 07 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
 Heh, after that many topics and discussion I have started to 
 think it would have been better if initial proposal to remove 
 them altogether succeeded.

Same feeling here. But I'll try to be constructive and I hope I find the time to write yet another DIP about properties next week. UFCS and properties just don't go together.
Feb 07 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
Properties provide a means of access control to fields. (Range checks,
only readable, only writable, triggering a signal on change, ...)

So as posted a few times, taking the address of the ref return value of
a property is of no value at all. If you want someone to be able to take
the address of a field, you should make it simply public (without
 property), because the  property accessor methods won't gain you
anything in this case.

Having said this, I think the solution to the & operator is pretty
straight forward, it takes the address of the accessor function, which
in fact might me useful at times, but it never takes the address of the
return value. (This only applies to properties, for functions simply do
something like &(func()) to get the address of the return value.)

Tada. Problem solved :-)

I can remember Adam D. Ruppe saying that he would rather have it hidden
completely that the property is accessed by methods, so that taking the
address of the function would not be possible. I have to say, that this
does not feel right for a system programming language and it does not
really improve things, especially with  property fields.

Instead of hiding that properties are functions, we hide that there
might be a real field behind those properties.

Best regards,

Robert
Feb 07 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 7 February 2013 at 16:35:17 UTC, Andrei Alexandrescu 
wrote:
 I felt we were getting somewhere.

 Andrei

Both yes and no at the same time. Last proposals did a great job addressing different issues regarding property syntax and I somewhat like them in that sense. But they miss an important paragraph about what properties are supposed to be in D semantically, when they should be used and what problems they try to solve. So far design feels like it is syntax based as opposed to use case based.
Feb 07 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Feb 07, 2013 at 07:55:22PM +0100, Dicebot wrote:
 On Thursday, 7 February 2013 at 16:35:17 UTC, Andrei Alexandrescu
 wrote:
I felt we were getting somewhere.

Andrei

Both yes and no at the same time. Last proposals did a great job addressing different issues regarding property syntax and I somewhat like them in that sense. But they miss an important paragraph about what properties are supposed to be in D semantically, when they should be used and what problems they try to solve. So far design feels like it is syntax based as opposed to use case based.

Agreed. I've mostly refrained from participating in the myriad of related threads, because I felt like a lot of it was just bikeshedding over what syntax should/shouldn't be allowed, what this or that syntax should/shouldn't mean, but there wasn't much consideration of *why* we're doing this in the first place, and whether / how the various proposals will get us there. Currently I feel like we're just making a gigantic mountain out of a molehill, whereas more important issues like reviewing Dmitri's std.uni replacement are being overlooked. T -- Valentine's Day: an occasion for florists to reach into the wallets of nominal lovers in dire need of being reminded to profess their hypothetical love for their long-forgotten.
Feb 07 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Feb 2013 13:05:50 -0500, Robert <jfanatiker gmx.at> wrote:

 Properties provide a means of access control to fields. (Range checks,
 only readable, only writable, triggering a signal on change, ...)

 So as posted a few times, taking the address of the ref return value of
 a property is of no value at all. If you want someone to be able to take
 the address of a field, you should make it simply public (without
  property), because the  property accessor methods won't gain you
 anything in this case.

property ref T front(T[] arr) { return arr[0];} Not being able to take an address of an array's front element is not a viable solution. The array range's business is not to restrict access to the first element, it's simply to conform to a certain API. This all comes down to an incorrect belief that properties are simply front ends for private variables. They are not, even when many languages make such things necessary or easy to implement (objective C comes to mind). There are plenty of different uses of properties, and redirecting access to another variable (as does the above function) is certainly a valid use. I don't think we should make rules that are focused on specific use cases while discarding or diminishing others. -Steve
Feb 07 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
Good point, but I think that this is pretty much a corner case where it
occasionally might be useful, but it does not rectify the consequences:
The moment you are allowed to take the address, you are stuck with the
ref returning accessor and can not change it later to a get/set pair. 

An easy solution:

	auto a=myrange.front;
	someCFunc(&a);
	myrange.front=a;

It is a little more to write, and maybe a tad slower (depending on the
smartness of the compiler), but we maintain the property guarantees,
which seems to me to be a very valuable goal.


Best regards,

Robert

On Thu, 2013-02-07 at 19:43 +0100, FG wrote:
 Once again. Ref returns are commonly used in ranges.
 I'd say that being able to take address of someRange.front is good for
 example for interoperability with external C libraries.
 Temporarily using a pointer here should be fine.
 

Feb 07 2013
prev sibling next sibling parent "eles" <eles eles.com> writes:
On Thursday, 7 February 2013 at 16:33:46 UTC, Andrei Alexandrescu 
wrote:
 On 2/7/13 9:44 AM, eles wrote:
 On Wednesday, 6 February 2013 at 22:10:29 UTC, Robert wrote:

and our intent is indeed to have properties emulate fields.

At least it caught a bit of attention... but I agree. Sorry.
 Properties emulate fields, but they can't behave 100% like 
 fields because if they did they'd be fields.

That's no reason to make them functions instead. Or something so far from fields that becomes cumbersome. The basic idea is: "properties are (a little more) that fields with validation and directional access control". That's all. Notice that in the brackets above there is "more", but also it is prefixed by "a little".
Feb 07 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
It depends on how we are going to define properties and with all the
arguments in the discussions it seems to me that the only sane way to
design properties is as simple front ends for private fields (which is
my understanding of properties anyway). 

But with optional parantheses the  property would also not be necessary
for this case. So such use cases would need to be handled by normal
functions. It would simply not be a property by definition. 

Redirecting access would not be the purpose of properties but for
functions returning refs. And you are free to take the address then with
&arr.front().


  property ref T front(T[] arr) { return arr[0];}

Do you have any other UFCS examples, where property would seem to be appropriate?
 
 This all comes down to an incorrect belief that properties are simply  
 front ends for private variables.  They are not, even when many languages  
 make such things necessary or easy to implement (objective C comes to  
 mind).
 
 There are plenty of different uses of properties, and redirecting access  
 to another variable (as does the above function) is certainly a valid  
 use.  I don't think we should make rules that are focused on specific use  
 cases while discarding or diminishing others.

It all depends on definitions. If you define an integer as an integral type, you would not expect it to do floating point arithmetic. Although there are use cases for floating point operations, but an integer is just the wrong tool for it.
Feb 07 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
Just to be clear here, with DIP23 in place, the syntax at the caller
side for:

 property ref T front(T[] arr) { return arr[0];}

would not change if you remove the  property. So little code breakage
here and the code that breaks is easily fixed by removing  property. 
Feb 07 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Feb 2013 15:14:22 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/7/13 2:13 PM, Steven Schveighoffer wrote:
 On Thu, 07 Feb 2013 13:05:50 -0500, Robert <jfanatiker gmx.at> wrote:

 Properties provide a means of access control to fields. (Range checks,
 only readable, only writable, triggering a signal on change, ...)

 So as posted a few times, taking the address of the ref return value of
 a property is of no value at all. If you want someone to be able to  
 take
 the address of a field, you should make it simply public (without
  property), because the  property accessor methods won't gain you
 anything in this case.

property ref T front(T[] arr) { return arr[0];} Not being able to take an address of an array's front element is not a viable solution. The array range's business is not to restrict access to the first element, it's simply to conform to a certain API.

I think the point we're making here with T* vs ref T is that most good work could and should be done with references that have provable scoping. Needing the actual address of something should not be casual.

That is fine, as long as it is possible, and NOT overly-complex. Think of it like casting. Casting is essentially a no-op for performance, but is possible, explicit (well, *mostly* explicit), and straightforward. I don't see the problem with restricting address-taking of ref parameters or return values to system code. Well, other than making it less attractive to code in safe mode, but then again, I don't see myself using it much the way it is now. Most certainly, we should not outlaw taking the address of ref parameters because it's "hard" to solve the problem of getting property delegates (but only as long as people insist that adding to __traits is taboo). That was MY point. Your "solving" a problem by ignoring it, and also causing 10 problems elsewhere. -Steve
Feb 07 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Feb 2013 15:57:56 -0500, Robert <jfanatiker gmx.at> wrote:

 Just to be clear here, with DIP23 in place, the syntax at the caller
 side for:

  property ref T front(T[] arr) { return arr[0];}

 would not change if you remove the  property. So little code breakage
 here and the code that breaks is easily fixed by removing  property.

int delegate()[] arr; arr.front(); -Steve
Feb 07 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
On Thu, 2013-02-07 at 16:08 -0500, Steven Schveighoffer wrote:
 int delegate()[] arr;
 
 arr.front();

That's part of the mess we are trying to clean up here? As of DIP 23, you would have to do arr.front()() in order to actually call the delegate. The current behaviour is also that you have to do arr.front()() in order to actually call the function. So with DIP23 in effect you would actually have to remove property in order to be backwards compatible.
Feb 07 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Feb 2013 16:28:42 -0500, Robert <jfanatiker gmx.at> wrote:

 On Thu, 2013-02-07 at 16:08 -0500, Steven Schveighoffer wrote:
 int delegate()[] arr;

 arr.front();

That's part of the mess we are trying to clean up here? As of DIP 23, you would have to do arr.front()() in order to actually call the delegate.

Not with property
 The current behaviour is also that you have to do arr.front()() in order
 to actually call the function. So with DIP23 in effect you would
 actually have to remove  property in order to be backwards compatible.

I don't understand the point here. Why would we want to be backwards compatible with a buggy compiler? In a bug-free implementation of arrays-as-ranges, arr[0] and arr.front should be perfectly interchangeable (with the well-known exception of strings). -Steve
Feb 07 2013
prev sibling next sibling parent eskimo <jfanatiker gmx.at> writes:
Ok, forget backwards compatibility for a moment, it was just an
additional goody.
On Thu, 2013-02-07 at 19:38 -0500, Steven Schveighoffer wrote:
 Not with  property
 
 

That's the point, it would no longer be a property but a simple function returning ref. front for arrays would not be a property for two reasons: 1. front is a UFCS function, I think supporting UFCS with properties is just getting it wrong, have a look at DIP 23 if you don't believe me. 2. My current version, would not allow properties to return ref, but instead a property is a property if it defines a getter or a setter or both with the following exact definition: property void a(T val); property T a(); Everything that does not match these requirements can no longer be a property. With this restrictions in place, properties cause no problems, everything works as expected, no weird corner cases. These restrictions happen to establish property semantics that match the field hiding pattern and this is what properties are all about, if you ask me. The moment we stop trying making properties something they aren't, everything works out. With optional parentheses in place, accessors to fields via a ref are still possible, they just no longer conform to the property specification and thus can not be marked with property. (And don't need to be, because: arr.front=something; and something=arr.front; both still would work) The gain of this? Clear semantics. If I have a property and I can write access it, I know that there is a set function. If I have a property I can read, there has to be a getter. If it is no property, I don't have any guarantees, which might be fine, depending on the API. (E.g. for your arr.front example).
Feb 08 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 08 Feb 2013 10:28:14 -0500, eskimo <jfanatiker gmx.at> wrote:

 Ok, forget backwards compatibility for a moment, it was just an
 additional goody.
 On Thu, 2013-02-07 at 19:38 -0500, Steven Schveighoffer wrote:
 Not with  property

That's the point, it would no longer be a property but a simple function returning ref.

Then it doesn't conform to the range API, where front is a property.
 front for arrays would not be a property for two reasons:
 1. front is a UFCS function, I think supporting UFCS with properties is
 just getting it wrong, have a look at DIP 23 if you don't believe me.

I don't believe you. DIP23 has flaws. Care to explain? "just wrong" isn't an explanation.
 2. My current version, would not allow properties to return ref, but
 instead a property is a property if it defines a getter or a setter or
 both with the following exact definition:

 	 property void a(T val);
 	 property T a();

This is a severe reduction in expression, we should not be looking for extra ways to invalidate existing code unless there is an extremely good reason. "Just wrong" is not it. -Steve
Feb 08 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
On Fri, 2013-02-08 at 12:52 -0500, Steven Schveighoffer wrote:
 
 Then it doesn't conform to the range API, where front is a property.

http://dlang.org/phobos/std_range.html#isInputRange all it states that you can get the current element by issuing: r.front which would still be possible with the optional parentheses of DIP23.
 
 front for arrays would not be a property for two reasons:
 1. front is a UFCS function, I think supporting UFCS with properties

 just getting it wrong, have a look at DIP 23 if you don't believe

I don't believe you. DIP23 has flaws. Care to explain? "just wrong" isn't an explanation.

Look at the section "No module-level properties". Why not?! That's a perfectly valid use of properties. The proposal disallows module-level properties, but instead allows: 42.fun = 43; which reads like: assign 43 to the fun property of 42. We get this really obscure feature but disallowing module-level properties? If that is not wrong, than I don't know what is.
 
 2. My current version, would not allow properties to return ref, but
 instead a property is a property if it defines a getter or a setter

 both with the following exact definition:

        property void a(T val);
        property T a();

This is a severe reduction in expression, we should not be looking for extra ways to invalidate existing code unless there is an extremely good reason. "Just wrong" is not it.

I have really good reasons and I hope I'll explain them well enough in the DIP I am currently writing. You already suggested that keeping compatibility to a broken implementation is not worth it, simply removing the property in cases where there are no longer allowed, seems not too hard a change to me, especially if we agree that we have to break compatibility in one way or the other.
Feb 08 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 08 Feb 2013 14:05:40 -0500, Robert <jfanatiker gmx.at> wrote:

 On Fri, 2013-02-08 at 12:52 -0500, Steven Schveighoffer wrote:
 Then it doesn't conform to the range API, where front is a property.

http://dlang.org/phobos/std_range.html#isInputRange all it states that you can get the current element by issuing: r.front which would still be possible with the optional parentheses of DIP23.

Technically this is true. But the expectation is that r.front is a property/field, not a function. That aspect is difficult to capture in a template, especially in the current implementation where property on a getter is essentially redundant info. In fact, the only case where a properly-implemented property would be required on a getter is for delegate properties. I would argue that if property worked correctly, it would be possible and correct to require r.front to be a property in that template.
 front for arrays would not be a property for two reasons:
 1. front is a UFCS function, I think supporting UFCS with properties

 just getting it wrong, have a look at DIP 23 if you don't believe

I don't believe you. DIP23 has flaws. Care to explain? "just wrong" isn't an explanation.

Look at the section "No module-level properties". Why not?! That's a perfectly valid use of properties. The proposal disallows module-level properties, but instead allows: 42.fun = 43; which reads like: assign 43 to the fun property of 42. We get this really obscure feature but disallowing module-level properties? If that is not wrong, than I don't know what is.

Module level properties pose an issue, because property does not designate whether a property is a getter or a setter. In particular, a single-arg property function could be considered both a module property setter, or a UFCS property getter. So your issue is not really that UFCS properties are wrong, it's that disabling module-level properties is wrong. I agree with you, but at the same time, module level properties are not as common or useful as UFCS. In fact, one could argue they are more confusing since module scope is one of the only scopes that can be obscured. There are other possible solutions, such as designating something as a getter specifically, or adding more syntax (i.e. decorating the first parameter as 'this' for a module-level UFCS getter). But for now, the easiest thing is to disallow one or the other, and since UFCS properties are pretty much essential in Phobos, he's disabling the module level properties. The 42.fun = 43 example, just about everything is wrong with that. Look here is another function that D "allows": void increment(int x); What is that exactly supposed to do? 42.increment(); // what? increment(42); // what? Design and naming of functions is never going to be a problem that the compiler can solve.
 2. My current version, would not allow properties to return ref, but
 instead a property is a property if it defines a getter or a setter

 both with the following exact definition:

        property void a(T val);
        property T a();

This is a severe reduction in expression, we should not be looking for extra ways to invalidate existing code unless there is an extremely good reason. "Just wrong" is not it.

I have really good reasons and I hope I'll explain them well enough in the DIP I am currently writing. You already suggested that keeping compatibility to a broken implementation is not worth it, simply removing the property in cases where there are no longer allowed, seems not too hard a change to me, especially if we agree that we have to break compatibility in one way or the other.

My point on that was, if something works but is not supposed to, we shouldn't have to worry about keeping that code working. property in its current form is NOT implemented as it was designed. There is no requirement to keep existing behavior that doesn't correctly work. In the example given, property is supposed to ban the use of parentheses according to the spec, but it doesn't. In fact, in the case of a property that returns a delegate, it REQUIRES the extra parentheses. This is a bug, and not something to try and keep working. On the other hand, ref properties is NOT a bug, it functions as designed. Whether to remove it or not is certainly a discussion we can have, but it's not buggy behavior. See the difference? -Steve
Feb 08 2013
prev sibling next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Thursday, 7 February 2013 at 18:55:23 UTC, Dicebot wrote:
 On Thursday, 7 February 2013 at 16:35:17 UTC, Andrei 
 Alexandrescu wrote:
 I felt we were getting somewhere.

 Andrei

Both yes and no at the same time. Last proposals did a great job addressing different issues regarding property syntax and I somewhat like them in that sense. But they miss an important paragraph about what properties are supposed to be in D semantically, when they should be used and what problems they try to solve. So far design feels like it is syntax based as opposed to use case based.

In writing my article about nested structs, I stumbled upon a general definition of a property which may be of value here. "A property is a named set of overloaded operations on a piece of data which replaces the appearance of that data in code(™)."
Feb 08 2013
prev sibling next sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Friday, 8 February 2013 at 21:31:17 UTC, Zach the Mystic wrote:
 On Thursday, 7 February 2013 at 18:55:23 UTC, Dicebot wrote:
 On Thursday, 7 February 2013 at 16:35:17 UTC, Andrei 
 Alexandrescu wrote:
 I felt we were getting somewhere.

 Andrei

Both yes and no at the same time. Last proposals did a great job addressing different issues regarding property syntax and I somewhat like them in that sense. But they miss an important paragraph about what properties are supposed to be in D semantically, when they should be used and what problems they try to solve. So far design feels like it is syntax based as opposed to use case based.

In writing my article about nested structs, I stumbled upon a general definition of a property which may be of value here. "A property is a named set of overloaded operations on a piece of data which replaces the appearance of that data in code(™)."

By stumbled I mean I accidentally wrote it without knowing what I was doing.
Feb 08 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
First of all, thanks for this very insight full discussion. I start to
understand the other side. :-)
On Fri, 2013-02-08 at 15:13 -0500, Steven Schveighoffer wrote:
 On Fri, 08 Feb 2013 14:05:40 -0500, Robert <jfanatiker gmx.at> wrote:
 
 On Fri, 2013-02-08 at 12:52 -0500, Steven Schveighoffer wrote:
 Then it doesn't conform to the range API, where front is a property.

http://dlang.org/phobos/std_range.html#isInputRange all it states that you can get the current element by issuing: r.front which would still be possible with the optional parentheses of DIP23.

Technically this is true. But the expectation is that r.front is a property/field, not a function. That aspect is difficult to capture in a template, especially in the current implementation where property on a getter is essentially redundant info.

works: auto h=r.front; (stolen from the implementation of isForwardRange), if I understood your argument correctly.
 
 In fact, the only case where a properly-implemented  property would be  
 required on a getter is for delegate properties.  I would argue that if  
  property worked correctly, it would be possible and correct to require  
 r.front to be a property in that template.

not matching the specification regarding no parentheses for properties?
 
 Module level properties pose an issue, because  property does not  
 designate whether a property is a getter or a setter.  In particular, a  
 single-arg property function could be considered both a module property  
 setter, or a UFCS property getter.
 
 So your issue is not really that UFCS properties are wrong, it's that  
 disabling module-level properties is wrong.  I agree with you, but at the  
 same time, module level properties are not as common or useful as UFCS.   

make a lot of sense. (If you apply my definition of a property and accept simple functions with optional parentheses as better way.) I am sorry, I don't understand what you mean here with:
 In fact, one could argue they are more confusing since module scope is one  
 of the only scopes that can be obscured.

 
 There are other possible solutions, such as designating something as a  
 getter specifically, or adding more syntax (i.e. decorating the first  
 parameter as 'this' for a module-level UFCS getter).  But for now, the  
 easiest thing is to disallow one or the other, and since UFCS properties  
 are pretty much essential in Phobos, he's disabling the module level  
 properties.
 
 The 42.fun = 43 example, just about everything is wrong with that.
 
 Look here is another function that D "allows":
 
 void increment(int x);
 
 What is that exactly supposed to do?
 
 42.increment(); // what?
 increment(42); // what?
 
 Design and naming of functions is never going to be a problem that the  
 compiler can solve.

Point taken. But my point is, that with optional parentheses UFCS properties are not needed, so the cleaner solution is to forbid UFCS properties. (See my DIP for further reasoning when it is ready)
 
 My point on that was, if something works but is not supposed to, we  
 shouldn't have to worry about keeping that code working.   property in its  
 current form is NOT implemented as it was designed.  There is no  
 requirement to keep existing behavior that doesn't correctly work.
 
 In the example given,  property is supposed to ban the use of parentheses  
 according to the spec, but it doesn't.  In fact, in the case of a  
  property that returns a delegate, it REQUIRES the extra parentheses.   
 This is a bug, and not something to try and keep working.

with that?
 
 On the other hand, ref  properties is NOT a bug, it functions as  
 designed.  Whether to remove it or not is certainly a discussion we can  
 have, but it's not buggy behavior.  See the difference?

But the documentation of properties: http://dlang.org/property.html in the section about user defined properties also states in the very first sentence: Properties are functions that can be syntactically treated as if they were fields or variables. which is clearly not true at the moment. If this sentence got removed and replaced with a big fat warning that properties are not exchangeable with fields, this would be the least that should be done. The current thinking instead seems to be that properties are just syntactic sugar and the level of encapsulation is business that is left to the developer. My thinking on the other hand is, that properties are the method of encapsulation, so they should ensure it. If something does not, it is not a property, which leads to a very clean design of properties.
Feb 08 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
On Fri, 2013-02-08 at 22:15 +0100, FG wrote:
 Or should void front(T val) remain a
  property, while ref T front() becomes a plain function?

Feb 08 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 8 February 2013 at 21:02:10 UTC, Andrei Alexandrescu 
wrote:
 On 2/8/13 2:05 PM, Robert wrote:
 Look at the section "No module-level properties". Why not?! 
 That's a
 perfectly valid use of properties. The proposal disallows 
 module-level
 properties, but instead allows:
 	42.fun = 43;
 which reads like: assign 43 to the fun property of 42. We get 
 this
 really obscure feature but disallowing module-level 
 properties? If that
 is not wrong, than I don't know what is.

There would be ambiguities with module level properties. A property with one argument may be either a setter for a module-level property or a getter for the property of a module-level object.

I think this was settled, allowing such property to only be a getter via UFCS.
Feb 08 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 08 Feb 2013 16:45:58 -0500, Robert <jfanatiker gmx.at> wrote:

 First of all, thanks for this very insight full discussion. I start to
 understand the other side. :-)

You are welcome! I also am learning things and shaping my opinions based on these discussions.
 On Fri, 2013-02-08 at 15:13 -0500, Steven Schveighoffer wrote:
 On Fri, 08 Feb 2013 14:05:40 -0500, Robert <jfanatiker gmx.at> wrote:

 all it states that you can get the current element by issuing:
 	r.front
 which would still be possible with the optional parentheses of DIP23.

Technically this is true. But the expectation is that r.front is a property/field, not a function. That aspect is difficult to capture in a template, especially in the current implementation where property on a getter is essentially redundant info.

works: auto h=r.front; (stolen from the implementation of isForwardRange), if I understood your argument correctly.

In the grand scheme of things, the fact that a range's front accessor is a property or a function is not technically important. But front being a property IS important for specific uses. You can't have it so that front is a function only when using it as a range, and a property when using it as a delegate getter.
 In fact, the only case where a properly-implemented  property would be
 required on a getter is for delegate properties.  I would argue that if
  property worked correctly, it would be possible and correct to require
 r.front to be a property in that template.

not matching the specification regarding no parentheses for properties?

The problem is, isInputRange does not require that it is a function, but you ARE requiring that by specifying arbitrary rules. Imagine an infinite range (one which never ends), that returns exactly a specific delegate. Such a range could be implemented: struct infiniteDelegate { int delegate() front; enum empty = false; void popFront() {}; } Such a range would fit the definition of input range, but unlike an array, r.front() is how you call the delegate, not r.front()(). Making a consistent interface is not possible without property.
 Module level properties pose an issue, because  property does not
 designate whether a property is a getter or a setter.  In particular, a
 single-arg property function could be considered both a module property
 setter, or a UFCS property getter.

 So your issue is not really that UFCS properties are wrong, it's that
 disabling module-level properties is wrong.  I agree with you, but at  
 the
 same time, module level properties are not as common or useful as UFCS.

make a lot of sense. (If you apply my definition of a property and accept simple functions with optional parentheses as better way.)

Actually, that is not true. Check out the definition of hasAssignableElements: http://dlang.org/phobos/std_range.html#.hasAssignableElements By your requirements, hasAssignableElements!(T[]) would necessarily always be false, since UFCS properties are banned, so array.front is not a property. You are saying, I can't assign to the front element of an array. That doesn't sit well with the rest of array's API.
 I am sorry, I don't understand what you mean here with:
 In fact, one could argue they are more confusing since module scope is  
 one
 of the only scopes that can be obscured.


int x; void foo() { int x; // allowed x = 5; // applies to local scope, not module { int x; // error! shadows outer scope x. } } So the point is, a global property could possibly be obscured if you declared a local variable with the same name. Note also that you can have struct-qualified properties (at least you should be able to, it seems Andrei's DIP does not allow it, but it's not at odds with UFCS). Those are just about equivalent to module-level properties, they just require specifying the struct name (and people have used this in clever ways to achieve good readable results).
 There are other possible solutions, such as designating something as a
 getter specifically, or adding more syntax (i.e. decorating the first
 parameter as 'this' for a module-level UFCS getter).  But for now, the
 easiest thing is to disallow one or the other, and since UFCS properties
 are pretty much essential in Phobos, he's disabling the module level
 properties.

 The 42.fun = 43 example, just about everything is wrong with that.

 Look here is another function that D "allows":

 void increment(int x);

 What is that exactly supposed to do?

 42.increment(); // what?
 increment(42); // what?

 Design and naming of functions is never going to be a problem that the
 compiler can solve.

Point taken. But my point is, that with optional parentheses UFCS properties are not needed, so the cleaner solution is to forbid UFCS properties. (See my DIP for further reasoning when it is ready)

What about setters?
 My point on that was, if something works but is not supposed to, we
 shouldn't have to worry about keeping that code working.   property in  
 its
 current form is NOT implemented as it was designed.  There is no
 requirement to keep existing behavior that doesn't correctly work.

 In the example given,  property is supposed to ban the use of  
 parentheses
 according to the spec, but it doesn't.  In fact, in the case of a
  property that returns a delegate, it REQUIRES the extra parentheses.
 This is a bug, and not something to try and keep working.

with that?

I'm not saying it's a problem, I suppose it could be considered by some, desirable to require the extra parentheses. I haven't heard from that person yet. But "being backwards compatible" is not a good reason when you are talking about incorrect behavior. It would have to be because that is a desirable feature. Frankly, if that was the case, I think we would never have introduced property.
 On the other hand, ref  properties is NOT a bug, it functions as
 designed.  Whether to remove it or not is certainly a discussion we can
 have, but it's not buggy behavior.  See the difference?

But the documentation of properties: http://dlang.org/property.html in the section about user defined properties also states in the very first sentence: Properties are functions that can be syntactically treated as if they were fields or variables. which is clearly not true at the moment. If this sentence got removed and replaced with a big fat warning that properties are not exchangeable with fields, this would be the least that should be done.

It certainly is true. They can be treated like fields for getting and setting, and I think "syntactically" means you access them like you would access a field. You might say "yeah, but you can't do ++ on them!", but you can't do that to a const field either. Should const fields be considered fields? A ref property pretty much behaves EXACTLY like a field.
 The current thinking instead seems to be that properties are just
 syntactic sugar and the level of encapsulation is business that is left
 to the developer.

I don't think that SHOULD be D's business. Encapsulation should be possible, encouraged, but not dictated.
 My thinking on the other hand is, that properties are the method of
 encapsulation, so they should ensure it. If something does not, it is
 not a property, which leads to a very clean design of properties.

Such a design is entirely possible today, even if ref properties exist, even if *properties* didn't exist. Why must you use ref properties just because they are available? Note that the reader/user of code is never guaranteed that they are working with properly encapsulated code. A property looks like a field, and a field is NOT encapsulated. So any compiler/language guarantees of encapsulation with properties are moot. -Steve
Feb 09 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
Ok, at the very first I have to make clear that my DIP is about changing
the actual specification, not trying to make the implementation to match
the specification, because in my view of things, the specification is
the problem.

Properties in my proposal are no longer about optional parentheses ore
forbidden parentheses. Properties are a concept hat benefits from the
fact, that parentheses are optional, but would work either way.

Reducing properties to functions with no parentheses is just not getting
it right as we can see with the problems we have.


 
 In the grand scheme of things, the fact that a range's front accessor is a  
 property or a function is not technically important.  But front being a  
 property IS important for specific uses.  You can't have it so that front  
 is a function only when using it as a range, and a property when using it  
 as a delegate getter.

In my DIP a property is a function and they behave the same, except that prop=5; calls prop(5); if prop is a property.
 
 In fact, the only case where a properly-implemented  property would be
 required on a getter is for delegate properties.  I would argue that if
  property worked correctly, it would be possible and correct to require
 r.front to be a property in that template.

not matching the specification regarding no parentheses for properties?

The problem is, isInputRange does not require that it is a function, but you ARE requiring that by specifying arbitrary rules.

I think this has to be fixed, because it solves all ambiguities and encourages good design.
 
 Imagine an infinite range (one which never ends), that returns exactly a  
 specific delegate.  Such a range could be implemented:
 
 struct infiniteDelegate
 {
      int delegate() front;
      enum empty = false;
      void popFront() {};
 }

It would, based on the current definition, yes. But what is it good for? Why not simply write: struct infiniteDelegate { int delegate() front(); bool empty() property { return false; } void popFront() {}; } Where the body of front for example can ensure that the delegate is actually set and not null or can change it if necessary, ... I haven't applied property to front in this example, because it would not change anything, it would be required though if you provided a setter and wanted to have front=something; work. Whether or not you apply property to read-only functions, depends on your use case, if you want proper encapsulation, you would add property and in case you want a writable front at some time, you would add a setter. If you don't consider encapsulation necessary, you would probably do not add property and return a ref if it has to be writable sometime.
 Actually, that is not true.  Check out the definition of  
 hasAssignableElements:
 
 http://dlang.org/phobos/std_range.html#.hasAssignableElements
 
 By your requirements, hasAssignableElements!(T[]) would necessarily always  
 be false, since UFCS properties are banned, so array.front is not a  
 property.  You are saying, I can't assign to the front element of an  
 array.  That doesn't sit well with the rest of array's API.

Not true, the current definition of front for arrays is: property ref T front(T)(T[] a); which would still work just the same, if you removed property. Strings are interesting as front returns a non ref dchar (obviously), but they have no writable front anyway. If you would really have a use case where you need an actual setter/getter for an array for example, just do proper encapsulation in a struct/class. If you don't do that, your setter could be bypassed anyway so the design is questionable at best. (Which you could still achieve via alias this, if you really wanted that.)
 void foo()
 {
 
     int x; // allowed
 
     x = 5; // applies to local scope, not module
     {
        int x; // error!  shadows outer scope x.
     }
 }
 
 So the point is, a global property could possibly be obscured if you  
 declared a local variable with the same name.

Same for instance variables and member functions.
 
 Note also that you can have struct-qualified properties (at least you  
 should be able to, it seems Andrei's DIP does not allow it, but it's not  
 at odds with UFCS).  Those are just about equivalent to module-level  
 properties, they just require specifying the struct name (and people have  
 used this in clever ways to achieve good readable results).

Hmm, no real difference to struct/class properties: import std.stdio; int i; void main() { int i; i=8; writeln(".i: ", .i); writeln(".i: ", testglobal.i); } Prints 0 both times. (The file was named testglobal.d)
 It certainly is true.  They can be treated like fields for getting and  
 setting, and I think "syntactically" means you access them like you would  
 access a field.
 
 You might say "yeah, but you can't do ++ on them!", but you can't do that  
 to a const field either.  Should const fields be considered fields?

Well that's probably what was meant by this statement, but obviously it was misunderstood by me and many others. It suggests that you can use public fields if you would have required trivial set/get methods. (I even found a blog post by someone who was bashing against Java how silly they are and how cool D is, because we don't need trival set/get methods)
 
 A ref property pretty much behaves EXACTLY like a field.

Exactly that is why I don't consider it a property. :-)
 
 The current thinking instead seems to be that properties are just
 syntactic sugar and the level of encapsulation is business that is left
 to the developer.

I don't think that SHOULD be D's business. Encapsulation should be possible, encouraged, but not dictated.

It is not dictated, it is just encouraged and possible. If you don't need encapsulation, don't call it a property. Nothing changes. You even have a way out, if you first considered it a property with proper set/get and later on you decide that this is not really needed, you can drop it, no code will break, you just can not go back. But that was your decision the moment you gave up property.
 
 My thinking on the other hand is, that properties are the method of
 encapsulation, so they should ensure it. If something does not, it is
 not a property, which leads to a very clean design of properties.

Such a design is entirely possible today, even if ref properties exist, even if *properties* didn't exist. Why must you use ref properties just because they are available?

You don't, but their availability is no gain at all, because you would have exactly the same if you removed property, just the concept of a property is screwed. If you want property qualified ref returning functions, then you also want UFCS properties, and my point is that there is no point to it.
 
 Note that the reader/user of code is never guaranteed that they are  
 working with properly encapsulated code.  A property looks like a field,  
 and a field is NOT encapsulated.  So any compiler/language guarantees of  
 encapsulation with properties are moot.
 
 -Steve

My point is that it is wrong that a property should look like a field, this just causes confusion, because people mix it up and forget about encapsulation. Just stand to the fact that it is no field. If you want a field, use a field or a method returning ref, don't use property. So there will be guaranteed to have a proper encapsulated field, the moment they see property, but what is more important is, that the provider of the code can be sure that he/she got encapsulation right as long as he/she does qualifies something with property.
Feb 10 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
On Sun, 2013-02-10 at 13:40 +0100, Timon Gehr wrote:
 Why does this justify a keyword? I think Walter's initial proposal of 
 getting rid of  property has more merit than this.

Read the DIP? It is about encapsulation and making set functions callable with = in order to be compatible with ref returning functions: (Compatible from set function to ref returning function, not the other way round) and for the more expressive syntax: a=something; instead of a(something); and so that tools can easily extract what's a property. (For enabling access from scripting languages for example, like Qt does.) The one reason why we can not drop it, is that = calls the set function on properties. The reason why we should not, is that having such a cool straight forward feature for providing proper no-boilerplate encapsulation seems valuable in an OOP enabled language.
Feb 10 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
 The reason why we should not, is that having such a cool
 straight forward feature for providing proper no-boilerplate
 encapsulation seems valuable in an OOP enabled language.
 

Provided we actually give properties this meaning in D, which is currently not the case.
Feb 10 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
 Read the DIP?

Stop trolling.

over again, I just get the feeling that people don't even read it, which is kinda frustrating, as it was a lot of work.
 
 It is about encapsulation

Perfectly possible without DIP26 and encapsulation can be violated using property as given in DIP26 just as easily as without it.

How?! I mean yeah, you can return a pointer to a field, that is correct. But apart from that, which might get forbidden too for properties (I have to think about it first), what do you mean?
 
 and making set functions
 callable with = in order to be compatible with ref returning functions:
 (Compatible from set function to ref returning function, not the other
 way round)

setter(2);

 
 and for the more expressive syntax:
 	a=something;

That's not more expressive.

is. Arguably not more than setA(something), but well it is a nice syntax and we stay compatible with ref returning functions and with the current implementation.
 Use UDAs.

True if this was the only reason.
 
 The one reason why we can not drop it, is  that = calls the set function
 on properties.

So does ( ). And both are the case already.

Yeah, which actually is a good thing, because we won't break much code. People have their code written according to the implementation not some specification, so if we keep most currently existing code running and get sane behaviour, I think this is a good thing, but ok there are people who seem to disagree.
 
 The reason why we should not, is that having such a cool
 straight forward feature for providing proper no-boilerplate

Boilerplate can be trivially automated.

Also true, but integrating it into the language makes the property feature complete and well integrated.
Feb 10 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
 How?! I mean yeah, you can return a pointer to a field, that is correct.
 But apart from that, which might get forbidden too for properties (I
 have to think about it first), what do  you mean?


I mean of course you can. Always. There are many ways: - alias this - some other function which returns the variable by ref/pointer - make the field public But the property marked functions won't break it.
Feb 10 2013
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 10 Feb 2013 07:09:52 -0500, Robert <jfanatiker gmx.at> wrote:

 Ok, at the very first I have to make clear that my DIP is about changing
 the actual specification, not trying to make the implementation to match
 the specification, because in my view of things, the specification is
 the problem.

 Properties in my proposal are no longer about optional parentheses ore
 forbidden parentheses. Properties are a concept hat benefits from the
 fact, that parentheses are optional, but would work either way.

We don't need a feature to implement encapsulation, it's quite possible without property specification. And your proposal does not guarantee encapsulation anyway.
 In the grand scheme of things, the fact that a range's front accessor  
 is a
 property or a function is not technically important.  But front being a
 property IS important for specific uses.  You can't have it so that  
 front
 is a function only when using it as a range, and a property when using  
 it
 as a delegate getter.

In my DIP a property is a function and they behave the same, except that prop=5; calls prop(5); if prop is a property.

Then why do we need special syntax? I don't see the point. This is just back to D1 properties.
 In fact, the only case where a properly-implemented  property would  


 required on a getter is for delegate properties.  I would argue that  


  property worked correctly, it would be possible and correct to  


 r.front to be a property in that template.


 not matching the specification regarding no parentheses for  

The problem is, isInputRange does not require that it is a function, but you ARE requiring that by specifying arbitrary rules.

I think this has to be fixed, because it solves all ambiguities and encourages good design.

And who says what good design is? What if good design means low performance? What if performance is more important? How can you say you know the goals of every possible implementable object and whether encapsulation is entirely necessary for it? You are holding hostage a syntax feature on the concession that it play nice with your "requiring function call" rules. I don't think D should be dictating everything about how you write your properties and methods. This is a systems language, not a nanny language.
 Imagine an infinite range (one which never ends), that returns exactly a
 specific delegate.  Such a range could be implemented:

 struct infiniteDelegate
 {
      int delegate() front;
      enum empty = false;
      void popFront() {};
 }

It would, based on the current definition, yes. But what is it good for?

I think you miss the point then. You can't dismiss arguments because they don't fit your narrative. This is a corner case, and not a far-fetched one.
 Why not simply write:
 struct infiniteDelegate
 {
       int delegate() front();
       bool empty()  property { return false; }
       void popFront() {};
 }

Because then I have to do: id.front()(); To call the delegate. Not what I wanted to design. You are calling into question my design because it doesn't suit your DIP. Why is your DIP more important than my design?
 Actually, that is not true.  Check out the definition of
 hasAssignableElements:

 http://dlang.org/phobos/std_range.html#.hasAssignableElements

 By your requirements, hasAssignableElements!(T[]) would necessarily  
 always
 be false, since UFCS properties are banned, so array.front is not a
 property.  You are saying, I can't assign to the front element of an
 array.  That doesn't sit well with the rest of array's API.

Not true, the current definition of front for arrays is: property ref T front(T)(T[] a);

You are right, I did not look it up.
 which would still work just the same, if you removed  property.

Right, the setter is not the reason we need property on this, it's the getter. And only for delegate arrays. I should not have brought this example as a reason for UFCS setter properties.
 Strings are interesting as front returns a non ref dchar (obviously),
 but they have no writable front anyway. If you would really have a use
 case where you need an actual setter/getter for an array for example,
 just do proper encapsulation in a struct/class. If you don't do that,
 your setter could be bypassed anyway so the design is questionable at
 best. (Which you could still achieve via alias this, if you really
 wanted that.)

Right, strings are an exception, because they are not treated like arrays. A setter for front would be incorrect for strings.
 Note also that you can have struct-qualified properties (at least you
 should be able to, it seems Andrei's DIP does not allow it, but it's not
 at odds with UFCS).  Those are just about equivalent to module-level
 properties, they just require specifying the struct name (and people  
 have
 used this in clever ways to achieve good readable results).

Hmm, no real difference to struct/class properties: import std.stdio; int i; void main() { int i; i=8; writeln(".i: ", .i); writeln(".i: ", testglobal.i); } Prints 0 both times. (The file was named testglobal.d)

I don't know what this example is trying to prove. I don't see any properties here.
 A ref property pretty much behaves EXACTLY like a field.

Exactly that is why I don't consider it a property. :-)

If it's not a property, it does not behave like a field. If it is a function, then it can behave like a field for all cases except for the delegate case.
 The current thinking instead seems to be that properties are just
 syntactic sugar and the level of encapsulation is business that is  

 to the developer.

I don't think that SHOULD be D's business. Encapsulation should be possible, encouraged, but not dictated.

It is not dictated, it is just encouraged and possible. If you don't need encapsulation, don't call it a property. Nothing changes. You even have a way out, if you first considered it a property with proper set/get and later on you decide that this is not really needed, you can drop it, no code will break, you just can not go back. But that was your decision the moment you gave up property.

Your design dictates that if you want field-like syntax, you have to agree to arbitrary rules regarding ref, and you can't do it with UFCS. Such rules are pretty much arbitrary, because there is no hidden meaning to a property, they are just functions. The only benefit is the readability and the 'human' meaning. Because instead of calling my function setX, I can just call it x, and you have to use the x = ... to call it. But you want to assign some guarantees that really aren't guarantees, they are conventions. In the end, they just get in the way, and your requirements can't achieve the type of guarantees you want.
 My thinking on the other hand is, that properties are the method of
 encapsulation, so they should ensure it. If something does not, it is
 not a property, which leads to a very clean design of properties.

Such a design is entirely possible today, even if ref properties exist, even if *properties* didn't exist. Why must you use ref properties just because they are available?

You don't, but their availability is no gain at all, because you would have exactly the same if you removed property, just the concept of a property is screwed. If you want property qualified ref returning functions, then you also want UFCS properties, and my point is that there is no point to it.

Your concept of property is that they are just functions. But we already HAVE functions. There is no reason to have a language feature that says "this is a property" unless it dictates the *syntax*. It is up to the designer of the type to decide how it's parts are called, it should not be up to the caller. Leaving it up to the caller results in unnecessary obfuscation, and hidden meanings where none was intended. There is actually no real need for properties, they are functions, they can be called like functions. We can get along just fine if we have to write: setFoo(x); instead of foo = x; If there is any reason to have a property language feature, it's for syntax, not for design.
 Note that the reader/user of code is never guaranteed that they are
 working with properly encapsulated code.  A property looks like a field,
 and a field is NOT encapsulated.  So any compiler/language guarantees of
 encapsulation with properties are moot.

My point is that it is wrong that a property should look like a field, this just causes confusion, because people mix it up and forget about encapsulation. Just stand to the fact that it is no field. If you want a field, use a field or a method returning ref, don't use property. So there will be guaranteed to have a proper encapsulated field, the moment they see property, but what is more important is, that the provider of the code can be sure that he/she got encapsulation right as long as he/she does qualifies something with property.

But they don't see property: auto x = obj.y; // no property in sight. "guarantees" of encapsulation are easily thwarted: struct NotEncapsulated { int x; property int y() { return x;} } -Steve
Feb 10 2013
prev sibling next sibling parent Robert <jfanatiker gmx.at> writes:
On Sun, 2013-02-10 at 10:43 -0500, Steven Schveighoffer wrote:
 On Sun, 10 Feb 2013 07:09:52 -0500, Robert <jfanatiker gmx.at> wrote:
 
 Ok, at the very first I have to make clear that my DIP is about changing
 the actual specification, not trying to make the implementation to match
 the specification, because in my view of things, the specification is
 the problem.

 Properties in my proposal are no longer about optional parentheses ore
 forbidden parentheses. Properties are a concept hat benefits from the
 fact, that parentheses are optional, but would work either way.

We don't need a feature to implement encapsulation, it's quite possible without property specification. And your proposal does not guarantee encapsulation anyway.

We don't need it. -> Yes. Would it be nice to have. -> Discuss-able. Does it solve the issues we have. -> Yes. Properties as such do guarantee encapsulation, if you access the fields through the property methods. There is no way to forbid the programmer to break it by other members, alias this, or what ever. But as you said D is a systems programming language.
 
 Then why do we need special syntax?  I don't see the point.  This is just  
 back to D1 properties.

1. Downwards-Compatibility with functions returning ref. (Downwards means that you can replace a property with a function returning ref, but not the other way round) 2. Backwards compatibility. Not mandatory: 3. Nice syntax Why do we need properties to be radically different than functions? This breaks templates, except we try to make almost everything a property, what DIP23 seems to do. All I do is strive for a clean concept what a property actually is, instead of making everything a property just so that templates work, but by giving up any meaning property could have.
 
 And who says what good design is?  What if good design means low  
 performance?  What if performance is more important?  How can you say you  
 know the goals of every possible implementable object and whether  
 encapsulation is entirely necessary for it?  You are holding hostage a  
 syntax feature on the concession that it play nice with your "requiring  
 function call" rules.

I believe the principles of OOP are very well established and accepted. And once again, you don't have to use properties if they don't match your requirements. Also performance does not suffer from a trivial get/set functions. (For classes make them final if needed)
 
 I don't think D should be dictating everything about how you write your  
 properties and methods.  This is a systems language, not a nanny language.

point arithmetic with an integer? What's the difference with properties? If the tool does not fit your need, don't use it.
 Because then I have to do:
 
 id.front()();
 
 To call the delegate.  Not what I wanted to design.  You are calling into  
 question my design because it doesn't suit your DIP.  Why is your DIP more  
 important than my design?

You are questioning my DIP, because it does not match your design. How is that better? Seriously this is just my point of view, you can agree or not, all I am trying is to make sure that you understand why I think it is good and to find possible flaws in it, by discussing it. It establishes some semantics for properties, instead of simply making basically everything a property, just so that templates work somehow. The DIP increases uniformity among language features, instead of decreasing it. Also I am obviously convinced that my DIP is a good solution, otherwise I would not have proposed it.
 which would still work just the same, if you removed  property.

Right, the setter is not the reason we need property on this, it's the getter. And only for delegate arrays. I should not have brought this example as a reason for UFCS setter properties.

Not if we simply accept: front()(); as the syntax to go. It might not look as beautiful as front(), so if you think the syntax for this corner case is just so utterly ugly that it has to be fixed, well then my proposal is rubbish.
  import std.stdio;
 int i;

 void main() {
     int i;
     i=8;
     writeln(".i: ", .i);
     writeln(".i: ", testglobal.i);
 }

 Prints 0 both times. (The file was named testglobal.d)

I don't know what this example is trying to prove. I don't see any properties here.

properties. (The example works the same if i was a property) So what did you mean by: So the point is, a global property could possibly be obscured if you declared a local variable with the same name.
 
 A ref property pretty much behaves EXACTLY like a field.

Exactly that is why I don't consider it a property. :-)

If it's not a property, it does not behave like a field. If it is a function, then it can behave like a field for all cases except for the delegate case.

 Your design dictates that if you want field-like syntax, you have to agree  
 to arbitrary rules regarding ref, and you can't do it with UFCS.  Such  
 rules are pretty much arbitrary, because there is no hidden meaning to a  
 property, they are just functions.  The only benefit is the readability  
 and the 'human' meaning.  Because instead of calling my function setX, I  
 can just call it x, and you have to use the x = ... to call it.

The most important thing the DIP does, is giving "property" an actual meaning. Also readability is a valid goal, otherwise we could all code in machine code.
 
 But you want to assign some guarantees that really aren't guarantees, they  
 are conventions.  In the end, they just get in the way, and your  
 requirements can't achieve the type of guarantees you want.

So you basically say that OOP does not work? (No offense here, but it is hard to understand for me to understand this statement in any other way)
 
 Your concept of property is that they are just functions.  But we already  
 HAVE functions.  There is no reason to have a language feature that says  
 "this is a property" unless it dictates the *syntax*.  It is up to the  
 designer of the type to decide how it's parts are called, it should not be  
 up to the caller.  Leaving it up to the caller results in unnecessary  
 obfuscation, and hidden meanings where none was intended.
 
 There is actually no real need for properties, they are functions, they  
 can be called like functions.  We can get along just fine if we have to  
 write:
 
 setFoo(x);
 
 instead of
 
 foo = x;

Agreed, if we started from scratch and did not want this syntactic sugar. The problem is we do not start from scratch and we would basically break every single D program out there.
 
 If there is any reason to have a  property language feature, it's for  
 syntax, not for design.

At the moment. And I am criticizing this very fact. But if you consider this a good thing, than I understand your position completely. Because this way you don't need a meaning of property, you just adopt the rules, until templates work.
  ref, don't use  property.
 So there will be guaranteed to have a proper encapsulated field, the
 moment they see  property, but what is more important is, that the
 provider of the code can be sure that he/she got encapsulation right as
 long as he/she does qualifies something with  property.

But they don't see property: auto x = obj.y; // no property in sight.

Sure, but how important is this for the caller? The provider of the API has to ensure compatibility. (Also the caller sees it, if she looked at the documentation.)
 
 "guarantees" of encapsulation are easily thwarted:
 
 struct NotEncapsulated
 {
     int x;
      property int y() { return x;}
 }
 

you from stupidity. But then, why not get rid of private too, as this is also possible: struct { private int i; public int* u=&i; }
Feb 10 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 10 Feb 2013 11:52:47 -0500, Robert <jfanatiker gmx.at> wrote:

 On Sun, 2013-02-10 at 10:43 -0500, Steven Schveighoffer wrote:
 On Sun, 10 Feb 2013 07:09:52 -0500, Robert <jfanatiker gmx.at> wrote:

 Ok, at the very first I have to make clear that my DIP is about  

 the actual specification, not trying to make the implementation to  

 the specification, because in my view of things, the specification is
 the problem.

 Properties in my proposal are no longer about optional parentheses ore
 forbidden parentheses. Properties are a concept hat benefits from the
 fact, that parentheses are optional, but would work either way.

We don't need a feature to implement encapsulation, it's quite possible without property specification. And your proposal does not guarantee encapsulation anyway.

We don't need it. -> Yes. Would it be nice to have. -> Discuss-able. Does it solve the issues we have. -> Yes. Properties as such do guarantee encapsulation, if you access the fields through the property methods. There is no way to forbid the programmer to break it by other members, alias this, or what ever. But as you said D is a systems programming language.

It does not. property as you have designed it does not "solve" any issues. It does not enforce or guarantee encapsulation. Only the author can do that. One thing I have learned from D's design philosophies is that a guarantee is not a guarantee unless the compiler guarantees it. Like const. Walter constantly derides C++ const as convention, not enforced. This would be the same thing, if someone uses property, then you assume they have encapsulated. Unless they haven't, in which case, the compiler still happily compiles, and your guarantee is gone. How is your DIP any different from a statement that non-ref returning properties guarantee encapsulation? Answer: it's no different. And neither statement is true.
 Why do we need properties to be radically different than functions? This
 breaks templates, except we try to make almost everything a property,
 what DIP23 seems to do. All I do is strive for a clean concept what a
 property actually is, instead of making everything a property just so
 that templates work, but by giving up any meaning property could have.

They aren't *radically* different from functions, the syntax is different. Under the hood, they are identical to functions. Well, a certain form of functions.
 And who says what good design is?  What if good design means low
 performance?  What if performance is more important?  How can you say  
 you
 know the goals of every possible implementable object and whether
 encapsulation is entirely necessary for it?  You are holding hostage a
 syntax feature on the concession that it play nice with your "requiring
 function call" rules.

I believe the principles of OOP are very well established and accepted. And once again, you don't have to use properties if they don't match your requirements. Also performance does not suffer from a trivial get/set functions. (For classes make them final if needed)

It is true that properties are mostly in OOP languages. But D is not strictly OOP. structs are not OOP, and you can have properties on them. Static properties can exist, and they have absolutely nothing to do with OOP. It is a syntax modification. Encapsulation, an OOP design, does not require a special property syntax to implement them.
 I don't think D should be dictating everything about how you write your
 properties and methods.  This is a systems language, not a nanny  
 language.

point arithmetic with an integer? What's the difference with properties? If the tool does not fit your need, don't use it.

Actually, floating point is 2 integers. And yes, you can do floating point math with integers. I do it all the time to avoid the issues with floating point. But beside that point, your properties bring nothing to the table, so I can actually do without them completely. They are a tool that fixes problems that are already fixed.
 Because then I have to do:

 id.front()();

 To call the delegate.  Not what I wanted to design.  You are calling  
 into
 question my design because it doesn't suit your DIP.  Why is your DIP  
 more
 important than my design?

You are questioning my DIP, because it does not match your design. How is that better? Seriously this is just my point of view, you can agree or not, all I am trying is to make sure that you understand why I think it is good and to find possible flaws in it, by discussing it.

The issue is, my design is limited to MY library, your DIP affects EVERY library (or would if implemented). The bar is much higher that you have to pass, since everyone will have to play by your rules. Without your DIP, I can have my library, and others can have their libraries which might require you to use id.front()(). Freedom of design is definitely not something to take away lightly.
 It establishes some semantics for properties, instead of simply making
 basically everything a property, just so that templates work somehow.
 The DIP increases uniformity among language features, instead of
 decreasing it. Also I am obviously convinced that my DIP is a good
 solution, otherwise I would not have proposed it.

All the property proposals establish semantics for properties. Nobody is making everything a property, save perhaps your DIP, which mostly equates functions and properties, so I don't really get that. Your dip makes things much less uniform IMO, since properties should syntactically be more like fields than functions. With your DIP, I am forced to require "property or function" in a template, I can't require "field or property". Seeing as how properties are actually functions, I don't see the point. I feel this takes the major draw of properties away.
 which would still work just the same, if you removed  property.

Right, the setter is not the reason we need property on this, it's the getter. And only for delegate arrays. I should not have brought this example as a reason for UFCS setter properties.

Not if we simply accept: front()(); as the syntax to go. It might not look as beautiful as front(), so if you think the syntax for this corner case is just so utterly ugly that it has to be fixed, well then my proposal is rubbish.

It's not about the beauty. A field that is a delegate does not require two sets of parentheses. In this case, properties would behave like functions, and we already HAVE functions that execute arbitrary code, we don't need another language construct that executes arbitrary code and is called exactly like a function. So in your DIP, properties are pretty much redundant.
  import std.stdio;
 int i;

 void main() {
     int i;
     i=8;
     writeln(".i: ", .i);
     writeln(".i: ", testglobal.i);
 }

 Prints 0 both times. (The file was named testglobal.d)

I don't know what this example is trying to prove. I don't see any properties here.

properties. (The example works the same if i was a property) So what did you mean by: So the point is, a global property could possibly be obscured if you declared a local variable with the same name.

The original text this was in reply to made this confusing. What I was saying is that struct static fields/properties do not interfere with UFCS, and are as global as global fields/properties.
 A ref property pretty much behaves EXACTLY like a field.

Exactly that is why I don't consider it a property. :-)

If it's not a property, it does not behave like a field. If it is a function, then it can behave like a field for all cases except for the delegate case.


Again, we have fields, we have functions. If you want to make a *new type* of function, it needs to justify its existence. I don't see anything compelling for properties as you see them, they act just like functions.
 Your design dictates that if you want field-like syntax, you have to  
 agree
 to arbitrary rules regarding ref, and you can't do it with UFCS.  Such
 rules are pretty much arbitrary, because there is no hidden meaning to a
 property, they are just functions.  The only benefit is the readability
 and the 'human' meaning.  Because instead of calling my function setX, I
 can just call it x, and you have to use the x = ... to call it.

The most important thing the DIP does, is giving "property" an actual meaning. Also readability is a valid goal, otherwise we could all code in machine code.

Right, a meaning that is not true.
 But you want to assign some guarantees that really aren't guarantees,  
 they
 are conventions.  In the end, they just get in the way, and your
 requirements can't achieve the type of guarantees you want.

So you basically say that OOP does not work? (No offense here, but it is hard to understand for me to understand this statement in any other way)

No, I have no idea how you get that. Whether or not you *can* encapsulate with properties is a different statement than whether properties *guarantee* encapsulation. What you have is something that is unnecessarily strict, in exchange for a false guarantee. That's all I said. It had nothing to do with whether encapsulation is good practice, or if OOP works.
 Your concept of property is that they are just functions.  But we  
 already
 HAVE functions.  There is no reason to have a language feature that says
 "this is a property" unless it dictates the *syntax*.  It is up to the
 designer of the type to decide how it's parts are called, it should not  
 be
 up to the caller.  Leaving it up to the caller results in unnecessary
 obfuscation, and hidden meanings where none was intended.

 There is actually no real need for properties, they are functions, they
 can be called like functions.  We can get along just fine if we have to
 write:

 setFoo(x);

 instead of

 foo = x;

Agreed, if we started from scratch and did not want this syntactic sugar. The problem is we do not start from scratch and we would basically break every single D program out there.

Well, we actually are starting from pretty much what you are proposing. Your proposal adds complexity for no gain.
 If there is any reason to have a  property language feature, it's for
 syntax, not for design.

At the moment. And I am criticizing this very fact. But if you consider this a good thing, than I understand your position completely. Because this way you don't need a meaning of property, you just adopt the rules, until templates work.

Your counter proposal is to make property essentially a no-op. If you want to criticize, that is fine. If you want to establish a convention that using property to encapsulate really requires not returning ref, or using them with UFCS (which is in fact incorrect), that is fine too. But in order to have a reason to have property stay in the language, it has to be a feature that isn't easily done otherwise. It needs to pull it's weight. Having it just be another function isn't worth it.
  ref, don't use  property.
 So there will be guaranteed to have a proper encapsulated field, the
 moment they see  property, but what is more important is, that the
 provider of the code can be sure that he/she got encapsulation right  

 long as he/she does qualifies something with  property.

But they don't see property: auto x = obj.y; // no property in sight.

Sure, but how important is this for the caller? The provider of the API has to ensure compatibility. (Also the caller sees it, if she looked at the documentation.)

I don't think it is important. That is why your whole DIP is needless. As an object author, I can easily ensure encapsulation whether properties are used or not. properties as you define them give me no extra bonuses or features, they are simply functions. If your DIP is implemented, and any programmer looks at a property method and says "aha! that field is entirely encapsulated because it has property on it," I would call that programmer foolish. Any guarantees that you have to double check yourself are not guarantees.
 "guarantees" of encapsulation are easily thwarted:

 struct NotEncapsulated
 {
     int x;
      property int y() { return x;}
 }

you from stupidity. But then, why not get rid of private too, as this is also possible: struct { private int i; public int* u=&i; }

Again, when you say "guarantees", that is a strong term. If property claims to guarantee encapsulation, it better ensure the above doesn't compile, because otherwise it's not guaranteed. The rule in D is that if it guarantees something, the only way to get around it is to cast. This way, you can use cast as a red flag to indicate some guarantee may be broken. private does not guarantee that others cannot access it through other references. It simply is a tool with which you CAN guarantee others cannot access it. properties are no different, they do not guarantee encapsulation, with or without your DIP, they only provide a mechanism to be able to provide that guarantee. -Steve
Feb 10 2013