www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP23 draft: Fixing properties redux

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter and I have had a discussion on how to finalize properties.

http://wiki.dlang.org/DIP23

We got input from DIP21 (which we didn't want to clobber, hence the new 
DIP) and the recent discussion.

The proposal probably won't be accepted in its current form because it 
breaks some code. We hope to bring it to good shape with everyone's help.

In brief:

* Optional parens stay.

* Just mentioning a function or method without parens does NOT 
automatically take its address. (This is a change from the current 
behavior.)

* Read properties (using  property) work as expected with the mention 
that they may NOT be called with the parens. Any parens would apply to 
the returned value.

* Write properties (using  property) may only be used in the assignment 
form (no function-style call allowed).

It is understood that the current proposal is just a draft and there 
must be quite a few corner cases it doesn't discuss. We also understand 
it's impossible to reconcile all viewpoints and please all tastes. Our 
hope is to get to a point where the rules are self-consistent, 
meaningful, and complete.


Destroy.

Andrei
Feb 03 2013
next sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
I always wondered if there's a good way to incorporate opOpAssign family of
operators with the write property syntax.
Currently, using anything but the direct assignment fails, so even if
eventually the support for defining specific opOpAssign for properties
won't be implemented, at least the automatic rewrite of them would be nice:

struct A
{
public:
    int i()
    {
        return _i;
    }

    int i(int i_)
    {
        return _i = i_;
    }

private:
    int _i;
}

unittest
{
    A a;
    a.i += 2; // a.i(a.i() + 2);
}


On Sun, Feb 3, 2013 at 12:16 PM, Andrei Alexandrescu <
SeeWebsiteForEmail erdani.org> wrote:

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23

 We got input from DIP21 (which we didn't want to clobber, hence the new
 DIP) and the recent discussion.

 The proposal probably won't be accepted in its current form because it
 breaks some code. We hope to bring it to good shape with everyone's help.

 In brief:

 * Optional parens stay.

 * Just mentioning a function or method without parens does NOT
 automatically take its address. (This is a change from the current
 behavior.)

 * Read properties (using  property) work as expected with the mention that
 they may NOT be called with the parens. Any parens would apply to the
 returned value.

 * Write properties (using  property) may only be used in the assignment
 form (no function-style call allowed).

 It is understood that the current proposal is just a draft and there must
 be quite a few corner cases it doesn't discuss. We also understand it's
 impossible to reconcile all viewpoints and please all tastes. Our hope is
 to get to a point where the rules are self-consistent, meaningful, and
 complete.


 Destroy.

 Andrei
-- Bye, Gor Gyolchanyan.
Feb 03 2013
prev sibling next sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
Sorry, forgot the  property.


On Sun, Feb 3, 2013 at 12:27 PM, Gor Gyolchanyan <
gor.f.gyolchanyan gmail.com> wrote:

 I always wondered if there's a good way to incorporate opOpAssign family
 of operators with the write property syntax.
 Currently, using anything but the direct assignment fails, so even if
 eventually the support for defining specific opOpAssign for properties
 won't be implemented, at least the automatic rewrite of them would be nice:

 struct A
 {
 public:
     int i()
     {
         return _i;
     }

     int i(int i_)
     {
         return _i = i_;
     }

 private:
     int _i;
 }

 unittest
 {
     A a;
     a.i += 2; // a.i(a.i() + 2);
 }


 On Sun, Feb 3, 2013 at 12:16 PM, Andrei Alexandrescu <
 SeeWebsiteForEmail erdani.org> wrote:

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23

 We got input from DIP21 (which we didn't want to clobber, hence the new
 DIP) and the recent discussion.

 The proposal probably won't be accepted in its current form because it
 breaks some code. We hope to bring it to good shape with everyone's help.

 In brief:

 * Optional parens stay.

 * Just mentioning a function or method without parens does NOT
 automatically take its address. (This is a change from the current
 behavior.)

 * Read properties (using  property) work as expected with the mention
 that they may NOT be called with the parens. Any parens would apply to the
 returned value.

 * Write properties (using  property) may only be used in the assignment
 form (no function-style call allowed).

 It is understood that the current proposal is just a draft and there must
 be quite a few corner cases it doesn't discuss. We also understand it's
 impossible to reconcile all viewpoints and please all tastes. Our hope is
 to get to a point where the rules are self-consistent, meaningful, and
 complete.


 Destroy.

 Andrei
-- Bye, Gor Gyolchanyan.
-- Bye, Gor Gyolchanyan.
Feb 03 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 * Just mentioning a function or method without parens does NOT 
 automatically take its address. (This is a change from the 
 current behavior.)
I don't understand.
 * Read properties (using  property) work as expected with the 
 mention that they may NOT be called with the parens. Any parens 
 would apply to the returned value.
Great !
 * Write properties (using  property) may only be used in the 
 assignment form (no function-style call allowed).
Awesome. Two things now : - free functions annotated properties with one argument ? (are they setter ? getters ? both ?) - order of evaluation.
Feb 03 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:
 Destroy.
Overall, it looks good. It sounds like it's basically arguing for fully implementing property as intended save for the fact that parenless function calls on normal functions are allowed. And that's pretty much what I've been arguing for during all of this latest property debate. However, one issue that I'm concerned about with regards to properties which hasn't really been discussed much and which doesn't have a whole lot to do with how they're declared (but rather the syntax of how they're used) is how to handle symbol clashes. For instance, if you have the free function auto prop(int[] arr) {...} in module a.b.c, and you have auto prop(int[] arr) {...} in module a.d.e, how do you deal with code that does import a.b.c; import a.d.e; auto var = arr.prop; Syntactically, there's no way to indicate which of the two functions you mean. It's a problem that only occurs with free functions and UFCS (since with member functions, the member function wins in any conflict with a free function, and member functions on the same type can't be in different modules), but it's definitely something that can happen. And we really should come up with a fix for it. The best that I can think of at the moment is something like auto var = arr.a.b.c.prop; where you're trying to use a.b.c.prop, but I don't know if that's a good syntax or not. It could certainly cause problems if arr were a user-defined type with a property called arr, so maybe adding parens would help auto var = arr.(a.b.c).prop; but that's still a bit ugly. I don't know if there's a good way that _isn't_ ugly though. I suppose that we could get away with arguing that symbol renaming would be required alias a.b.c.prop myprop; auto var = arr.myprop; but I don't know that that's a great solution either. AFAIK though, it's the only way that we have to deal with the problem right now. - Jonathan M Davis
Feb 03 2013
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 08:51:58 UTC, Jonathan M Davis 
wrote:
 auto prop(int[] arr) {...}

 in module a.b.c, and you have

 auto prop(int[] arr) {...}

 in module a.d.e, how do you deal with code that does

 import a.b.c;
 import a.d.e;
 auto var = arr.prop;

 Syntactically, there's no way to indicate which of the two 
 functions you mean.
Couldn't an alias make it ? alias propFromA = a.b.c.prop; auto var = arr.propFromA;
Feb 03 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 3:50 AM, Jonathan M Davis wrote:
 On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:
 Destroy.
Overall, it looks good. It sounds like it's basically arguing for fully implementing property as intended save for the fact that parenless function calls on normal functions are allowed. And that's pretty much what I've been arguing for during all of this latest property debate. However, one issue that I'm concerned about with regards to properties which hasn't really been discussed much and which doesn't have a whole lot to do with how they're declared (but rather the syntax of how they're used) is how to handle symbol clashes. For instance, if you have the free function auto prop(int[] arr) {...} in module a.b.c, and you have auto prop(int[] arr) {...} in module a.d.e, how do you deal with code that does import a.b.c; import a.d.e; auto var = arr.prop;
First off, defining a top-level property ought indeed to have an air of definitive-ness, so this is good. It also illustrates that defining top-level properties should be rare. To fix this, no need to add syntax: import a.b.c; import a.b.c : prop1 = prop; import a.d.e; import a.d.e : prop2 = prop; auto v1 = arr.prop1; // goes to a.b.c.prop auto v2 = arr.prop2; // gies to a.d.e.prop Andrei
Feb 03 2013
prev sibling next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 It is understood that the current proposal is just a draft and 
 there must be quite a few corner cases it doesn't discuss.
Here are some more test cases to think about: http://wiki.dlang.org/Property_Discussion_Wrap-up#Unified_test_suite Specifically, for ref-returning function, I assume the &-operator is meant to return the address of the callable for non- property function, but the address of the returned value for properties? David
Feb 03 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 09:04:59 UTC, David Nadlinger wrote:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
 wrote:
 It is understood that the current proposal is just a draft and 
 there must be quite a few corner cases it doesn't discuss.
Here are some more test cases to think about: http://wiki.dlang.org/Property_Discussion_Wrap-up#Unified_test_suite Specifically, for ref-returning function, I assume the &-operator is meant to return the address of the callable for non- property function, but the address of the returned value for properties?
I wanted to avoid the topic as it is basically solved for properties. Andrei, is that possible to split the DIP in 2 : one for properties and one for other functions. It seems that the property part is agreed by most people, but the other one raise more questions.
Feb 03 2013
prev sibling next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 In brief:

 * Optional parens stay.

 Andrei
Will we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS? Did a sensible reasons actually ever come up for allowing optional parens on non-UFCS?
Feb 03 2013
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
03-Feb-2013 13:11, monarch_dodra пишет:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:
 In brief:

 * Optional parens stay.

 Andrei
Will we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS? Did a sensible reasons actually ever come up for allowing optional parens on non-UFCS?
Using verbs for actions and nouns for querying data and not being thrilled with useless parens everywhere? But let's not discus this again. -- Dmitry Olshansky
Feb 03 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 4:11 AM, monarch_dodra wrote:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:
 In brief:

 * Optional parens stay.

 Andrei
Will we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS?
No. Thanks for the reminder - I updated the DIP.
 Did a sensible reasons actually ever come up for allowing optional
 parens on non-UFCS?
This is a judgment call as reasonable people may disagree on it. Walter and I both believe optional parens are a good thing for D. At this point, we don't think one more pass through the pros and cons would change our opinion. Andrei
Feb 03 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 3 February 2013 at 14:40:30 UTC, Andrei Alexandrescu 
wrote:
 On 2/3/13 4:11 AM, monarch_dodra wrote:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei 
 Alexandrescu wrote:
 In brief:

 * Optional parens stay.

 Andrei
Will we keep the optional -property (or similar) for those of us that *want* enforced parens, even with UFCS?
No. Thanks for the reminder - I updated the DIP.
 Did a sensible reasons actually ever come up for allowing 
 optional
 parens on non-UFCS?
This is a judgment call as reasonable people may disagree on it. Walter and I both believe optional parens are a good thing for D. At this point, we don't think one more pass through the pros and cons would change our opinion. Andrei
Thank you for the answers. I didn't follow all 500 posts in the other thread, so it was really just to have more vision on the DIP. I don't want to try to change anybody's opinion. Just trying to get a clear status on where we currently stand.
Feb 03 2013
prev sibling next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 03 Feb 2013 03:16:08 -0500
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:


 It is understood that the current proposal is just a draft and there 
 must be quite a few corner cases it doesn't discuss. We also
 understand it's impossible to reconcile all viewpoints and please all
 tastes. Our hope is to get to a point where the rules are
 self-consistent, meaningful, and complete.
 
 
 Destroy.
 
 Andrei
"If a function returns a reference, then assignment through the paren-less call should work: " This is the only part where I would disagree. Why is this special rule necessary if we have full property support? I think this would still allow too many false positives. One important aspect that this proposal doesn't cover yet is whether we want to allow "semantic rewriting" for properties: ---- Struct a; a.property++; //would this be legal? ---- for other corner cases this list is a good start: http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns * Can we get a reference to the property? What does &x.property mean? * How can we get the getter / setter functions? Do we need to get those? * What is the type of the property? Return type, setter function type or getter function type? How to get the other types? * What does x.property++ do? ([http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Property#Semanticrewritingofproperties Semantic rewriting]) * Is returning ref values from the getter OK? * Is taking ref values in the setter OK? * Should all properties be nothrow? pure? getter const? ** Probably better as a rule for style guide. * Are UFCS properties possible? How do they work exactly? * How do you disambiguate property functions when they're free functions which conflict? ** Normal UFCS functions can be force called by using their fully qualified name. That's not possible for properties if function call syntax is disallowed? * How many parameters are allowed for property functions? ** Are default parameters allowed? ** Especially consider the example about __FILE__ and __LINE__ * Are templated properties allowed? ** The access syntax for properties doesn't allow providing types
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 5:14 AM, Johannes Pfau wrote:
 "If a function returns a reference, then assignment through the
 paren-less call should work: "

 This is the only part where I would disagree. Why is this special rule
 necessary if we have full  property support? I think this would still
 allow too many false positives.
(As a note, this is the current behavior.) The way I see it is this is a natural consequence of optional parens. The name of a function without a "&" prepended or a "()" after it will invoke the function, and that's that.
 One important aspect that this proposal doesn't cover yet is whether we
 want to allow "semantic rewriting" for properties:
 ----
 Struct a;
 a.property++; //would this be legal?
 ----
It's dangerous to get too clever about that. Anyhow, such rewrites are possible: ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }() a.p++ ----> { auto v = a.p; ++a.p; return v; }() and so on.
 for other corner cases this list is a good start:
 http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns

 * Can we get a reference to the property? What does
    &x.property mean?
We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.
 * How can we get the getter / setter functions? Do we need to get those?
Per (2) above there is no need for special provisions.
 * What is the type of the property? Return type, setter function type
    or getter function type? How to get the other types?
typeof(r.front) is the return type of the property, typeof(&(r.front)) is the type of a pointer to the return type of the property where applicable, and typeof(&r.front) is the (possibly ambiguous) address of the method. (To disambiguate one would use the appropriate receiver type.)
 * What does x.property++ do?
    ([http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Property#Semanticrewritingofproperties
    Semantic rewriting])
Added to http://wiki.dlang.org/DIP23.
 * Is returning ref values from the getter OK?
I see no reason to disallow it at the language level.
 * Is taking ref values in the setter OK?
How do you mean that?
 * Should all properties be nothrow? pure? getter const?
 ** Probably better as a rule for style guide.
No restriction at language level.
 * Are UFCS properties possible? How do they work exactly?
 * How do you disambiguate property functions when they're free
    functions which conflict?
I think it would be best to simply disallow parameterless module-level properties. // at top level property int foo(); // error property int goo(int); // fine, assume a getter for int
 ** Normal UFCS functions can be force
    called by using their fully qualified name. That's not possible for
    properties if function call syntax is disallowed?
Correct. Writing property buys the writer into a constrained universe.
 * How many parameters are allowed for property functions?
One or two at top level, zero or one at member level.
 ** Are default parameters allowed?
 ** Especially consider the example about __FILE__ and __LINE__
I'd say no. Just keep it simple and focused on the goal.
 * Are templated properties allowed?
 ** The access syntax for properties doesn't allow providing types
No. Templated member variables are not allowed either. Andrei
Feb 03 2013
next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>

 We need to add this to the proposal. There are two schools of thought here:

 1. Make properties emulate regular variables as much as possible. In that
 case &a.p is the same as &(a.p), i.e. it applies to the returned value.
 (One counter-argument here is that properties should seldom return a
 reference because that breaks encapsulation.)

 2. Allow people to do whatever they need to do without much aggravation.
 In that case &a.p obeys the normal rules of taking a method's address, and
 &(a.p) applies to the returned value.

 I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to
 Walter.
I have thought about the problem, and filed an enhancement. http://d.puremagic.com/issues/show_bug.cgi?id=9062 But, Walter disagreed against it. http://d.puremagic.com/issues/show_bug.cgi?id=9062#c13 Kenji Hara
Feb 03 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 11:28 AM, kenji hara wrote:
 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org
 <mailto:SeeWebsiteForEmail erdani.org>>

     We need to add this to the proposal. There are two schools of
     thought here:

     1. Make properties emulate regular variables as much as possible. In
     that case &a.p is the same as &(a.p), i.e. it applies to the
     returned value. (One counter-argument here is that properties should
     seldom return a reference because that breaks encapsulation.)

     2. Allow people to do whatever they need to do without much
     aggravation. In that case &a.p obeys the normal rules of taking a
     method's address, and &(a.p) applies to the returned value.

     I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to
     Walter.


 I have thought about the problem, and filed an enhancement.
 http://d.puremagic.com/issues/show_bug.cgi?id=9062

 But, Walter disagreed against it.
 http://d.puremagic.com/issues/show_bug.cgi?id=9062#c13

   Kenji Hara
Now that an overhaul is on the table, that warrants a second look. Andrei
Feb 03 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 11:11:05 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 5:14 AM, Johannes Pfau wrote:
 "If a function returns a reference, then assignment through the
 paren-less call should work: "

 This is the only part where I would disagree. Why is this special rule
 necessary if we have full  property support? I think this would still
 allow too many false positives.
(As a note, this is the current behavior.) The way I see it is this is a natural consequence of optional parens. The name of a function without a "&" prepended or a "()" after it will invoke the function, and that's that.
 One important aspect that this proposal doesn't cover yet is whether we
 want to allow "semantic rewriting" for properties:
 ----
 Struct a;
 a.property++; //would this be legal?
 ----
It's dangerous to get too clever about that. Anyhow, such rewrites are possible: ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }() a.p++ ----> { auto v = a.p; ++a.p; return v; }() and so on.
 for other corner cases this list is a good start:
 http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns

 * Can we get a reference to the property? What does
    &x.property mean?
We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.
This sounds good. It might be a bit confusing, but nice in the fact that &(a.b) always means address of whatever b returns, whether it is a field or property.
 * Are UFCS properties possible? How do they work exactly?
 * How do you disambiguate property functions when they're free
    functions which conflict?
I think it would be best to simply disallow parameterless module-level properties. // at top level property int foo(); // error property int goo(int); // fine, assume a getter for int
I think this is a possible solution, and I can live with that, I'm fairly certain that some people use global properties currently, so they will not be too happy. But having to set global properties using a function call (global getters can simply be paren-less functions) isn't horrible.
 * Are templated properties allowed?
 ** The access syntax for properties doesn't allow providing types
No. Templated member variables are not allowed either.
Wait, what? I don't like this idea. Why should this not be allowed: property void x(T)(T t) {_x = to!(typeof(_x))(t);} As for templates that return a templated type, it should be allowed, although the calling syntax would have to be for the explicit template call, since you can't do IFTI on return values. In other words: template x(T) { property T x(){return to!(T)(_x);} } // could be shortened to normal property T x(T)() auto xcopy = obj.x!(string).x; Certainly, we need templated getters and setters at module levels: property T front(T)(T[] r) { return r[0];} -Steve
Feb 03 2013
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 11:28:52 -0500, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:


 As for templates that return a templated type, it should be allowed,  
 although the calling syntax would have to be for the explicit template  
 call, since you can't do IFTI on return values.  In other words:

 template x(T) {  property T x(){return to!(T)(_x);} }  // could be  
 shortened to normal  property T x(T)()

 auto xcopy = obj.x!(string).x;
Hm... I actually am changing my mind on this, you should be able to do: auto xcopy = obj.x!(string); For the simple reason that if property is omitted, this would work (simple lack of parens). It makes no sense to make properties not have this ability. -Steve
Feb 03 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 11:28 AM, Steven Schveighoffer wrote:
 This sounds good. It might be a bit confusing, but nice in the fact that
 &(a.b) always means address of whatever b returns, whether it is a field
 or property.
Yah, this is a good rule of thumb for generic code. Note that there's a subtlety in the expression "&expr.name". This is not precedence, just use of punctuation to express a unit. Attempting to decompose it by inserting parens yields different things altogether: &(expr.name) and (&expr).name are not mere redirections of precedence.
  property int foo(); // error
  property int goo(int); // fine, assume a getter for int
I think this is a possible solution, and I can live with that, I'm fairly certain that some people use global properties currently, so they will not be too happy.
Yah, let's see how this restriction pans out.
 No. Templated member variables are not allowed either.
Wait, what? I don't like this idea. Why should this not be allowed: property void x(T)(T t) {_x = to!(typeof(_x))(t);}
Yah, I misspoke. Properties can be templated subject to the other restrictions. Andrei
Feb 03 2013
prev sibling next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 03 Feb 2013 11:11:05 -0500
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 2/3/13 5:14 AM, Johannes Pfau wrote:
 "If a function returns a reference, then assignment through the
 paren-less call should work: "

 This is the only part where I would disagree. Why is this special
 rule necessary if we have full  property support? I think this
 would still allow too many false positives.
(As a note, this is the current behavior.) The way I see it is this is a natural consequence of optional parens. The name of a function without a "&" prepended or a "()" after it will invoke the function, and that's that.
I didn't think of it as a call without parentheses but it indeed makes sense.
 
 * Is returning ref values from the getter OK?
I see no reason to disallow it at the language level.
You have to consider cases though where you have both a setter and a getter returning a 'ref value'. property ref int value(); property void value(int new); * Is it valid to define both at the same time? * Which one is used for assignment etc?
 * Is taking ref values in the setter OK?
How do you mean that?
property int value(ref int new); IIRC that was just meant to complement the "is returning ref OK". Usually nothing bad can happen. Although the ref parameter could be converted into a pointer with some nasty tricks it's probably not the job of the language to prevent that.
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 11:34 AM, Johannes Pfau wrote:
 You have to consider cases though where you have both a setter and a
 getter returning a 'ref value'.

  property ref int value();
  property void value(int new);
For now I disallow 0-parameter top level properties. This is a good argument for keeping things that way.
 * Is it valid to define both at the same time?
 * Which one is used for assignment etc?

 * Is taking ref values in the setter OK?
How do you mean that?
property int value(ref int new); IIRC that was just meant to complement the "is returning ref OK". Usually nothing bad can happen. Although the ref parameter could be converted into a pointer with some nasty tricks it's probably not the job of the language to prevent that.
Yah, there should be no restrictions there. Andrei
Feb 03 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 14:42:17 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 11:34 AM, Johannes Pfau wrote:
 You have to consider cases though where you have both a setter and a
 getter returning a 'ref value'.

  property ref int value();
  property void value(int new);
For now I disallow 0-parameter top level properties. This is a good argument for keeping things that way.
I think Johannes' argument applies to non-global properties. struct X { private int _val; property ref int value() { return _val;} property void value(int newv) { _val = newv; writeln("in setter!");} } So should setting 'value' call the specific setter, or call the getter and just write it? My vote would be to call the setter, since it wouldn't exist if the user didn't want to hook that call. However, it certainly begs the question, why would anyone return ref if they want to hook setting? One could always do this: void foo(ref int v) {v = 5;} X x; foo(x.value); I think it's still too early to make any assumptions at this point. Someone may find a good reason for that, and it's certainly just easier to allow code that is already valid than it is to come up with a reason to have an error. -Steve
Feb 03 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 05:11 PM, Andrei Alexandrescu wrote:
 ...

 2. Allow people to do whatever they need to do without much aggravation.
 In that case &a.p obeys the normal rules of taking a method's address,
 and &(a.p) applies to the returned value.

 I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.
That is horrible! The entire language construct is necessarily a bit of a patchwork, but there is no reason to aggravate this gratuitously.
 ...
 * Are templated properties allowed?
 ** The access syntax for properties doesn't allow providing types
No.
Ditto.
 Templated member variables are not allowed either.
(Actually they are silently rewritten to static member variables. I do not like that.)
Feb 03 2013
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
I'm glad Johannes brought up all these cases. They all need to go into the DIP.
Feb 03 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-03 17:11, Andrei Alexandrescu wrote:

 It's dangerous to get too clever about that. Anyhow, such rewrites are
 possible:

 ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }()
 a.p++ ----> { auto v = a.p; ++a.p; return v; }()

 and so on.
Is that part of the proposal or not? -- /Jacob Carlborg
Feb 04 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, February 04, 2013 09:22:56 Jacob Carlborg wrote:
 On 2013-02-03 17:11, Andrei Alexandrescu wrote:
 It's dangerous to get too clever about that. Anyhow, such rewrites are
 possible:
 
 ++a.p ----> { auto v = a.p; ++v; a.p = v; return v; }()
 a.p++ ----> { auto v = a.p; ++a.p; return v; }()
 
 and so on.
Is that part of the proposal or not?
It is now, though I don't think that it was intially. It's in the "Applying operators" section. - Jonathan M Davis
Feb 04 2013
prev sibling parent Chad Joan <chadjoan gmail.com> writes:
On 02/03/2013 11:11 AM, Andrei Alexandrescu wrote:
 On 2/3/13 5:14 AM, Johannes Pfau wrote:
 ...
 for other corner cases this list is a good start:
 http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns

 * Can we get a reference to the property? What does
 &x.property mean?
We need to add this to the proposal. There are two schools of thought here: 1. Make properties emulate regular variables as much as possible. In that case &a.p is the same as &(a.p), i.e. it applies to the returned value. (One counter-argument here is that properties should seldom return a reference because that breaks encapsulation.) 2. Allow people to do whatever they need to do without much aggravation. In that case &a.p obeys the normal rules of taking a method's address, and &(a.p) applies to the returned value. I favor (2) and put it in http://wiki.dlang.org/DIP23. Will talk to Walter.
I disagree with this. I think that allowing address-of on getters is potentially a big source of trouble. I've felt that getters should be forbidden from returning lvalues. So returning ref from a getter is not OK, but const ref should be fine. Anyone who wants to make the property behave like a reference should define an appropriate setter for it. There are a couple reasons for this: - It would be nice to allow variables/fields to have property as an annotation. This would forbid address-of to allow seamless transition into fully-implemented property functions later. To make the roundtrip possible, the property functions should also disallow address-of. - Allowing mutation of a getter's expression can create unwanted ambiguities when attempting to apply property rewrites. Without an lvalue getter it becomes unambiguous: any side-effectful operation on a property (that isn't direct assignment, or something requiring a read) will call both its getter and setter.
 ...
Andrei
Feb 04 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties: property int foo(int x) {return x * 5;} could be interpreted as: foo = 2; // not correct (for this example) int x = 2.foo; // correct Note that: property int foo(); property void foo(int x, int y); are both unambiguous. ================== I have a possible suggestion to fix this within your proposal: property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter. Therefore, if you wish to write a UFCS getter, omit the property designation. int foo(int x) {return x * 5;} foo = 2; // illegal int x = 2.foo; // OK, sets x to 10 int x = foo(2); // same as above property int foo(int x) {_foo = x;} foo = 2; // OK, sets _foo to 2 int x = 2.foo; // illegal int x = foo(2); // illegal I know this is not a complete solution, and can be confusing, but we have little options at this point, given existing code. Also note that we already have a way to specify a getter property on a user-defined type, UFCS isn't entirely necessary for that. This will break SOME declarations, but removing property should result in compiling code I think. -Steve
Feb 03 2013
next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/3 Steven Schveighoffer <schveiguy yahoo.com>

 I have a possible suggestion to fix this within your proposal:

  property on single-arg free functions ONLY enables a setter mode, it does
 not work as a UFCS getter.
[snip]

I was thinking the exact same thing.

Kenji Hara
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 7:40 AM, kenji hara wrote:
 2013/2/3 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>

     I have a possible suggestion to fix this within your proposal:

      property on single-arg free functions ONLY enables a setter mode,
     it does not work as a UFCS getter.

   [snip]

 I was thinking the exact same thing.
Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; } Andrei
Feb 03 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 12:36:10 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 7:40 AM, kenji hara wrote:
 2013/2/3 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>

     I have a possible suggestion to fix this within your proposal:

      property on single-arg free functions ONLY enables a setter mode,
     it does not work as a UFCS getter.

   [snip]

 I was thinking the exact same thing.
Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; }
ref T front(T[] array) { return array[0]; } // same unittest But I also can agree with the idea you currently have to make UFCS properties require a 'this' initial parameter. -Steve
Feb 03 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 06:47 PM, Steven Schveighoffer wrote:
 On Sun, 03 Feb 2013 12:36:10 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 7:40 AM, kenji hara wrote:
 2013/2/3 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>

     I have a possible suggestion to fix this within your proposal:

      property on single-arg free functions ONLY enables a setter mode,
     it does not work as a UFCS getter.

   [snip]

 I was thinking the exact same thing.
Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; }
ref T front(T[] array) { return array[0]; } // same unittest
different unittest: unittest{ auto a = [()=>2, ()=>3, ()=>4]; assert(a.front()==2); }
 But I also can agree with the idea you currently have to make UFCS
 properties require a 'this' initial parameter.

 -Steve
Feb 03 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 12:58:21 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 02/03/2013 06:47 PM, Steven Schveighoffer wrote:
 On Sun, 03 Feb 2013 12:36:10 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 7:40 AM, kenji hara wrote:
 2013/2/3 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>

     I have a possible suggestion to fix this within your proposal:

      property on single-arg free functions ONLY enables a setter mode,
     it does not work as a UFCS getter.

   [snip]

 I was thinking the exact same thing.
Then we can't make this work: property ref T front(T[] array) { return array[0]; } unittest { auto a = [ 1, 2, 3]; auto b = a.front; }
ref T front(T[] array) { return array[0]; } // same unittest
different unittest: unittest{ auto a = [()=>2, ()=>3, ()=>4]; assert(a.front()==2); }
OK, so that is not good. I think the current DIP23 idea should be sufficient, no global properties. -Steve
Feb 03 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu  
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style. -Steve
Feb 03 2013
next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/3 Steven Schveighoffer <schveiguy yahoo.com>

 On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer <
 schveiguy yahoo.com> wrote:

  On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <
 SeeWebsiteForEmail erdani.org**> wrote:

  Walter and I have had a discussion on how to finalize properties.
 http://wiki.dlang.org/DIP23
I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style.
On the contrary with you, I was read that we no longer get an address of ref returned value by address-op. property ref int foo(); static assert(is(typeof(&foo) == ref int function())); // typeof does not return int* If I am correct, there is no need for special enhancement like __traits. Kenji Hara
Feb 03 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 02:00 PM, kenji hara wrote:
 2013/2/3 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>
     ...

     I thought of one other problem with this proposal.  You can no
     longer get a delegate of a property.  Like it or not, there will be
     existing code that does get a delegate to properties (it is allowed
     now).

     I think we should provide a __traits accessor for this.  Otherwise,
     there is no way to port said code to the new style.


 On the contrary with you, I was read that we no longer get an address of
 ref returned value by address-op.

  property ref int foo();
 static assert(is(typeof(&foo) == ref int function()));  // typeof does
 not return int*

 If I am correct, there is no need for special enhancement like __traits.
The DIP actually misses to address this case.
Feb 03 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 08:00:32 -0500, kenji hara <k.hara.pg gmail.com> wrote:

 2013/2/3 Steven Schveighoffer <schveiguy yahoo.com>

 On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer <
 schveiguy yahoo.com> wrote:

  On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <
 SeeWebsiteForEmail erdani.org**> wrote:

  Walter and I have had a discussion on how to finalize properties.
 http://wiki.dlang.org/DIP23
I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style.
On the contrary with you, I was read that we no longer get an address of ref returned value by address-op. property ref int foo(); static assert(is(typeof(&foo) == ref int function())); // typeof does not return int* If I am correct, there is no need for special enhancement like __traits.
You are right, it does not specify this, I was somewhat mistaken. But the spirit of the proposal seems to suggest that for all intents and purposes, a property's type is the type of it's return value. For the most part, taking the address of an rvalue is an error anyway, so it makes sense to make this type of function return a delegate with the & operator. However, in the case of ref returns for properties, I think it may be too limiting if it is impossible to get the address of a ref return: property ref int foo(); int *x = &foo; // error returns delegate? int *y = &foo(); // error, using parens illegal? Somewhat glaring here is that you can't make ref local variables. I suppose in this case, the such a function could have property removed on it, but that is little help to the user of such a function who has no control over the API. A potential workaround could be a la Timon's suggestion: ref int foowrap() { return foo;} int *x = &foowrap(); Let's go with the current proposal, and I will address the __traits mechanism separately. -Steve
Feb 03 2013
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 15:16:30 UTC, Steven Schveighoffer 
wrote:
 But the spirit of the proposal seems to suggest that for all 
 intents and purposes, a property's type is the type of it's 
 return value.
If you want a function, then just don't annotate with property. The whole point of property is that it doesn't behave like a function.
Feb 03 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 10:31:31 -0500, deadalnix <deadalnix gmail.com> wrote:

 On Sunday, 3 February 2013 at 15:16:30 UTC, Steven Schveighoffer wrote:
 But the spirit of the proposal seems to suggest that for all intents  
 and purposes, a property's type is the type of it's return value.
If you want a function, then just don't annotate with property. The whole point of property is that it doesn't behave like a function.
That is not the point of properties. The point of properties is to have hooks for field setting and getting. They necessarily behave like functions. -Steve
Feb 03 2013
parent "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 3 February 2013 at 16:03:50 UTC, Steven Schveighoffer 
wrote:
 On Sun, 03 Feb 2013 10:31:31 -0500, deadalnix 
 <deadalnix gmail.com> wrote:
 If you want a function, then just don't annotate with 
  property. The whole point of property is that it doesn't 
 behave like a function.
That is not the point of properties. The point of properties is to have hooks for field setting and getting. They necessarily behave like functions. -Steve
That is not the point of properties. The point of setter and getter methods is to have hooks for field setting and getting. The point or properties is to have clearer semantics than what regular setter and getter methods would have.
Feb 03 2013
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Steven Schveighoffer <schveiguy yahoo.com>

 On Sun, 03 Feb 2013 08:00:32 -0500, kenji hara <k.hara.pg gmail.com>
 wrote:

 On the contrary with you, I was read that we no longer get an address of
 ref returned value by address-op.

  property ref int foo();
 static assert(is(typeof(&foo) == ref int function()));  // typeof does not
 return int*

 If I am correct, there is no need for special enhancement like __traits.
You are right, it does not specify this, I was somewhat mistaken. But the spirit of the proposal seems to suggest that for all intents and purposes, a property's type is the type of it's return value.
[snip] It is already satisfied. Inside typeof, all use of property makes its return type. I think the case of getting address of ref value returned from a property is much rare. If you really want to do it, we can write short workaround. A potential workaround could be a la Timon's suggestion:
 ref int foowrap() { return foo;}
 int *x = &foowrap();
One liner version: int* x = ((ref x) => &x)(foo); Let's go with the current proposal, and I will address the __traits
 mechanism separately.
It seems to me that is an overkill. Kenji Hara
Feb 03 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 10:56:50 -0500, kenji hara <k.hara.pg gmail.com> wrote:

 2013/2/4 Steven Schveighoffer <schveiguy yahoo.com>
 ref int foowrap() { return foo;}
 int *x = &foowrap();
One liner version: int* x = ((ref x) => &x)(foo);
That looks better than mine, it takes a bit to understand it :) It can be written into a global function: T *addressOf(T)(ref T t) {return &t;} I think this should actually work: int *x = foo.addressOf;
 Let's go with the current proposal, and I will address the __traits
 mechanism separately.
It seems to me that is an overkill.
I have other ideas for such a feature, which map into something I've wished for a long time. You will see. -Steve
Feb 03 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 10:16 AM, Steven Schveighoffer wrote:
 Let's go with the current proposal, and I will address the __traits
 mechanism separately.
Yes, __traits is a nice hatch if we discover we find we can't do something. Hopefully we won't find any, or just one. Andrei
Feb 03 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 06:44 PM, Andrei Alexandrescu wrote:
 On 2/3/13 10:16 AM, Steven Schveighoffer wrote:
 Let's go with the current proposal, and I will address the __traits
 mechanism separately.
Yes, __traits is a nice hatch if we discover we find we can't do something. Hopefully we won't find any, or just one. Andrei
__traits is a lot cleaner than assigning meaning to parentheses.
Feb 03 2013
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 01:49 PM, Steven Schveighoffer wrote:
 On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style. -Steve
T delegate() f = &a.prop -> auto f = ()=>a.prop; T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;
Feb 03 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:

 T delegate() f = &a.prop -> auto f = ()=>a.prop;
 T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;
I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function. -Steve
Feb 03 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 04:04 PM, Steven Schveighoffer wrote:
 On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:

 T delegate() f = &a.prop -> auto f = ()=>a.prop;
 T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;
I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function. -Steve
The spec could be updated to allow/mandate eta-reduction where applicable.
Feb 03 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 15:04:15 UTC, Steven Schveighoffer 
wrote:
 On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr 
 <timon.gehr gmx.ch> wrote:

 T delegate() f = &a.prop -> auto f = ()=>a.prop;
 T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;
I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function. -Steve
Unless you escape the delegate, it should allocate on the heap. And any inlining compiler should remove the delegate completely anyway.
Feb 03 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 02/03/13 16:04, Steven Schveighoffer wrote:
 On Sun, 03 Feb 2013 08:04:10 -0500, Timon Gehr <timon.gehr gmx.ch> wrote:
 
 T delegate() f = &a.prop -> auto f = ()=>a.prop;
 T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;
I don't like this solution. You are creating a dummy delegate function, and moving the stack frame into the heap, just so you can get a delegate to an already existing function.
Not really, it just needs to be specced properly. There's already a similar issue with lazy args, and the natural solution is the same. A trivial "{ return any_kind_of_hidden_delegate; }" lambda is functionally equivalent to a "cast(delegate)any_kind_of_hidden_delegate" expression. The "optimization" just needs to be mandated, so that you can rely on the "real" delegate being forwarded (ie the .funcptr should be the real one and such lambda shouldn't trigger heap allocation). artur
Feb 03 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 12:49:00 UTC, Steven Schveighoffer 
wrote:
 I thought of one other problem with this proposal.  You can no 
 longer get a delegate of a property.  Like it or not, there 
 will be existing code that does get a delegate to properties 
 (it is allowed now).
This isn't a problem.
Feb 03 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 7:49 AM, Steven Schveighoffer wrote:
 On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
I agree with everything in this. This looks exactly like what I wanted a few days ago. Thank you! One aspect not addressed is free-function properties:
I thought of one other problem with this proposal. You can no longer get a delegate of a property. Like it or not, there will be existing code that does get a delegate to properties (it is allowed now). I think we should provide a __traits accessor for this. Otherwise, there is no way to port said code to the new style.
In the proposal &a.b gets the delegate of a property. Andrei
Feb 03 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 3 February 2013 at 17:37:03 UTC, Andrei Alexandrescu 
wrote:
 In the proposal &a.b gets the delegate of a property.
:facepalm:
Feb 03 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 06:38 PM, deadalnix wrote:
 On Sunday, 3 February 2013 at 17:37:03 UTC, Andrei Alexandrescu wrote:
 In the proposal &a.b gets the delegate of a property.
:facepalm:
+1.
Feb 03 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not? -- /Jacob Carlborg
Feb 03 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.
 
 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not?
I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. ----------- - Jonathan M Davis
Feb 03 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-03 13:40, Jonathan M Davis wrote:

 I take it that you didn't read the DIP. At the very beginning of its section
 on "Write properties:"

 -----------
 In order to use the assignment operator "=" property-style, the  property
 annotation MUST be used.
 -----------
Right, I guess I missed that. -- /Jacob Carlborg
Feb 03 2013
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 03 Feb 2013 04:40:44 -0800
schrieb Jonathan M Davis <jmdavisProg gmx.com>:

 On Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.
 
 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not?
I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------
There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;
Feb 03 2013
next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 3 February 2013 at 15:48:00 UTC, Johannes Pfau wrote:
 -----------
 In order to use the assignment operator "=" property-style, the
  property annotation MUST be used.
 -----------
There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;
That example has nothing to do with properties. It's just: static int x; ref int fun1() { return x; } fun1() = 42; ...except that the empty parens were omitted (which is allowed there).
Feb 03 2013
parent Johannes Pfau <nospam example.com> writes:
Am Sun, 03 Feb 2013 17:01:59 +0100
schrieb "TommiT" <tommitissari hotmail.com>:

 On Sunday, 3 February 2013 at 15:48:00 UTC, Johannes Pfau wrote:
 -----------
 In order to use the assignment operator "=" property-style, the
  property annotation MUST be used.
 -----------
There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;
That example has nothing to do with properties. It's just: static int x; ref int fun1() { return x; } fun1() = 42; ...except that the empty parens were omitted (which is allowed there).
OK, but then 'In order to use the assignment operator "=" property-style, the property annotation MUST be used.' is wrong or a least misleading. IMHO "fun1 = 42;" is using "=" 'property style'. But if you think of it as a parentheses-less call that indeed makes sense.
Feb 03 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 10:48 AM, Johannes Pfau wrote:
 Am Sun, 03 Feb 2013 04:40:44 -0800
 schrieb Jonathan M Davis<jmdavisProg gmx.com>:

 On Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not?
I take it that you didn't read the DIP. At the very beginning of its section on "Write properties:" ----------- In order to use the assignment operator "=" property-style, the property annotation MUST be used. -----------
There's a example on the page though which contradicts this: static int x; ref int fun1() { return x; } fun1 = 42;
This introduces no contradiction. It's simple assignment to the result of fun1. Andrei
Feb 03 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 7:34 AM, Jacob Carlborg wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not?
No because writeln is not a property. For non-properties there's no lowering of assignment. Andrei
Feb 03 2013
parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 03 Feb 2013 10:37:45 -0500
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 2/3/13 7:34 AM, Jacob Carlborg wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not?
No because writeln is not a property. For non-properties there's no lowering of assignment. Andrei
Then this should be removed in the proposal: If a function returns a reference, then assignment through the paren-less call should work: unittest { static int x; ref int fun1() { return x; } fun1 = 42; }
Feb 03 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 10:49 AM, Johannes Pfau wrote:
 Am Sun, 03 Feb 2013 10:37:45 -0500
 schrieb Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>:

 On 2/3/13 7:34 AM, Jacob Carlborg wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
What about: writeln = "asd"; Allowed or not?
No because writeln is not a property. For non-properties there's no lowering of assignment. Andrei
Then this should be removed in the proposal: If a function returns a reference, then assignment through the paren-less call should work: unittest { static int x; ref int fun1() { return x; } fun1 = 42; }
No. That's not a lowering. Andrei
Feb 03 2013
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/3 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>

 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
Awesome!! After reading it, I thought that there is some consistent rules. 1. When a function is annotated with property, it cannot be called with parenthesis syntax. 2. 0-arg functions which not annotated with property can be called without parentheses. 3. Ref return getter can make "auxiliary setter", if formal getter is missing. 4. `typeof(exp)` never returns "function type". In other words, the actual type of `exp` and `typeof(exp)` should be same. 5. Both `&prop` and `&func` should return function pointer / delegate object 6. UFCS CAN NOT call global setter by getter syntax. I think that 4 to 6 are important points of this DIP. Based on the rules, I could write an exhaustive test case. alias Type = int; unittest { struct S { property Type foo(); // formal getter property void bar(Type); // formal setter property ref Type baz(); // ref return getter == auxiliary setter } S s; static assert( __traits(compiles, { s.foo; })); static assert(!__traits(compiles, { s.foo(); })); static assert(is(typeof(s.foo) == Type)); static assert(is(typeof(&s.foo) == Type delegate())); static assert( __traits(compiles, { s.bar = 1; })); static assert(!__traits(compiles, { s.bar(1); })); static assert(is(typeof(s.bar)) == false); static assert(is(typeof(&s.bar) == void delegate(Type))); static assert( __traits(compiles, { s.baz; })); static assert(!__traits(compiles, { s.baz(); })); static assert( __traits(compiles, { s.baz = 1; })); static assert(is(typeof(s.baz) == Type)); static assert(is(typeof(&s.foo) == ref Type delegate())); } unittest { struct S { Type foo(); // 0-arg function void bar(Type n); // 1-arg function ref Type baz(); // 0-arg ref return function } S s; static assert( __traits(compiles, { s.foo; })); static assert( __traits(compiles, { s.foo(); })); static assert(is(typeof(s.foo) == Type)); static assert(is(typeof(&s.foo) == Type delegate())); static assert(!__traits(compiles, { s.bar = 1; })); static assert( __traits(compiles, { s.bar(1); })); static assert(is(typeof(s.bar)) == false); static assert(is(typeof(&s.bar) == void delegate(Type))); static assert( __traits(compiles, { s.baz; })); static assert( __traits(compiles, { s.baz = 1; })); static assert( __traits(compiles, { s.baz(); })); static assert(is(typeof(s.baz) == Type)); static assert(is(typeof(&s.baz) == ref Type delegate())); } property Type foo(); property void bar(Type); property ref Type baz(); unittest { static assert( __traits(compiles, { foo; })); static assert(!__traits(compiles, { foo(); })); static assert(is(typeof(foo) == Type)); static assert(is(typeof(&foo) == Type function())); static assert( __traits(compiles, { bar = 1; })); static assert(!__traits(compiles, { bar(1); })); static assert(is(typeof(bar)) == false); static assert(is(typeof(&bar) == Type function())); static assert( __traits(compiles, { baz; })); static assert(!__traits(compiles, { baz(); })); static assert( __traits(compiles, { baz = 1; })); static assert(!__traits(compiles, { baz() = 1; })); static assert(is(typeof(baz) == Type)); static assert(is(typeof(&baz) == ref Type function())); } property Type foh(Type); property void bah(Type n, Type m); property ref Type bas(Type); Type hoo(Type); void var(Type, Type); ref Type vaz(Type); unittest { static assert( __traits(compiles, { foh = 1; }) && !__traits(compiles, { hoo = 1; })); static assert(!__traits(compiles, { foh(1); }) && __traits(compiles, { hoo(1); })); static assert(!__traits(compiles, { 1.foh; }) && __traits(compiles, { 1.hoo; })); static assert(!__traits(compiles, { 1.foh(); }) && __traits(compiles, { 1.hoo(); })); static assert(!__traits(compiles, { bah(1, 2); }) && __traits(compiles, { var(1, 2); })); static assert( __traits(compiles, { 1.bah = 2; }) && !__traits(compiles, { 1.var = 2; })); static assert(!__traits(compiles, { 1.bah(2); }) && __traits(compiles, { 1.var(2); })); static assert( __traits(compiles, { bas = 1; }) && !__traits(compiles, { vaz = 1; })); static assert(!__traits(compiles, { bas(1); }) && __traits(compiles, { vaz(1); })); static assert(!__traits(compiles, { bas(1) = 2; }) && __traits(compiles, { vaz(1) = 2; })); static assert(!__traits(compiles, { 1.bas; }) && __traits(compiles, { 1.vaz; })); static assert(!__traits(compiles, { 1.bas = 2; }) && __traits(compiles, { 1.vaz = 2; })); static assert(!__traits(compiles, { 1.bas(); }) && __traits(compiles, { 1.vaz(); })); static assert(!__traits(compiles, { 1.bas() = 2; }) && __traits(compiles, { 1.vaz() = 2; })); } Is this correct? Kenji Hara
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 7:37 AM, kenji hara wrote:
 1. When a function is annotated with  property, it cannot be called with
 parenthesis syntax.
 2. 0-arg functions which not annotated with  property can be called
 without parentheses.
 3. Ref return getter can make "auxiliary setter", if formal getter is
 missing.
 4. `typeof(exp)` never returns "function type". In other words, the
 actual type of `exp` and `typeof(exp)` should be same.
 5. Both `&prop` and `&func` should return function pointer / delegate object
 6. UFCS CAN NOT call global setter by getter syntax.
Yah. There is still some inconsistency, but I think there's no way to be 100% consistent. For properties &a.prop is not the same as &(a.prop), which is unlike other expressions.
 I think that 4 to 6 are important points of this DIP. Based on the
 rules, I could write an exhaustive test case.
I'll insert comments inline.
 alias Type = int;

 unittest
 {
      struct S
      {
           property Type foo();       // formal getter
           property void bar(Type);   // formal setter
           property ref Type baz();   // ref return getter == auxiliary
 setter
      }
      S s;
      static assert( __traits(compiles, { s.foo;     }));
      static assert(!__traits(compiles, { s.foo();   }));
      static assert(is(typeof(s.foo) == Type));
      static assert(is(typeof(&s.foo) == Type delegate()));
Yes, great. You may want to also add: static assert(!__traits(compiles, { auto p = &(s.foo); })); because that would apply & to the Type rvalue returned by s.foo.
      static assert( __traits(compiles, { s.bar = 1; }));
      static assert(!__traits(compiles, { s.bar(1);  }));
      static assert(is(typeof(s.bar)) == false);
      static assert(is(typeof(&s.bar) == void delegate(Type)));
Yes. Also: static assert(is(typeof(s.bar = 1) == void));
      static assert( __traits(compiles, { s.baz;     }));
      static assert(!__traits(compiles, { s.baz();   }));
      static assert( __traits(compiles, { s.baz = 1; }));
      static assert(is(typeof(s.baz) == Type));
      static assert(is(typeof(&s.foo) == ref Type delegate()));
Yes, assuming you meant "baz" on the last line, too.
 }
 unittest
 {
      struct S
      {
          Type foo();         // 0-arg function
          void bar(Type n);   // 1-arg function
          ref Type baz();     // 0-arg ref return function
      }
      S s;
      static assert( __traits(compiles, { s.foo;     }));
      static assert( __traits(compiles, { s.foo();   }));
      static assert(is(typeof(s.foo) == Type));
      static assert(is(typeof(&s.foo) == Type delegate()));
Correct. Also add: static assert(!is(typeof(&(s.foo))));
      static assert(!__traits(compiles, { s.bar = 1; }));
      static assert( __traits(compiles, { s.bar(1);  }));
      static assert(is(typeof(s.bar)) == false);
      static assert(is(typeof(&s.bar) == void delegate(Type)));
Correct. Also: static assert(!is(typeof(&(s.bar)))); because the expression s.bar is meaningless. (This is NEW BEHAVIOR.) The basic idea here is to disallow expressions that can't be typed.
      static assert( __traits(compiles, { s.baz;     }));
      static assert( __traits(compiles, { s.baz = 1; }));
      static assert( __traits(compiles, { s.baz();   }));
      static assert(is(typeof(s.baz) == Type));
      static assert(is(typeof(&s.baz) == ref Type delegate()));
 }
Correct. Also: static assert(is(typeof(&(s.baz)) == Type*));
  property Type foo();
I'm not sure we should allow this at module level. (And there is no way to write a corresponding setter.)
  property void bar(Type);
  property ref Type baz();
I think we should disallow this as well.
 unittest
 {
      static assert( __traits(compiles, { foo;     }));
      static assert(!__traits(compiles, { foo();   }));
      static assert(is(typeof(foo) == Type));
      static assert(is(typeof(&foo) == Type function()));
If we disallow top-level global properties neither of these will compile. If we do allow them, then the asserts would pass.
      static assert( __traits(compiles, { bar = 1; }));
      static assert(!__traits(compiles, { bar(1);  }));
      static assert(is(typeof(bar)) == false);
      static assert(is(typeof(&bar) == Type function()));
Nope, all of these are getters for int. The following should compile instead: static assert( __traits(compiles, { 1.bar; })); static assert(!__traits(compiles, { bar(1); })); static assert(is(typeof(bar)) == false); static assert(is(typeof(&bar) == void function(int)));
      static assert( __traits(compiles, { baz;       }));
      static assert(!__traits(compiles, { baz();     }));
      static assert( __traits(compiles, { baz = 1;   }));
      static assert(!__traits(compiles, { baz() = 1; }));
      static assert(is(typeof(baz) == Type));
      static assert(is(typeof(&baz) == ref Type function()));
If we allow top-level properties with 0 parameters, these should inded compile.
 }

  property Type foh(Type);
This is always a getter for Type returning a Type.
  property void bah(Type n, Type m);
This is always a setter having Type on the left-hand side and Type on the right-hand side.
  property ref Type bas(Type);
This is always a getter for Type.
 Type hoo(Type);
 void var(Type, Type);
 ref Type vaz(Type);

 unittest
 {
      static assert( __traits(compiles, { foh = 1; }) &&
 !__traits(compiles, { hoo = 1; }));
No, replace with: static assert( __traits(compiles, { 1.foh; }) && !__traits(compiles, { hoo = 1; }));
      static assert(!__traits(compiles, { foh(1);  }) &&
   __traits(compiles, { hoo(1);  }));
Correct.
      static assert(!__traits(compiles, { 1.foh;   }) &&
   __traits(compiles, { 1.hoo;   }));
Incorrect, foh is a getter for Type so the first should work. static assert(__traits(compiles, { 1.foh; }) && __traits(compiles, { 1.hoo; }));
      static assert(!__traits(compiles, { 1.foh(); }) &&
   __traits(compiles, { 1.hoo(); }));
This is identical to the one above.
      static assert(!__traits(compiles, { bah(1, 2); }) &&
   __traits(compiles, { var(1, 2); }));
Correct.
      static assert( __traits(compiles, { 1.bah = 2; }) &&
 !__traits(compiles, { 1.var = 2; }));
Correct.
      static assert(!__traits(compiles, { 1.bah(2);  }) &&
   __traits(compiles, { 1.var(2);  }));
First expression fails.
      static assert( __traits(compiles, { bas = 1;     }) &&
 !__traits(compiles, { vaz = 1;     }));
Both branches fail.
      static assert(!__traits(compiles, { bas(1);      }) &&
   __traits(compiles, { vaz(1);      }));
Correct.
      static assert(!__traits(compiles, { bas(1) = 2;  }) &&
   __traits(compiles, { vaz(1) = 2;  }));
Correct.
      static assert(!__traits(compiles, { 1.bas;       }) &&
   __traits(compiles, { 1.vaz;       }));
The first branch fails because 1.bas is legit.
      static assert(!__traits(compiles, { 1.bas = 2;   }) &&
   __traits(compiles, { 1.vaz = 2;   }));
First branch fails because 1.bas is legit and yields a ref int. Second branch passes.
      static assert(!__traits(compiles, { 1.bas();     }) &&
   __traits(compiles, { 1.vaz();     }));
Correct.
      static assert(!__traits(compiles, { 1.bas() = 2; }) &&
   __traits(compiles, { 1.vaz() = 2; }));
 }
Correct.
 Is this correct?
As noted above, I might have missed some. I will update the doc with a copy of your unittests. Thanks! Andrei
Feb 03 2013
next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/3/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 For properties &a.prop is not the same as &(a.prop),
 which is unlike other expressions.
I have an idea. The DIP says that property cannot return a property function. Therefore we could introduce a new built-in property (pardon the pun) that only property functions have, ala: a.prop.addrOf Similar to how we have .funcPtr for other types. This field would only exist for propery functions and therefore it's never ambiguous on whether it applies to the function or to the function call (it *has* to apply to the function since it cannot return a property. So instead of having behavior based on whether there are any parens involved, you would have: &a.prop; // address of return value &(a.prop) // ditto a.prop.addrOf // address of property function
Feb 03 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 12:34 PM, Andrei Alexandrescu wrote:
 On 2/3/13 7:37 AM, kenji hara wrote:
[snip] Copied your unittests with changes and explanations: http://wiki.dlang.org/DIP23#unittest. Please take a look and let me know of what you think! For now I conservatively disallow top-level properties with 0 parameters. I think we can allow them later if there's a strong need. Top-level properties with 1 argument are always getters. We need a bunch more with unittests that return callable entities. Andrei
Feb 03 2013
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/3/13, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 So instead of having behavior based on whether there are any parens
 involved, you would have:

 &a.prop;  // address of return value
 &(a.prop)  // ditto
 a.prop.addrOf  // address of property function
So, thoughts on this?
Feb 03 2013
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
 ...
Looks good. Two things: What about eg: property T front(T)(T[] arr){ return arr[0]; } And: "Avoid embarrassing situations such as expressions with unexpressible types or no-op address-of operator (as is the case with C functions)." The DIP does not fix the first issue. pragma(msg, typeof(*(int x)=>x)); // pure nothrow safe int(int x)
Feb 03 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 7:59 AM, Timon Gehr wrote:
 On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
 ...
Looks good. Two things: What about eg: property T front(T)(T[] arr){ return arr[0]; }
I updated the doc to clarify that one-parameter properties are ALWAYS getters and two-parameter properties are ALWAYS setters.
 And:

 "Avoid embarrassing situations such as expressions with unexpressible
 types or no-op address-of operator (as is the case with C functions)."

 The DIP does not fix the first issue.

 pragma(msg, typeof(*(int x)=>x)); // pure nothrow  safe int(int x)
I see. I think dereferencing a function or delegate type should never work. Andrei
Feb 03 2013
prev sibling next sibling parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:

 We also understand it's impossible to reconcile all viewpoints 
 and please all tastes. Our hope is to get to a point where the 
 rules are self-consistent, meaningful, and complete.
Should we add also non ambiguous ? I think everyone should agree upon your last paragraph.
Feb 03 2013
prev sibling next sibling parent reply FG <home fgda.pl> writes:
On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.
Very reasonable in the majority of the proposal. I can't, however, get my head around 2-arg property functions: int a_; property void a(int v, bool rev=false) { a_ = rev ? -v : v; } a = 10; // fine 10.a = true; // this feels backwards, true is just an extra flag The boolean flag is optional and making it the rhs of the assignment suggests it is the value which will be set. On the other hand switching argument positions, resulting in true.a = 10 also feels very strange. I'd say: allow only 0 or 1 argument in properties. If you need more arguments, write a normal function for it.
Feb 03 2013
next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/3 FG <home fgda.pl>

 On 2013-02-03 09:16, Andrei Alexandrescu wrote:

 Walter and I have had a discussion on how to finalize properties.
Very reasonable in the majority of the proposal. I can't, however, get my head around 2-arg property functions: int a_; property void a(int v, bool rev=false) { a_ = rev ? -v : v; } a = 10; // fine 10.a = true; // this feels backwards, true is just an extra flag The boolean flag is optional and making it the rhs of the assignment suggests it is the value which will be set. On the other hand switching argument positions, resulting in true.a = 10 also feels very strange. I'd say: allow only 0 or 1 argument in properties. If you need more arguments, write a normal function for it.
Two arguments property function would be declared only in module level, and just be called with UFCS. I think that functions annotated with property must not have default parameters. As you show, it would introduce not little ambiguity. Kenji Hara
Feb 03 2013
parent FG <home fgda.pl> writes:
On 2013-02-03 14:33, kenji hara wrote:
 Two arguments  property function would be declared only in module level,
 and just be called with UFCS.
 I think that functions annotated with  property must not have default
 parameters. As you show, it would introduce not little ambiguity.
With such constraints two argument property functions are fine, as long as it is their second argument that is most significant in the assignment. The DIP's 42.fun = 43 is the ideal counter-example of that. :)
Feb 03 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 8:16 AM, FG wrote:
 On 2013-02-03 09:16, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.
Very reasonable in the majority of the proposal. I can't, however, get my head around 2-arg property functions: int a_; property void a(int v, bool rev=false) { a_ = rev ? -v : v; }
I'd say never allow defaulted arguments with property.
 a = 10; // fine
 10.a = true; // this feels backwards, true is just an extra flag

 The boolean flag is optional and making it the rhs of the assignment
 suggests it is the value which will be set. On the other hand switching
 argument positions, resulting in true.a = 10 also feels very strange.

 I'd say: allow only 0 or 1 argument in properties.
 If you need more arguments, write a normal function for it.
Two-argument properties are always setters. Andrei
Feb 03 2013
prev sibling next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 Walter and I have had a discussion on how to finalize 
 properties.

 http://wiki.dlang.org/DIP23
 [..]
What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 10:35:29 -0500, TommiT <tommitissari hotmail.com>  
wrote:

 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
 [..]
What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
I would expect it to call S.prop, not the global prop. If not, that should be a bug (Kenji, you should add this case to the tests if not already there) With UFCS, you cannot override type-specified methods and properties. -Steve
Feb 03 2013
prev sibling next sibling parent FG <home fgda.pl> writes:
On 2013-02-03 16:35, TommiT wrote:
 What happens here?

 struct S
 {
      int _n;

       property ref int prop()
      {
          return _n;
      }
 }

  property void prop(ref S s, int n)
 {
      s._n = 42;
 }

 void main()
 {
      S s;
      s.prop = 10;
 }
This is an interesting problem. 1) I think setters should outrank getters when there's an assignment. 2) Also actual methods outrank UFCS free functions with same arguments. It's a question which rule has higher precedence. I think no.2 does and then _n becomes 10.
Feb 03 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 10:35 AM, TommiT wrote:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
 [..]
What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
The member is chosen. Andrei
Feb 03 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 3 February 2013 at 17:46:00 UTC, Andrei Alexandrescu 
wrote:
 On 2/3/13 10:35 AM, TommiT wrote:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei 
 Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize 
 properties.

 http://wiki.dlang.org/DIP23
 [..]
What happens here? struct S { int _n; property ref int prop() { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
The member is chosen. Andrei
What happens in these examples? Example 1: struct S { int _n; property ref const(int) prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; } -------------------------------------------- Example 2: struct T { int _n; disable void opAssign(T rhs) { } } struct S { T _t; property ref T prop() { return _t; } } property void prop(ref S s, T t) { s._t._n = t._n; } void main() { S s; s.prop = T.init; }
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 1:14 PM, TommiT wrote:
 Example 1:

 struct S
 {
 int _n;

  property ref const(int) prop() const
 {
 return _n;
 }
 }

  property void prop(ref S s, int n)
 {
 s._n = 42;
 }

 void main()
 {
 S s;
 s.prop = 10;
 }
This is a matter of visibility. The presence of a member precludes any UFCS. Won't compile. Same for the 2nd example. Andrei
Feb 03 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 3 February 2013 at 18:28:06 UTC, Andrei Alexandrescu 
wrote:
 [..]
 This is a matter of visibility. The presence of a member 
 precludes any UFCS. Won't compile. Same for the 2nd example.
Just to be perfectly clear, it must be that this wouldn't compile either, right? struct S { int _n; property int prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 1:32 PM, TommiT wrote:
 On Sunday, 3 February 2013 at 18:28:06 UTC, Andrei Alexandrescu wrote:
 [..]
 This is a matter of visibility. The presence of a member precludes any
 UFCS. Won't compile. Same for the 2nd example.
Just to be perfectly clear, it must be that this wouldn't compile either, right? struct S { int _n; property int prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Nope. Andrei
Feb 03 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 13:42:57 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 1:32 PM, TommiT wrote:
 On Sunday, 3 February 2013 at 18:28:06 UTC, Andrei Alexandrescu wrote:
 [..]
 This is a matter of visibility. The presence of a member precludes any
 UFCS. Won't compile. Same for the 2nd example.
Just to be perfectly clear, it must be that this wouldn't compile either, right? struct S { int _n; property int prop() const { return _n; } } property void prop(ref S s, int n) { s._n = 42; } void main() { S s; s.prop = 10; }
Nope.
He means "Nope it wouldn't compile" in case that was confusing ;) In general, functions must be overloaded within the same visibility level/scope. If there is one overload at a level, ALL overloads must exist at that level, or they are not seen. -Steve
Feb 03 2013
prev sibling next sibling parent reply "eles" <eles eles.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 In brief:

 * Optional parens stay.
This syntax sugar only helps in chained-UFCS calling. Why allowing it everywhere, that is even if the function's name is not followed by a dot? like this: Obj1.action1.action2.action3(); It is clearer than Obj1.action1().action2().action3(); and, still, does not allow something like Obj1.action1; requiring an Obj1.action1(); instead.
 * Just mentioning a function or method without parens does NOT 
 automatically take its address. (This is a change from the 
 current behavior.)
If you stick to the above "optional only if followed by a dot"-paradigm, you could maintain the behavior, except in that UFCS-chains, where it doesn't matter anyway what mentioning a function or method without parens returns, since one assumes invocation in this kind of chains.
 * Read properties (using  property) work as expected with the 
 mention that they may NOT be called with the parens. Any parens 
 would apply to the returned value.
And if the returned value is a parameterless function, shouldn't that be callable without parens?
 * Write properties (using  property) may only be used in the 
 assignment form (no function-style call allowed).
Feb 03 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 11:24 PM, eles wrote:
 On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu wrote:
 In brief:

 * Optional parens stay.
This syntax sugar only helps in chained-UFCS calling. ...
Nope. a.map!(a=>2*a);
 ...
 * Read properties (using  property) work as expected with the mention
 that they may NOT be called with the parens. Any parens would apply to
 the returned value.
And if the returned value is a parameterless function, shouldn't that be callable without parens? ...
No, it shouldn't. The rewrite is (rightfully) not applicable to expressions of first class function types. The only reason why the implicit calling and property approaches are workable is because the language also supports non first class functions (inherited directly from C).
Feb 03 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:
 ...

 * Just mentioning a function or method without parens does NOT
 automatically take its address. (This is a change from the current
 behavior.)
(No, it is not.) From the DIP: "This proposal sustains that optional parentheses should stay in. That means, if a function or method may be called without arguments, the trailing parens may be omitted. [...] The same goes about methods: [...] However, that's not the case with function objects, delegate objects, or objects that implement the function call operator. [...]" Should also mention static opCall. The section does not mention what happens with first class callables that are invoked via UFCS. In particular, the validity of eg. the following code (which currently is valid) is not specified: enum foo = (int x)=>x; static assert(2==2.foo);
Feb 03 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Feb 03, 2013 at 03:16:08AM -0500, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.
 
 http://wiki.dlang.org/DIP23
[...] +1. I think this proposal (1) addresses the most important issues with the current implementation of property, and (2) is probably one of the simplest ways to fix current issues without introducing too many changes and new features. I vote for this. T -- Having a smoking section in a restaurant is like having a peeing section in a swimming pool. -- Edward Burr
Feb 03 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
[snip]

Some more thinking got me to three simple principles that guide the 
proposed property design:

http://wiki.dlang.org/DIP23#In_a_nutshell

I think most, if not all, detailed rules derive from these.


Andrei
Feb 03 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Feb 03, 2013 at 08:30:48PM -0500, Andrei Alexandrescu wrote:
 On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
 [snip]
 
 Some more thinking got me to three simple principles that guide the
 proposed property design:
 
 http://wiki.dlang.org/DIP23#In_a_nutshell
 
 I think most, if not all, detailed rules derive from these.
[...] This is precisely the kind of simplicity we need to resolve this issue. I fully concur. T -- 2+2=4. 2*2=4. 2^2=4. Therefore, +, *, and ^ are the same operation.
Feb 03 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, February 03, 2013 20:30:48 Andrei Alexandrescu wrote:
 On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
 [snip]
 
 Some more thinking got me to three simple principles that guide the
 proposed property design:
 
 http://wiki.dlang.org/DIP23#In_a_nutshell
 
 I think most, if not all, detailed rules derive from these.
Technically, the bit about having exactly one or exactly two parameters is wrong, unless you're counting the invisible this pointer/reference in that. Member property functions end up with exactly zero or exactly one parameters. - Jonathan M Davis
Feb 03 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-04 02:56, Jonathan M Davis wrote:

 Technically, the bit about having exactly one or exactly two parameters is
 wrong, unless you're counting the invisible this pointer/reference in that.
 Member property functions end up with exactly zero or exactly one parameters.
I don't know if the text has been update since you read it but it says: "counting the implicit this parameter if at all". -- /Jacob Carlborg
Feb 04 2013
prev sibling next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu 
wrote:
 I think most, if not all, detailed rules derive from these.
One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given. Introducing a rule by which parenthesizing an expression in a way that does not change precedence suddenly causes a difference in behavior certainly wouldn't be among the first ideas coming to my mind this way. David
Feb 03 2013
next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu 
 wrote:
 I think most, if not all, detailed rules derive from these.
One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way su<ch strange behavior could be explained in a way that is coherent with the rest of the language.
As another data point, Walter wrote a while ago himself: »I'm just arguing against the e and (e) solution as (perhaps) causing more ambiguity problems«. David
Feb 03 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu 
 wrote:
 I think most, if not all, detailed rules derive from these.
One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.
The problem we are dealing with here isn't complex. It is made complex artificially. We are trying to make properties behave like fields, but hey in this case I want it to behave like a function . . . oh yeah so in this special case, I have to workaround, ho and here and here as well, oh damn, that is complicated. Same goes when conflating the function with it's return value (which optional () is about).
 Introducing a rule by which parenthesizing an expression in a 
 way that does not change precedence suddenly causes a 
 difference in behavior certainly wouldn't be among the first 
 ideas coming to my mind this way.
By trying to make things easy, we miss that the important point is to make them simple.
Feb 03 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 03:28 AM, deadalnix wrote:
 On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:
 I think most, if not all, detailed rules derive from these.
One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.
The problem we are dealing with here isn't complex. It is made complex artificially.
It is not even made complex. It is quite obvious how things should work. (and &a vs &(a) is not it.)
 We are trying to make  properties behave like fields,
(Syntactically.)
 but hey in this  case I want it to behave like a function . . .
This is the step that must be reconsidered.
 oh yeah so in this
 special case, I have to workaround, ho and here and here as well, oh
 damn, that is complicated.

 Same goes when conflating the function with it's return value (which
 optional () is about).
Certainly not! & is the syntactic element distinguishing functions from return values, not (). Optional & would be about conflating the function with its return value. (Scala basically does this, but instead of prefix & they use suffix _.)
 Introducing a rule by which parenthesizing an expression in a way that
 does not change precedence suddenly causes a difference in behavior
 certainly wouldn't be among the first ideas coming to my mind this way.
By trying to make things easy, we miss that the important point is to make them simple.
Most of this stuff is simple enough. Have you implemented optional parens already?
Feb 03 2013
prev sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
On Monday, 4 February 2013 at 02:28:39 UTC, deadalnix wrote:
 On Monday, 4 February 2013 at 02:18:08 UTC, David Nadlinger 
 wrote:
 On Monday, 4 February 2013 at 01:30:49 UTC, Andrei 
 Alexandrescu wrote:
 I think most, if not all, detailed rules derive from these.
One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)". There is no way such strange behavior could be explained in a way that is coherent with the rest of the language. I found that when you are working on a complex problem and have a solution that seems to work for everything except a little detail, the best approach often is to step back a bit and have an entirely fresh look at that area again, but now taking the rest of your design as a given.
The problem we are dealing with here isn't complex. It is made complex artificially. We are trying to make properties behave like fields, but hey in this case I want it to behave like a function . . . oh yeah so in this special case, I have to workaround, ho and here and here as well, oh damn, that is complicated. Same goes when conflating the function with it's return value (which optional () is about).
Not sure I'm following – you are arguing that the whole endeavor is futile as long as we keep parens-less function calls? I actually think that DIP23 is a big step in the right direction, given that parens-less function calls are *very* unlikely to go away. Contrary to some of the previous proposals, it's actually a principled approach, like Adam and others (including me) have asked for. Now it's just a matter of getting the details right.
 Introducing a rule by which parenthesizing an expression in a 
 way that does not change precedence suddenly causes a 
 difference in behavior certainly wouldn't be among the first 
 ideas coming to my mind this way.
By trying to make things easy, we miss that the important point is to make them simple.
My point is precisely that. I think there are much simpler solutions than adding some magic properties to a pair of parentheses in the right position, even if it might look like a convenient hack. David
Feb 03 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler solutions
 than adding some magic properties to a pair of parentheses in the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all. Think it over, and compare it with the language semantics even today. Andrei
Feb 03 2013
next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu 
wrote:
 On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler 
 solutions
 than adding some magic properties to a pair of parentheses in 
 the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all. Think it over, […]
I've done that. What about *you* thinking it over? :P
 and compare it with the language semantics even today.
I thought we agreed that today's semantics are hopelessly broken. Actually, we might already have some of the &a vs. &(a) stuff, I remember Kenji opening a pull request about that at some point, but don't know if it went in OTOH. David
Feb 03 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu 
wrote:
 On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler 
 solutions
 than adding some magic properties to a pair of parentheses in 
 the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all. Think it over, and compare it with the language semantics even today.
Going from complete crap to bearable don't make bearable good.
Feb 03 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 05:21 AM, deadalnix wrote:
 On Monday, 4 February 2013 at 03:13:07 UTC, Andrei Alexandrescu wrote:
 On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler solutions
 than adding some magic properties to a pair of parentheses in the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all. Think it over, and compare it with the language semantics even today.
Going from complete crap to bearable don't make bearable good.
In what way is this bearable?
Feb 04 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 13:12:54 UTC, Timon Gehr wrote:
 On 02/04/2013 05:21 AM, deadalnix wrote:
 On Monday, 4 February 2013 at 03:13:07 UTC, Andrei 
 Alexandrescu wrote:
 On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler 
 solutions
 than adding some magic properties to a pair of parentheses 
 in the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all. Think it over, and compare it with the language semantics even today.
Going from complete crap to bearable don't make bearable good.
In what way is this bearable?
The proposal is a big improvement over current behavior. Still it has major flaws, like the way & and property interact.
Feb 04 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 04:13 AM, Andrei Alexandrescu wrote:
 On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler solutions
 than adding some magic properties to a pair of parentheses in the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all.
It is a horrible hack. Why is this not obvious?
 Think it over, and compare it with the language semantics even today.
I am intimately familiar with today's language semantics as I am writing a D compiler front end. Please be more explicit.
Feb 04 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 9:34 AM, Timon Gehr wrote:
 On 02/04/2013 04:13 AM, Andrei Alexandrescu wrote:
 On 2/3/13 9:58 PM, David Nadlinger wrote:
 My point is precisely that. I think there are much simpler solutions
 than adding some magic properties to a pair of parentheses in the right
 position, even if it might look like a convenient hack.
I don't think it's a hack at all.
It is a horrible hack. Why is this not obvious?
I think it's because it's a matter in which reasonable people may disagree. Andrei
Feb 04 2013
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I think it's because it's a matter in which reasonable people may disagree.
Well, Walter seemed to agree with us before: d.puremagic.com/issues/show_bug.cgi?id=9062#c13 And even Kenji who likes it seemed to close his pull: https://github.com/D-Programming-Language/dmd/pull/1310#issuecomment-12524998 I don't know what changed their opinions now.
Feb 04 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 02:58:55 UTC, David Nadlinger wrote:
 Not sure I'm following – you are arguing that the whole 
 endeavor is futile as long as we keep parens-less function 
 calls?

 I actually think that DIP23 is a big step in the right 
 direction, given that parens-less function calls are *very* 
 unlikely to go away. Contrary to some of the previous 
 proposals, it's actually a principled approach, like Adam and 
 others (including me) have asked for. Now it's just a matter of 
 getting the details right.
My point is that we try to pack fundamentally different concept into one. Which is doomed to produce a three headed monster.
 My point is precisely that. I think there are much simpler 
 solutions than adding some magic properties to a pair of 
 parentheses in the right position, even if it might look like a 
 convenient hack.
Convenient hack is not good design.
Feb 03 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 9:17 PM, David Nadlinger wrote:
 On Monday, 4 February 2013 at 01:30:49 UTC, Andrei Alexandrescu wrote:
 I think most, if not all, detailed rules derive from these.
One does not, the strange special case for taking the address of a property. I'd REALLY urge you to explore alternative solutions, such as the one proposed by Andrej, before introducing an abomination like distinguishing between "&a" and "&(a)".
Andrej's proposal is nice, but I think you're wrong about this. We're already there - &a.b means something (a delegate) which is not decomposable into smaller parts.
 There is no way such strange behavior could be explained in a way that
 is coherent with the rest of the language.
I disagree.
 I found that when you are working on a complex problem and have a
 solution that seems to work for everything except a little detail, the
 best approach often is to step back a bit and have an entirely fresh
 look at that area again, but now taking the rest of your design as a given.
I agree with the general thought.
 Introducing a rule by which parenthesizing an expression in a way that
 does not change precedence suddenly causes a difference in behavior
 certainly wouldn't be among the first ideas coming to my mind this way.
I really think you are wrong about this. Parenthesizing has nothing to do with this. &a.b is punctuation that creates an indivizible unit. Andrei
Feb 03 2013
parent reply "David Nadlinger" <see klickverbot.at> writes:
On Monday, 4 February 2013 at 03:11:25 UTC, Andrei Alexandrescu 
wrote:
 There is no way such strange behavior could be explained in a 
 way that
 is coherent with the rest of the language.
I disagree.
Then I'm eager to hear your explanation. Parentheses in an expression usually change precedence. Here they do something entirely different.
 Introducing a rule by which parenthesizing an expression in a 
 way that
 does not change precedence suddenly causes a difference in 
 behavior
 certainly wouldn't be among the first ideas coming to my mind 
 this way.
I really think you are wrong about this. Parenthesizing has nothing to do with this. &a.b is punctuation that creates an indivizible unit.
a.b already is an indivisible unit, the result of the function call. David
Feb 03 2013
parent reply "David Nadlinger" <see klickverbot.at> writes:
On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 03:11:25 UTC, Andrei Alexandrescu 
 wrote:
 I really think you are wrong about this. Parenthesizing has 
 nothing to do with this. &a.b is punctuation that creates an 
 indivizible unit.
a.b already is an indivisible unit, the result of the function call.
Actually, let me illustrate this point a bit further, sorry for the hasty reply. The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively. Now, grouping the expression »&a.b« according to the precedence rules yields »&(a.b)« – but in your proposal, they mean completely different things. You could argue that &<expression>.<identifier> is a special construct different from the normal address-of operator. But where do you mentally draw the line? What about &a.b.c <-> &(a.b).c <-> &((a.b).c)? &(a + b).c <-> &((a + b).c)? Again, from an user's perspective the change in behavior seems to be completely at odds with the usual rule in C-family languages that grouping parens can be added without changing the meaning of an expression. Thus, this part of the proposed syntax strikes me as being extremely misleading, which is especially bad because the situation with the two possible meanings is confusing enough to start out with already. And how often do you think you'll find yourself in the situation of needing to get a delegate from a property anyway? Can't we just make » property getter expressions are always equivalent to their return value« a hard (simple!) rule and add something like __traits(propertyGetter, ...) for the rare cases where you really need to get hold of the underlying function? David
Feb 03 2013
next sibling parent reply "BLM768" <blm768 gmail.com> writes:
On Monday, 4 February 2013 at 04:00:28 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger 
 wrote:

 And how often do you think you'll find yourself in the 
 situation of needing to get a delegate from a property anyway? 
 Can't we just make » property getter expressions are always 
 equivalent to their return value« a hard (simple!) rule and add 
 something like __traits(propertyGetter, ...) for the rare cases 
 where you really need to get hold of the underlying function?

 David
I like this solution; it follows the Principle of Least Surprise quite well. The syntax may be a bit longer, but it's immediately obvious even to a beginning/intermediate D user what's going on without having to worry about too many nuances.
Feb 03 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 11:17 PM, BLM768 wrote:
 On Monday, 4 February 2013 at 04:00:28 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote:

 And how often do you think you'll find yourself in the situation of
 needing to get a delegate from a property anyway? Can't we just make
 » property getter expressions are always equivalent to their return
 value« a hard (simple!) rule and add something like
 __traits(propertyGetter, ...) for the rare cases where you really need
 to get hold of the underlying function?

 David
I like this solution; it follows the Principle of Least Surprise quite well. The syntax may be a bit longer, but it's immediately obvious even to a beginning/intermediate D user what's going on without having to worry about too many nuances.
This is a good point, and __traits make all possible syntactic confusion go away. Andrei
Feb 03 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, February 04, 2013 05:00:21 David Nadlinger wrote:
 On Monday, 4 February 2013 at 03:15:51 UTC, David Nadlinger wrote:
 On Monday, 4 February 2013 at 03:11:25 UTC, Andrei Alexandrescu
=20
 wrote:
 I really think you are wrong about this. Parenthesizing has
 nothing to do with this. &a.b is punctuation that creates an
 indivizible unit.
=20 a.b already is an indivisible unit, the result of the function call.
=20 Actually, let me illustrate this point a bit further, sorry for the hasty reply. =20 The problem I see is that usually, one can insert grouping pairs of parentheses into an expression according to the operator precedence/associativity rules at will without changing the result. This isn't merely a theoretical exercise, but the way (well, in the form of trees) I tend to reason about source code intuitively. =20 Now, grouping the expression =C2=BB&a.b=C2=AB according to the preced=
ence
 rules yields =C2=BB&(a.b)=C2=AB =E2=80=93 but in your proposal, they =
mean
 completely different things.
=20
 You could argue that &<expression>.<identifier> is a special
 construct different from the normal address-of operator. But
 where do you mentally draw the line? What about &a.b.c <->
 &(a.b).c <-> &((a.b).c)? &(a + b).c <-> &((a + b).c)?
=20
 Again, from an user's perspective the change in behavior seems to
 be completely at odds with the usual rule in C-family languages
 that grouping parens can be added without changing the meaning of
 an expression. Thus, this part of the proposed syntax strikes me
 as being extremely misleading, which is especially bad because
 the situation with the two possible meanings is confusing enough
 to start out with already.
=20
 And how often do you think you'll find yourself in the situation
 of needing to get a delegate from a property anyway? Can't we
 just make =C2=BB property getter expressions are always equivalent to=
 their return value=C2=AB a hard (simple!) rule and add something like=
 __traits(propertyGetter, ...) for the rare cases where you really
 need to get hold of the underlying function?
I tend to agree that making the parens change the nature of the express= ion is=20 a bad idea. I'm also concerned that making it legal to take the address= of a=20 property function is going to cause serious issues when anyone tries to= =20 actually try and swap between variables and property functions. But the= re's=20 also the issue of it not being terribly common to need the address of a= =20 property function. The biggest concern there would be what happens when= =20 someone takes the address of a variable which then gets turned into a=20= property. It's not going to work, and the way that that it doesn't work= is=20 going to vary depending on what & does on a property function and what = they're=20 trying to assign it to. - Jonathan M Davis
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 11:31 PM, Jonathan M Davis wrote:
 I tend to agree that making the parens change the nature of the expression is
 a bad idea.
I think there's some misunderstanding here. Parens change the nature of expressions ALL the time. There is a weird rule in C++11 that makes sometimes typeof(expr) and typeof((expr)) mean different things. That is arguably an example to avoid. But introducing parens among parts of an expression is expected to affect meaning. Andrei
Feb 03 2013
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 05:36:10 UTC, Andrei Alexandrescu 
wrote:
 On 2/3/13 11:31 PM, Jonathan M Davis wrote:
 I tend to agree that making the parens change the nature of 
 the expression is
 a bad idea.
I think there's some misunderstanding here. Parens change the nature of expressions ALL the time. There is a weird rule in C++11 that makes sometimes typeof(expr) and typeof((expr)) mean different things. That is arguably an example to avoid. But introducing parens among parts of an expression is expected to affect meaning.
Weird behaviors of C++ are a very good reason to have D in the first place.
Feb 03 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 06:36 AM, Andrei Alexandrescu wrote:
 On 2/3/13 11:31 PM, Jonathan M Davis wrote:
 I tend to agree that making the parens change the nature of the
 expression is a bad idea.
I think there's some misunderstanding here.
Agreed.
 Parens change the nature of expressions ALL the time.
In D? No way. Precedence rules are introduced in order to make parens _implicit_. In a language with unary & and binary ., There are two possible interpretations for &a.b: (&a).b &(a.b) In the case of D, &a.b is just a shortcut for &(a.b). How can they denote different things?
 There is a weird rule in C++11 that makes sometimes typeof(expr) and
 typeof((expr)) mean different things.
There is also the argument-dependent name lookup thing namespace bar{ struct S{} baz; S foo(S x){ return x; } } int main(){ foo(bar::baz); // Koenig lookup finds bar::foo (foo)(bar::baz); // no Koenig lookup, foo undefined } Not examples to follow.
 That is arguably an example to
 avoid. But introducing parens among parts of an expression is expected
 to affect meaning.
Sure, but that is not what happens here at all. The parens are introduced around ONE part of the expression.
Feb 04 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 11:00 PM, David Nadlinger wrote:
 The problem I see is that usually, one can insert grouping pairs of
 parentheses into an expression according to the operator
 precedence/associativity rules at will without changing the result. This
 isn't merely a theoretical exercise, but the way (well, in the form of
 trees) I tend to reason about source code intuitively.
Well this is going to sound bad, but you either use reason or intuition. I don't see how one can reason intuitively.
 Now, grouping the expression »&a.b« according to the precedence rules
 yields »&(a.b)« – but in your proposal, they mean completely different
 things.
I agree they mean different things. I'm unclear that's a problem. All your examples stop here, there's no propagation of the issue. To take the address of a property, one writes &obj.prop. To take the address of a property's result, one writes &(obj.prop). And that's that. It all works with typeof.
 You could argue that &<expression>.<identifier> is a special construct
 different from the normal address-of operator. But where do you mentally
 draw the line? What about &a.b.c <-> &(a.b).c <-> &((a.b).c)? &(a + b).c
 <-> &((a + b).c)?
That argument is easily destroyed. In a.b.c, a.b is the expression and c is the property name.
 Again, from an user's perspective the change in behavior seems to be
 completely at odds with the usual rule in C-family languages that
 grouping parens can be added without changing the meaning of an
 expression.
I think we avoid much more bizarre things that way, such that expr and &expr meaning sometimes the same exact thing. Or that we have expressions without a type. And nobody blinks an eye. I just think we're better off.
 Thus, this part of the proposed syntax strikes me as being
 extremely misleading, which is especially bad because the situation with
 the two possible meanings is confusing enough to start out with already.
 And how often do you think you'll find yourself in the situation of
 needing to get a delegate from a property anyway? Can't we just make
 » property getter expressions are always equivalent to their return
 value« a hard (simple!) rule and add something like
 __traits(propertyGetter, ...) for the rare cases where you really need
 to get hold of the underlying function?
I don't see where the trouble is. If I thought the trait is necessary, I'd make it part of the proposal. Currently I don't see it as necessary, but I definitely can be convinced. Andrei
Feb 03 2013
next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>

 On 2/3/13 11:00 PM, David Nadlinger wrote:

  Now, grouping the expression =C2=BB&a.b=C2=AB according to the preceden=
ce rules
 yields =C2=BB&(a.b)=C2=AB =E2=80=93 but in your proposal, they mean comp=
letely different
 things.
I agree they mean different things. I'm unclear that's a problem. All you=
r
 examples stop here, there's no propagation of the issue. To take the
 address of a property, one writes &obj.prop. To take the address of a
 property's result, one writes &(obj.prop). And that's that. It all works
 with typeof.
If the expression is generated from string mixin, might have a problem. // This is much simple case. Real example might be more complicated. template AddressOf(string exp) { enum AddressOf =3D "&" ~ exp; } struct S { property int prop() { return 1; } } void main() { S s; assert(s.prop =3D=3D 1); int* p =3D mixin(AddressOf!("s.prop")); // &s.prop returns delegate } I think that parenthesis-dependent syntax is not good. Kenji Hara
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 12:53 AM, kenji hara wrote:
 If the expression is generated from string mixin, might have a problem.

 // This is much simple case. Real example might be more complicated.
 template AddressOf(string exp)
 {
      enum AddressOf = "&" ~ exp;
 }
 struct S {
       property int prop() { return 1; }
 }
 void main() {
      S s;
      assert(s.prop == 1);
      int* p = mixin(AddressOf!("s.prop"));  // &s.prop returns delegate
 }

 I think that parenthesis-dependent syntax is not good.

 Kenji Hara
Couldn't AddressOf use "&(" + exp + ")"? I thought more about this. The problem remains even without property, due to optional parens in function invocation. Consider: ref int fun() { ... } auto p1 = &fun; auto p2 = &(fun); auto p3 = &(fun()); What are the types of the three? The optional parens in invocation require some disambiguation. I think the sensible disambiguation is to have &fun take the address of fun and the other two take the address of fun's result. I would agree restricting the properties, but requiring a __trait to take the address of a regular function or method seems overkill. Andrei
Feb 04 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:
 ...
 Couldn't AddressOf use "&(" + exp + ")"?

 I thought more about this. The problem remains even without  property,
 due to optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in invocation
 require some disambiguation.
The obvious rule is not to give significance to redundant parentheses.
 I think the sensible disambiguation is to
 have &fun take the address of fun and the other two take the address of
 fun's result.
No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.) The rules are straightforward: A non- property function name 'foo' denotes a function invocation without arguments iff it does not occur in one of the following contexts: 1. foo(...) // explicitly called 2. &foo // address taken 3. ...!(...,foo,...) // template argument (well, that's what DMD currently does) 4. alias ... = foo; // aliased
 I would agree restricting the properties, but requiring a __trait to
 take the address of a regular function or method seems overkill.
I have no idea how the conclusion would be reached that this is necessary under any of the discussed schemes.
Feb 04 2013
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 14:25:10 UTC, Timon Gehr wrote:
 On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:
 ...
 Couldn't AddressOf use "&(" + exp + ")"?

 I thought more about this. The problem remains even without 
  property,
 due to optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in 
 invocation
 require some disambiguation.
The obvious rule is not to give significance to redundant parentheses.
 I think the sensible disambiguation is to
 have &fun take the address of fun and the other two take the 
 address of
 fun's result.
No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.)
Scala don't really agree. fun is the function pointer. It is evaluated if the function pointer is a NOOP, but that's it. Here is scala semantic with D syntax : void bar() {} bar; // execute bar. Is an exception because taking the function pointer is a NOOP. void foo(void function() bar) {} foo(bar); // OK, bar is not evaluated.
Feb 04 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 04:02 PM, deadalnix wrote:
 On Monday, 4 February 2013 at 14:25:10 UTC, Timon Gehr wrote:
 On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:
 ...
 Couldn't AddressOf use "&(" + exp + ")"?

 I thought more about this. The problem remains even without  property,
 due to optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in invocation
 require some disambiguation.
The obvious rule is not to give significance to redundant parentheses.
 I think the sensible disambiguation is to
 have &fun take the address of fun and the other two take the address of
 fun's result.
No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.)
Scala don't really agree. fun is the function pointer. It is evaluated if the function pointer is a NOOP, but that's it.
Of course Scala agrees. scala> def foo() = 2 foo: ()Int scala> foo res0: Int = 2 scala> foo _ res1: () => Int = <function0> scala> (foo) _ res2: () => Int = <function0> scala> def bar[A](arg : A) = arg bar: [A](arg: A)A scala> bar(foo) res3: Int = 2
 Here is scala semantic
 with D syntax :

 void bar() {}
 bar; // execute bar. Is an exception because taking the function pointer
 is a NOOP.
No, it is the rule.
 void foo(void function() bar) {}
 foo(bar); // OK, bar is not evaluated.
This is the exception. (That nobody has argued in favour of so far.)
Feb 04 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 9:25 AM, Timon Gehr wrote:
 On 02/04/2013 03:05 PM, Andrei Alexandrescu wrote:
 I think the sensible disambiguation is to
 have &fun take the address of fun and the other two take the address of
 fun's result.
No! &fun and &(fun) are the same thing. Functions that get their address taken are not implicitly invoked. (Again, Scala agrees.) The rules are straightforward: A non- property function name 'foo' denotes a function invocation without arguments iff it does not occur in one of the following contexts: 1. foo(...) // explicitly called 2. &foo // address taken 3. ...!(...,foo,...) // template argument (well, that's what DMD currently does) 4. alias ... = foo; // aliased
The problem with (3) is that it creates a rule that gives different meaning of expressions inside &(...) and outside it. Consider: &foo -> fine, takes the address of foo &(foo) -> parens don't matter, sweet, still takes the address of foo &( condition ? foo : bar ) -> hum, I guess takes the address of foo or bar &( { auto a = foo; ... return c ? foo : bar; }() ) -> what??? So this is essentially a rule that makes the same give expression have a meaning inside &( ... ) and a different meaning outside. In &expr.name and &(expr.name), that's it - expr may be arbitrarily complicated, but the construct must always end with a method name. In &name and &(name), it's even simpler - it's just punctuation. Andrei
Feb 04 2013
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>

 Couldn't AddressOf use "&(" + exp + ")"?
Yes. It's enough. I wanted to explain that "we should treat address-expression carefully".
 I thought more about this. The problem remains even without  property, due
 to optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in invocation require
 some disambiguation. I think the sensible disambiguation is to have &fun
 take the address of fun and the other two take the address of fun's result.
Agreed.
 I would agree restricting the properties, but requiring a __trait to take
 the address of a regular function or method seems overkill.
Fully agreed. Although it looks strange and unstable, adding new distinction of semantics between &foo and &(foo) has no ambiguity. I think this is necessary feature for the D's function and property semantics. Kenji Hara
Feb 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 03:38 PM, kenji hara wrote:
 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org
 <mailto:SeeWebsiteForEmail erdani.org>>


     Couldn't AddressOf use "&(" + exp + ")"?


 Yes. It's enough. I wanted to explain that "we should treat
 address-expression carefully".

     I thought more about this. The problem remains even without
      property, due to optional parens in function invocation. Consider:

     ref int fun() { ... }
     auto p1 = &fun;
     auto p2 = &(fun);
     auto p3 = &(fun());

     What are the types of the three? The optional parens in invocation
     require some disambiguation. I think the sensible disambiguation is
     to have &fun take the address of fun and the other two take the
     address of fun's result.


 Agreed.
Why?
     I would agree restricting the properties, but requiring a __trait to
     take the address of a regular function or method seems overkill.


 Fully agreed.
It is not an interesting point. It is not necessary anyway.
 Although it looks strange and unstable, adding new distinction of
 semantics between &foo and &(foo) has no ambiguity.
It _is_ strange.
 I think this is necessary feature for the D's function and property
 semantics.
Why?
Feb 04 2013
next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Timon Gehr <timon.gehr gmx.ch>

 On 02/04/2013 03:38 PM, kenji hara wrote:

 I think this is necessary feature for the D's function and property
 semantics.
Why?
Because, "property" is one of D-specific feature. In D, "property" is directly translated to function call. So, we should get balance between two requirements: 1. property should be treated as its returned type. 2. property should be distinguished from raw field. (For example, serialization library should recognize it) Address expression is _only_one_ built-in feature to make a callable object from function symbol. So this "special feature" is enough reasonable to me. Kenji Hara
Feb 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 04:08 PM, kenji hara wrote:
 2013/2/4 Timon Gehr <timon.gehr gmx.ch <mailto:timon.gehr gmx.ch>>

     On 02/04/2013 03:38 PM, kenji hara wrote:

         I think this is necessary feature for the D's function and property
         semantics.


     Why?


 Because, "property" is one of D-specific feature.

 In D, "property" is directly translated to function call. So, we should
 get balance between two requirements:
 1. property should be treated as its returned type.
 2. property should be distinguished from raw field. (For example,
 serialization library should recognize it)
This is what __traits are for.
 Address expression is _only_one_ built-in feature to make a callable
 object from function symbol.
Property symbols are not to be treated like function symbols syntactically. That is the point. Otherwise we may as well get rid of properties.
 So this "special feature" is enough reasonable to me.

 ...
"special features" are usually not reasonable.
Feb 04 2013
parent kenji hara <k.hara.pg gmail.com> writes:
I have thought in long term that, in D, "proerty" is just a syntactic
rerwiting rule of  function call. It is much reasonable abstraction to me.

So, using __trait is overkill.

Kenji Hara
2013/02/05 0:45 "Timon Gehr" <timon.gehr gmx.ch>:

 On 02/04/2013 04:08 PM, kenji hara wrote:

 2013/2/4 Timon Gehr <timon.gehr gmx.ch <mailto:timon.gehr gmx.ch>>

     On 02/04/2013 03:38 PM, kenji hara wrote:

         I think this is necessary feature for the D's function and
 property
         semantics.


     Why?


 Because, "property" is one of D-specific feature.

 In D, "property" is directly translated to function call. So, we should
 get balance between two requirements:
 1. property should be treated as its returned type.
 2. property should be distinguished from raw field. (For example,
 serialization library should recognize it)
This is what __traits are for. Address expression is _only_one_ built-in feature to make a callable
 object from function symbol.
Property symbols are not to be treated like function symbols syntactically. That is the point. Otherwise we may as well get rid of properties. So this "special feature" is enough reasonable to me.
 ...
"special features" are usually not reasonable.
Feb 04 2013
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:
 This is not correct."m.s & m.s" is always parsed as binary bitwise AND
expression.
 So there is no address expression.
Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operator On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:
 Address expression is _only_one_ built-in feature to make a callable object
 from function symbol. So
 this "special feature" is enough reasonable to me.
Yes "only one". And then later we'll add another "one", and another one, until we end up with the mess that is C++. This feature does not pull its own weight regardless of how easy it is to implement in the compiler. From a user's perspective, it is completely pointless and unintuitive.
Feb 04 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
04-Feb-2013 19:15, Andrej Mitrovic пишет:
 On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:
 This is not correct."m.s & m.s" is always parsed as binary bitwise AND
expression.
 So there is no address expression.
Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operator
Unary & is not overloadable, precisely due to confusing mess it can create (see C++). -- Dmitry Olshansky
Feb 04 2013
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/4/13, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:
 Unary & is not overloadable, precisely due to confusing mess it can
 create (see C++).
Right I overlooked that, but this new rule will introduce a confusing mess as well. Anyway my vote is firmly against it. If anything we should have a vote on it before someone starts hacking on master without us knowing about it (UDA's, anyone?).
Feb 04 2013
prev sibling parent kenji hara <k.hara.pg gmail.com> writes:
2013/2/5 Andrej Mitrovic <andrej.mitrovich gmail.com>

 On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:
 This is not correct."m.s & m.s" is always parsed as binary bitwise AND
expression.
 So there is no address expression.
Fantastic, more special casing. I don't think you guys realize what a mess you would introduce. Basically: s & s; // fine, they're binary operators &s; // oops, doesn't work even if property returns a type with a unary operator
Address operator cannot be overloaded. http://dlang.org/operatoroverloading On 2/4/13, kenji hara <k.hara.pg gmail.com> wrote:
 Address expression is _only_one_ built-in feature to make a callable
object
 from function symbol. So
 this "special feature" is enough reasonable to me.
Yes "only one". And then later we'll add another "one", and another one, until we end up with the mess that is C++. This feature does not pull its own weight regardless of how easy it is to implement in the compiler. From a user's perspective, it is completely pointless and unintuitive.
We can think like this. "To resolve ambiguity, we should introduce new operator: &( exp )". Or, we can think like that we introduce one new restriction. "If you want to get function address, you MUST not add redundant parenthesis." &func; // OK &(func); // Bad. It should be written in the article "Migration for Property Enforcement". Kenji Hara
Feb 04 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 2/4/2013 6:05 AM, Andrei Alexandrescu wrote:
 Couldn't AddressOf use "&(" + exp + ")"?

 I thought more about this. The problem remains even without  property, due to
 optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in invocation require some
 disambiguation. I think the sensible disambiguation is to have &fun take the
 address of fun and the other two take the address of fun's result.
The only time it is valid to take the address of a function's return value is if the function returns a ref. But I also would think that it's a suspicious practice to take the address of a ref. We've disallowed it in other circumstances, why allow it here? If a function intends for someone to take the address of the return ref, shouldn't the function return a pointer instead? If taking the address of a ref is disallowed, then the above problem goes away. &fun, in all its variants, takes the address of the function.
Feb 04 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 04 Feb 2013 18:18:16 -0500, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 2/4/2013 6:05 AM, Andrei Alexandrescu wrote:
 Couldn't AddressOf use "&(" + exp + ")"?

 I thought more about this. The problem remains even without  property,  
 due to
 optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in invocation  
 require some
 disambiguation. I think the sensible disambiguation is to have &fun  
 take the
 address of fun and the other two take the address of fun's result.
The only time it is valid to take the address of a function's return value is if the function returns a ref. But I also would think that it's a suspicious practice to take the address of a ref. We've disallowed it in other circumstances, why allow it here? If a function intends for someone to take the address of the return ref, shouldn't the function return a pointer instead?
I'd agree with you if we could have ref variables. In some cases, taking the address is the ONLY option. -Steve
Feb 05 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 11:44 AM, Steven Schveighoffer wrote:
 On Mon, 04 Feb 2013 18:18:16 -0500, Walter Bright
 <newshound2 digitalmars.com> wrote:

 On 2/4/2013 6:05 AM, Andrei Alexandrescu wrote:
 Couldn't AddressOf use "&(" + exp + ")"?

 I thought more about this. The problem remains even without
  property, due to
 optional parens in function invocation. Consider:

 ref int fun() { ... }
 auto p1 = &fun;
 auto p2 = &(fun);
 auto p3 = &(fun());

 What are the types of the three? The optional parens in invocation
 require some
 disambiguation. I think the sensible disambiguation is to have &fun
 take the
 address of fun and the other two take the address of fun's result.
The only time it is valid to take the address of a function's return value is if the function returns a ref. But I also would think that it's a suspicious practice to take the address of a ref. We've disallowed it in other circumstances, why allow it here? If a function intends for someone to take the address of the return ref, shouldn't the function return a pointer instead?
I'd agree with you if we could have ref variables. In some cases, taking the address is the ONLY option.
Walter and I reviewed the discussion and had a long talk. We are very seriously considering banning the use of & against a ref result from a function (and actually ref parameters and even struct members in safe code). One would still be able to take the address of a field in a class because that's assumed to live on the GC heap. To get the address of an object in system code without resorting to operator& at all, we're considering adding a stdlib function implemented like this (there are several other ways, this is just for illustration): system T* addressOf(T)(ref T obj) { static T* id(T* p) { return p; } auto idr = cast(T* function(ref T)) id; return idr(obj); } I have a DIP in the making that makes "ref" entirely sealed, i.e. it makes it impossible to have a dangling ref in safe code. If that DIP gets approved, then DIP23 gets considerably simplified because operator& won't be applicable to the result of a function anymore. Andrei
Feb 05 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 One would still be able to take the address of a field in a 
 class because that's assumed to live on the GC heap.
Maybe some people want to allocate many small class instances on the stack. Bye, bearephile
Feb 05 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter and I reviewed the discussion and had a long talk. We are very  
 seriously considering banning the use of & against a ref result from a  
 function (and actually ref parameters and even struct members in  safe  
 code). One would still be able to take the address of a field in a class  
 because that's assumed to live on the GC heap.
What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance. I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?
 To get the address of an object in  system code without resorting to  
 operator& at all, we're considering adding a stdlib function implemented  
 like this (there are several other ways, this is just for illustration):

  system T* addressOf(T)(ref T obj)
 {
      static T* id(T* p) { return p; }
      auto idr = cast(T* function(ref T)) id;
      return idr(obj);
 }
I think a cast would be sufficient: cast(int *)(&refparam); // understood that a cast is required To jump through this machinery to turn a reference into a, um... reference, seems like a huge waste of code space and resources. -Steve
Feb 05 2013
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Feb 05, 2013 at 02:05:24PM -0500, Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
Walter and I reviewed the discussion and had a long talk. We are
very seriously considering banning the use of & against a ref
result from a function (and actually ref parameters and even
struct members in  safe code). One would still be able to take the
address of a field in a class because that's assumed to live on
the GC heap.
What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance. I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?
[...] AFAIK, pointers are allowed in safe code as long as no type casts or pointer arithmetic are performed. T -- There is no gravity. The earth sucks.
Feb 05 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 2:11 PM, H. S. Teoh wrote:
 On Tue, Feb 05, 2013 at 02:05:24PM -0500, Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:

 Walter and I reviewed the discussion and had a long talk. We are
 very seriously considering banning the use of&  against a ref
 result from a function (and actually ref parameters and even
 struct members in  safe code). One would still be able to take the
 address of a field in a class because that's assumed to live on
 the GC heap.
What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance. I think the point about safe code is moot, aren't pointers disallowed in safe code anyway?
[...] AFAIK, pointers are allowed in safe code as long as no type casts or pointer arithmetic are performed.
Yah, apparently that's not sufficient. We must make sure pointers don't escape. Andrei
Feb 05 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 2:05 PM, Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter and I reviewed the discussion and had a long talk. We are very
 seriously considering banning the use of & against a ref result from a
 function (and actually ref parameters and even struct members in  safe
 code). One would still be able to take the address of a field in a
 class because that's assumed to live on the GC heap.
What about structs that live on the heap? e.g. a struct element of an array, or a struct member of a class instance.
In that case we'll disallow it conservatively.
 I think the point about  safe code is moot, aren't pointers disallowed
 in safe code anyway?
Yah, time to start enforcing it more seriously. But we want to ban some uses of & in all code.
 To get the address of an object in  system code without resorting to
 operator& at all, we're considering adding a stdlib function
 implemented like this (there are several other ways, this is just for
 illustration):

  system T* addressOf(T)(ref T obj)
 {
 static T* id(T* p) { return p; }
 auto idr = cast(T* function(ref T)) id;
 return idr(obj);
 }
I think a cast would be sufficient: cast(int *)(&refparam); // understood that a cast is required To jump through this machinery to turn a reference into a, um... reference, seems like a huge waste of code space and resources.
The whole point was to avoid using operator &. Andrei
Feb 05 2013
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 05 Feb 2013 15:15:05 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/5/13 2:05 PM, Steven Schveighoffer wrote:
 I think a cast would be sufficient:

 cast(int *)(&refparam); // understood that a cast is required

 To jump through this machinery to turn a reference into a, um...
 reference, seems like a huge waste of code space and resources.
The whole point was to avoid using operator &.
The mechanism to avoid it seems overly extravagant (and prone to low performance). If you want actually avoid using operator &, then make a compiler special function or something. Also, the use of & can still be hidden inside a function. -Steve
Feb 05 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 4:45 PM, Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 15:15:05 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 2/5/13 2:05 PM, Steven Schveighoffer wrote:
 I think a cast would be sufficient:

 cast(int *)(&refparam); // understood that a cast is required

 To jump through this machinery to turn a reference into a, um...
 reference, seems like a huge waste of code space and resources.
The whole point was to avoid using operator &.
The mechanism to avoid it seems overly extravagant (and prone to low performance). If you want actually avoid using operator &, then make a compiler special function or something.
As I said, there are various solutions. I wrote one that's reasonably portable.
 Also, the use of & can still be hidden inside a function.
My point was to not need & such that the function itself can be compiled. Overall I think this is not the focal issue, the consequences are. Andrei
Feb 05 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 09:15 PM, Andrei Alexandrescu wrote:
 ...
 The whole point was to avoid using operator &.
 ...
Well, that is completely unnecessary.
Feb 05 2013
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, February 05, 2013 14:05:24 Steven Schveighoffer wrote:
 I think the point about  safe code is moot, aren't pointers disallowed in
 safe code anyway?
Goodness no. It's pointer arithmetic which is disallowed. Pointers themselves are perfectly safe as long as you just pass them around or dereference them (which would include calling functions on them). For instance, the result of in on an AA is a pointer to the object, and that's safe. - Jonathan M Davis
Feb 05 2013
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 05 Feb 2013 16:43:39 -0500, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Tuesday, February 05, 2013 14:05:24 Steven Schveighoffer wrote:
 I think the point about  safe code is moot, aren't pointers disallowed  
 in
 safe code anyway?
Goodness no. It's pointer arithmetic which is disallowed. Pointers themselves are perfectly safe as long as you just pass them around or dereference them (which would include calling functions on them). For instance, the result of in on an AA is a pointer to the object, and that's safe.
Well, it would seem setting all kinds of extra rules on ref (in addition to the restrictions we have now), when pointers are more useful even in safe code, will simply result in people using pointers more than ref. I'm not sure that's the right message, but I'm afraid that will be what it is. For example, I have to use pointers for my linked list implementation in dcollections, because ref is forbidden to be used as a class or struct member (my nodes are structs because classes are too heavy). Also, ref is not rebindable, whereas a pointer is. -Steve
Feb 05 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, February 05, 2013 16:53:51 Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 16:43:39 -0500, Jonathan M Davis <jmdavisProg gmx.com>
 
 wrote:
 On Tuesday, February 05, 2013 14:05:24 Steven Schveighoffer wrote:
 I think the point about  safe code is moot, aren't pointers disallowed
 in
 safe code anyway?
Goodness no. It's pointer arithmetic which is disallowed. Pointers themselves are perfectly safe as long as you just pass them around or dereference them (which would include calling functions on them). For instance, the result of in on an AA is a pointer to the object, and that's safe.
Well, it would seem setting all kinds of extra rules on ref (in addition to the restrictions we have now), when pointers are more useful even in safe code, will simply result in people using pointers more than ref. I'm not sure that's the right message, but I'm afraid that will be what it is. For example, I have to use pointers for my linked list implementation in dcollections, because ref is forbidden to be used as a class or struct member (my nodes are structs because classes are too heavy). Also, ref is not rebindable, whereas a pointer is.
That may end up happening, but the issues with ref may boil over into some of what happens with pointers - the key issue being escaping references. Using & on a local variable is already considered unsafe, but using ref as a function parameter gets you pretty much exactly the same thing if a local variable is passed to it and ref is returned by the function (I believe that discussions on that are what triggered Andrei's work on the DIP on ref that he brought up). What's really needed is to be able to detect and prevent escaping pointers and references, and there are a lot of difficulties with that. The easy way out tends to mean making a lot of code be system, which could either end up being very limiting or result in a lot more code being system instead of safe. I don't know what exactly Andrei and Walter are cooking up, but SafeD could end up becoming very limited with regards to pointers and refs in order to deal with all of the corner cases. - Jonathan M Davis
Feb 05 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter and I reviewed the discussion and had a long talk. We are very  
 seriously considering banning the use of & against a ref result from a  
 function (and actually ref parameters and even struct members in  safe  
 code). One would still be able to take the address of a field in a class  
 because that's assumed to live on the GC heap.
Back to the problem I stated, how does one do this: ref A foo(); ref A bar(); A *a; if(condition) a = &foo(); else a = &bar(); // use a for a few lines I can see a possible solution but it's not pretty: void processA(ref A a) { // lines that deal with a here } if(condition) processA(foo()); else processA(bar()); But this kind of seems hacky. Why should I have to declare a function just to keep a persistent reference to a return value for the scope of my function? Not only is is awkward, there is a performance hit in that I have to call another function. Note also that this doesn't fix memory issues: struct S { ref S self() {return this;} } ref S bad() { S s; return s.self(); } Which I believe would be valid still with your rules. -Steve
Feb 05 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 2:21 PM, Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter and I reviewed the discussion and had a long talk. We are very
 seriously considering banning the use of & against a ref result from a
 function (and actually ref parameters and even struct members in  safe
 code). One would still be able to take the address of a field in a
 class because that's assumed to live on the GC heap.
Back to the problem I stated, how does one do this: ref A foo(); ref A bar(); A *a; if(condition) a = &foo(); else a = &bar(); // use a for a few lines I can see a possible solution but it's not pretty: void processA(ref A a) { // lines that deal with a here } if(condition) processA(foo()); else processA(bar()); But this kind of seems hacky. Why should I have to declare a function just to keep a persistent reference to a return value for the scope of my function? Not only is is awkward, there is a performance hit in that I have to call another function.
You define the function in situ. We understand some valid code will be disallowed by the change,
 Note also that this doesn't fix memory issues:

 struct S
 {
 ref S self() {return this;}
 }

 ref S bad()
 {
 S s;
 return s.self();
 }

 Which I believe would be valid still with your rules.
Also consider the simpler: ref int id(ref int x) { return x; } ref int id1(ref int x) { return id(x); } ref int id2(ref int x) { return id1(x); } ref int oops(int x) { return id2(x); } DIP24 addresses that and other similar cases at their core. Andrei
Feb 05 2013
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 05 Feb 2013 15:21:14 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Also consider the simpler:

 ref int id(ref int x) { return x; }
 ref int id1(ref int x) { return id(x); }
 ref int id2(ref int x) { return id1(x); }
 ref int oops(int x) { return id2(x); }

 DIP24 addresses that and other similar cases at their core.
I look forward to reading it. -Steve
Feb 05 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:
  ...
  Also consider the simpler:

 ref int id(ref int x) { return x; }
 ref int id1(ref int x) { return id(x); }
 ref int id2(ref int x) { return id1(x); }
 ref int oops(int x) { return id2(x); }

 DIP24 addresses that and other similar cases at their core.
 ...
Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
Feb 05 2013
parent reply <address_is invalid.invalid> writes:
Timon Gehr <timon.gehr gmx.ch> wrote:
 On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:
  ...
  Also consider the simpler:
 
 ref int id(ref int x) { return x; }
 ref int id1(ref int x) { return id(x); }
 ref int id2(ref int x) { return id1(x); }
 ref int oops(int x) { return id2(x); }
 
 DIP24 addresses that and other similar cases at their core.
 ...
Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
What is the noticeable tendency of my latest design proposals? Andrei
Feb 05 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdan.org> writes:
<address_is invalid.invalid> wrote:
 Timon Gehr <timon.gehr gmx.ch> wrote:
 On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:
  ...
  Also consider the simpler:
 
 ref int id(ref int x) { return x; }
 ref int id1(ref int x) { return id(x); }
 ref int id2(ref int x) { return id1(x); }
 ref int oops(int x) { return id2(x); }
 
 DIP24 addresses that and other similar cases at their core.
 ...
Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
What is the noticeable tendency of my latest design proposals? Andrei
That was me on the misconfigured phone. Andrei
Feb 05 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 11:58 PM, Andrei Alexandrescu wrote:
 <address_is invalid.invalid> wrote:
 Timon Gehr <timon.gehr gmx.ch> wrote:
 On 02/05/2013 09:21 PM, Andrei Alexandrescu wrote:
   ...
   Also consider the simpler:

 ref int id(ref int x) { return x; }
 ref int id1(ref int x) { return id(x); }
 ref int id2(ref int x) { return id1(x); }
 ref int oops(int x) { return id2(x); }

 DIP24 addresses that and other similar cases at their core.
 ...
Given a noticeable tendency of your latest design proposals, I guess it does so by disallowing the 'ref' keyword in the lexer stage. :o)
What is the noticeable tendency of my latest design proposals? Andrei
...
They were mostly about banning stuff.
Feb 05 2013
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter and I reviewed the discussion and had a long talk. We are very  
 seriously considering banning the use of & against a ref result from a  
 function (and actually ref parameters and even struct members in  safe  
 code). One would still be able to take the address of a field in a class  
 because that's assumed to live on the GC heap.
Thinking about this some more, would this be allowed: trusted T *getAddr(T)(ref T obj) { return &obj; } // allowed? You said only safe code would disallow address of ref parameters -Steve
Feb 05 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 2:25 PM, Steven Schveighoffer wrote:
 On Tue, 05 Feb 2013 13:33:35 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 Walter and I reviewed the discussion and had a long talk. We are very
 seriously considering banning the use of & against a ref result from a
 function (and actually ref parameters and even struct members in  safe
 code). One would still be able to take the address of a field in a
 class because that's assumed to live on the GC heap.
Thinking about this some more, would this be allowed: trusted T *getAddr(T)(ref T obj) { return &obj; } // allowed? You said only safe code would disallow address of ref parameters
We hope to be able to disallow it. Andrei
Feb 05 2013
prev sibling next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu 
wrote:
 I have a DIP in the making that makes "ref" entirely sealed, 
 i.e. it makes it impossible to have a dangling ref in safe 
 code. If that DIP gets approved, then DIP23 gets considerably 
 simplified because operator& won't be applicable to the result 
 of a function anymore.


 Andrei
I hope it at least considers my proposal with regard to 'out' return values. 'out' implies ref and guarantees that the result is as good as global: out int foo(ref int a) { return a; } // Error, 'out' return may not return ref parameter out int goo(ref int a) { return new int; } // Fine My impression was that this would solve 98% of problems, the other 2% requiring scope parameters, which also imply ref: ref int haa(ref int a, scope int b) { return b; } // Error, may not return scope parameter ref int gaa(ref int a, scope int b) { return a; } // Fine
Feb 05 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 2:44 PM, Zach the Mystic wrote:
 On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:
 I have a DIP in the making that makes "ref" entirely sealed, i.e. it
 makes it impossible to have a dangling ref in safe code. If that DIP
 gets approved, then DIP23 gets considerably simplified because
 operator& won't be applicable to the result of a function anymore.


 Andrei
I hope it at least considers my proposal with regard to 'out' return values. 'out' implies ref and guarantees that the result is as good as global: out int foo(ref int a) { return a; } // Error, 'out' return may not return ref parameter out int goo(ref int a) { return new int; } // Fine My impression was that this would solve 98% of problems, the other 2% requiring scope parameters, which also imply ref: ref int haa(ref int a, scope int b) { return b; } // Error, may not return scope parameter ref int gaa(ref int a, scope int b) { return a; } // Fine
I'm sorry, I didn't know of that proposal. Generally we're aiming for economy of means i.e. we want to clarify semantics of existing syntax instead of adding new syntax and semantics. Andrei
Feb 05 2013
parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Tuesday, 5 February 2013 at 20:24:16 UTC, Andrei Alexandrescu 
wrote:
 I hope it at least considers my proposal with regard to 'out' 
 return
 values. 'out' implies ref and guarantees that the result is as 
 good as
 global:

 out int foo(ref int a) { return a; } // Error, 'out' return 
 may not
 return ref parameter
 out int goo(ref int a) { return new int; } // Fine

 My impression was that this would solve 98% of problems, the 
 other 2%
 requiring scope parameters, which also imply ref:

 ref int haa(ref int a, scope int b) { return b; } // Error, 
 may not
 return scope parameter
 ref int gaa(ref int a, scope int b) { return a; } // Fine
I'm sorry, I didn't know of that proposal. Generally we're aiming for economy of means i.e. we want to clarify semantics of existing syntax instead of adding new syntax and semantics. Andrei
It's not a new syntax, just new semantics. Also, the reason for adding these semantics to the function signature was so that the compiler would never have to leave the function in order to compile it. It's a natural complement to ref returns' scope being the most local of the ref parameters, which you suggested in your proposal. It keeps that too.
Feb 05 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 4:35 PM, Zach the Mystic wrote:
 On Tuesday, 5 February 2013 at 20:24:16 UTC, Andrei Alexandrescu wrote:
 I hope it at least considers my proposal with regard to 'out' return
 values. 'out' implies ref and guarantees that the result is as good as
 global:

 out int foo(ref int a) { return a; } // Error, 'out' return may not
 return ref parameter
 out int goo(ref int a) { return new int; } // Fine

 My impression was that this would solve 98% of problems, the other 2%
 requiring scope parameters, which also imply ref:

 ref int haa(ref int a, scope int b) { return b; } // Error, may not
 return scope parameter
 ref int gaa(ref int a, scope int b) { return a; } // Fine
I'm sorry, I didn't know of that proposal. Generally we're aiming for economy of means i.e. we want to clarify semantics of existing syntax instead of adding new syntax and semantics. Andrei
It's not a new syntax, just new semantics. Also, the reason for adding these semantics to the function signature was so that the compiler would never have to leave the function in order to compile it. It's a natural complement to ref returns' scope being the most local of the ref parameters, which you suggested in your proposal. It keeps that too.
Just to make sure: this is about http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org. Language design is a subjective topic. With time I have learned it's best to not comment very much about it. I have created dozens, maybe hundreds of tidbits of language design and invariably I believe they had obvious merits and negligible drawbacks. The confidence in the quality of my own language designs has decayed exponentially over the years. I'm telling this to put in perspective my following comment. I think it's awesome that work like yours is discussed and refined in this group. At the same time my opinion is that the design is not appropriate for us. It changes semantics of existing code and fosters a cross-talk between subcomponents that has not been time tested. It is complicated in implementation for a benefit that's not properly motivated. At the top level it solves the wrong problem. As stated: "The challenge is to do better, both in terms of functionality and in terms of syntax, than his proposal: ..." The actual challenge is to make properties work with maximum backward compatibility, minimal surprise, best integration with the rest of the language, and maximum of benefits. Andrei
Feb 05 2013
next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Tuesday, 5 February 2013 at 21:59:53 UTC, Andrei Alexandrescu 
wrote:
 Just to make sure: this is about 
 http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org.

 Language design is a subjective topic. With time I have learned 
 it's best to not comment very much about it. I have created 
 dozens, maybe hundreds of tidbits of language design and 
 invariably I believe they had obvious merits and negligible 
 drawbacks. The confidence in the quality of my own language 
 designs has decayed exponentially over the years.

 I'm telling this to put in perspective my following comment. I 
 think it's awesome that work like yours is discussed and 
 refined in this group. At the same time my opinion is that the 
 design is not appropriate for us. It changes semantics of 
 existing code and fosters a cross-talk between subcomponents 
 that has not been time tested. It is complicated in 
 implementation for a benefit that's not properly motivated. At 
 the top level it solves the wrong problem. As stated: "The 
 challenge is to do better, both in terms of functionality and 
 in terms of syntax, than his proposal: ..." The actual 
 challenge is to make properties work with maximum backward 
 compatibility, minimal surprise, best integration with the rest 
 of the language, and maximum of benefits.


 Andrei
Okay. But I just want to be clear that you are saying what I am reading, which is that I came to this language too late to really make a difference in it.
Feb 05 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 7:15 PM, Zach the Mystic wrote:
 Okay. But I just want to be clear that you are saying what I am reading,
 which is that I came to this language too late to really make a
 difference in it.
Depends on how you look at it. Among languages of any note, I suspect D is one of the more open to language design discussions. Also, there is plenty of fun to be had with library enhancements, proving properties of language constructs, tightening the screws all around, writing articles, tutorials, and documentation, and more. We're just at the beginning of a vast expansion. If by making a difference you mean strictly adding a language feature to D, you're not late even for that but you have to come up with something pretty darn interesting. Your proposal is not that; it does hold water, it is likely implementable, and it is possibly useful (though I have some doubts about the latter). It's just not compelling enough to make the A list, and we can't afford anything but the A+ list. Note that most people tend to vastly overestimate their few first language designs, and that there are much more people who think are good at language design than those actually are. (Note I'm only passing opinion on what I saw; You may as well be an awesome language designer, but the spark is not visible in this particular proposal.) Though I've had an idea or two that stuck, I confess without any false modesty that I don't consider myself to be a noted language designer. Andrei
Feb 05 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, February 05, 2013 21:22:34 Andrei Alexandrescu wrote:
 Note that most people tend to vastly overestimate their few first
 language designs, and that there are much more people who think are good
 at language design than those actually are. (Note I'm only passing
 opinion on what I saw; You may as well be an awesome language designer,
 but the spark is not visible in this particular proposal.) Though I've
 had an idea or two that stuck, I confess without any false modesty that
 I don't consider myself to be a noted language designer.
Another thing to consider is that it's fairly common for people to come up with ideas that seem like very good ideas and seem very solid but which ultimately end up falling apart due to corner cases. And we're already suffering from features which are partially implemented and not necessarily fully thought through, even if they're solid in their basics. As far as changing D goes, we're far enough along in the process that anything which would break backwards compatibility needs a really compelling case for it happen. We're trying to stabilize the language, which _does_ require breaking code in some cases, but we'd like to minimize that. Backwards compatible feature requests are more likely to make it in, but even then, they need very compelling use cases and are likely to be held back by all of the work that _needs_ to be done (new features may be nice, but they're unlikely to be necessary at this point). We're past the point where we're freely mucking with the language to try out new ideas but instead are trying to polish what we have. But as Andrei says, there's tons of room for stuff to be done on the library front and plenty of work to do helping out with stuff like documentation and articles. So, there's tons for people to do to help out, and there's certainly plenty of innovation that could be done with regards to how stuff is handled in new stuff in the standard library. It's just the lanugage itself where we're limiting what innovation we put into it at this point. - Jonathan M Davis
Feb 05 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Wednesday, 6 February 2013 at 02:36:13 UTC, Jonathan M Davis 
wrote:
 On Tuesday, February 05, 2013 21:22:34 Andrei Alexandrescu 
 wrote:
 Note that most people tend to vastly overestimate their few 
 first
 language designs, and that there are much more people who 
 think are good
 at language design than those actually are. (Note I'm only 
 passing
 opinion on what I saw; You may as well be an awesome language 
 designer,
 but the spark is not visible in this particular proposal.) 
 Though I've
 had an idea or two that stuck, I confess without any false 
 modesty that
 I don't consider myself to be a noted language designer.
Another thing to consider is that it's fairly common for people to come up with ideas that seem like very good ideas and seem very solid but which ultimately end up falling apart due to corner cases. And we're already suffering from features which are partially implemented and not necessarily fully thought through, even if they're solid in their basics. As far as changing D goes, we're far enough along in the process that anything which would break backwards compatibility needs a really compelling case for it happen. We're trying to stabilize the language, which _does_ require breaking code in some cases, but we'd like to minimize that. Backwards compatible feature requests are more likely to make it in, but even then, they need very compelling use cases and are likely to be held back by all of the work that _needs_ to be done (new features may be nice, but they're unlikely to be necessary at this point). We're past the point where we're freely mucking with the language to try out new ideas but instead are trying to polish what we have. But as Andrei says, there's tons of room for stuff to be done on the library front and plenty of work to do helping out with stuff like documentation and articles. So, there's tons for people to do to help out, and there's certainly plenty of innovation that could be done with regards to how stuff is handled in new stuff in the standard library. It's just the lanugage itself where we're limiting what innovation we put into it at this point. - Jonathan M Davis
Well, Jonathan M Davis, I had posted a second response to Andrei's first comment before reading either his second one or yours. But I think I pretty much explained my position, for better or worse. It's not so much not having the feature included so much as wanting to know why because despite Andrei's clear intelligence and good intentions, I felt pretty strongly that I had put onto the table something very good.
Feb 05 2013
prev sibling parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Tuesday, 5 February 2013 at 21:59:53 UTC, Andrei Alexandrescu 
wrote:
 Just to make sure: this is about 
 http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org.

 Language design is a subjective topic. With time I have learned 
 it's best to not comment very much about it. I have created 
 dozens, maybe hundreds of tidbits of language design and 
 invariably I believe they had obvious merits and negligible 
 drawbacks. The confidence in the quality of my own language 
 designs has decayed exponentially over the years.

 I'm telling this to put in perspective my following comment. I 
 think it's awesome that work like yours is discussed and 
 refined in this group. At the same time my opinion is that the 
 design is not appropriate for us. It changes semantics of 
 existing code
My proposal changes exactly one existing semantic, which is that a nested struct will find symbols it doesn't find in itself in the parent before looking at module and import levels. I'm pretty sure it's a bad practice to shadow names in nested structs, and I predicted no code breakage at all in the vast majority of projects.
 and fosters a cross-talk between subcomponents that has not 
 been time tested. It is complicated in implementation for a 
 benefit that's not properly motivated. At the top level it 
 solves the wrong problem. As stated: "The challenge is to do 
 better, both in terms of functionality and in terms of syntax, 
 than his proposal: ..." The actual challenge is to make 
 properties work with maximum backward compatibility, minimal 
 surprise, best integration with the rest of the language, and 
 maximum of benefits.

 Andrei
I've thought about this some more. You're right in that my proposal does not meet the first two design goals. But it doesn't harm them either. property can exist side-by-side with my proposal indefinitely. The only demand you must make on programmers is that they convert all overloads of a given local property implementation at once so there's no repeat declaration. As far as best integration with the rest of the language, my proposal requires one new syntax (Highlander) and no new keyword or even the keeping of ' property' itself. As far as maximum of benefits, I think mine wins by far. Not only have properties been granted the full semantic power of the already-designed-and-implemented structs, but the features required to make this possible have their own uses totally apart from making properties easy. Yes, my proposal fosters cross-talk between subcomponents that have not been time tested, but it doesn't prevent people from programming in the way they always have, either, with the one exception mentioned above. So is my proposal properly motivated? Here's what happened. I saw a connection between what everyone is trying to do with properties and what the built-in struct operators already do. I can't figure out why you would want to have two systems when you could just design one really well (design goal 3 above: best integration with the rest of the language). So I figured out what needed to change to be able to use the one system for the two purposes. The new proposal with nested structs is confusing, but I see no problems with it. Underneath, it's just what old-fashioned C programming is about, a bunch of functions which accept a bunch of variables, some of them references. Whether or not my proposal gains any more traction than it already has, I consider myself lucky to have discovered it. It felt like it was just sitting right there for someone, and I was the one to find it. I may feel a little bad that there was so much opposition. So far, the original person who posed the challenge has said nothing at all about it, for example, but still, I'm glad I found it, and I don't even care at this point if anyone else cares.
Feb 05 2013
prev sibling next sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu 
wrote:
 [..]
 Walter and I reviewed the discussion and had a long talk. We 
 are very seriously considering banning the use of & against a 
 ref result from a function (and actually ref parameters and 
 even struct members in  safe code). [..]
Did you consider using Rust's idea of 'Named lifetimes' in order to make ref parameters memory-safe. I haven't given much thought to it, but since Rust's borrowed pointers are effectively isomorphic to D's ref variables, it should work. Here's a Rust borrowed pointer tutorial: http://static.rust-lang.org/doc/tutorial-borrowed-ptr.html
Feb 05 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 3:08 PM, TommiT wrote:
 On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:
 [..]
 Walter and I reviewed the discussion and had a long talk. We are very
 seriously considering banning the use of & against a ref result from a
 function (and actually ref parameters and even struct members in  safe
 code). [..]
Did you consider using Rust's idea of 'Named lifetimes' in order to make ref parameters memory-safe. I haven't given much thought to it, but since Rust's borrowed pointers are effectively isomorphic to D's ref variables, it should work. Here's a Rust borrowed pointer tutorial: http://static.rust-lang.org/doc/tutorial-borrowed-ptr.html
Thanks, I'll give that a read. We're very careful at this point about spending much "complexity budget" (as a friend calls it) on new features. Andrei
Feb 05 2013
prev sibling parent reply "Max Samukha" <maxsamukha gmail.com> writes:
On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu 
wrote:

 Walter and I reviewed the discussion and had a long talk. We 
 are very seriously considering banning the use of & against a 
 ref result from a function
Please, no. ref T foo(); extern(C) void bar(T*); bar(&foo()); // how?
Feb 05 2013
parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-02-05, 23:46, Max Samukha wrote:

 On Tuesday, 5 February 2013 at 18:33:36 UTC, Andrei Alexandrescu wrote:

 Walter and I reviewed the discussion and had a long talk. We are very  
 seriously considering banning the use of & against a ref result from a  
 function
Please, no. ref T foo(); extern(C) void bar(T*); bar(&foo()); // how?
system T* addressOf(T)(ref T obj) { static T* id(T* p) { return p; } auto idr = cast(T* function(ref T)) id; return idr(obj); } bar(addressOf(foo()); // Like this It's right there in his post. -- Simen
Feb 05 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 05:32:39 UTC, Andrei Alexandrescu
wrote:
 On 2/3/13 11:00 PM, David Nadlinger wrote:
 The problem I see is that usually, one can insert grouping 
 pairs of
 parentheses into an expression according to the operator
 precedence/associativity rules at will without changing the 
 result. This
 isn't merely a theoretical exercise, but the way (well, in the 
 form of
 trees) I tend to reason about source code intuitively.
Well this is going to sound bad, but you either use reason or intuition. I don't see how one can reason intuitively.
Yes, that is why, ideally, you want to close the gap as much as possible.
Feb 03 2013
prev sibling next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 4 February 2013 at 05:32:39 UTC, Andrei Alexandrescu 
wrote:
 On 2/3/13 11:00 PM, David Nadlinger wrote:
 The problem I see is that usually, one can insert grouping 
 pairs of
 parentheses into an expression according to the operator
 precedence/associativity rules at will without changing the 
 result. This
 isn't merely a theoretical exercise, but the way (well, in the 
 form of
 trees) I tend to reason about source code intuitively.
Well this is going to sound bad, but you either use reason or intuition. I don't see how one can reason intuitively.
 Now, grouping the expression »&a.b« according to the 
 precedence rules
 yields »&(a.b)« – but in your proposal, they mean completely 
 different
 things.
I agree they mean different things. I'm unclear that's a problem. All your examples stop here, there's no propagation of the issue. To take the address of a property, one writes &obj.prop. To take the address of a property's result, one writes &(obj.prop). And that's that. It all works with typeof. [SNIP] Andrei
It was my understanding that once a function is declared a property, it is meant to emulate a field. In such circumstance, there were talks about plain and simply not allowing taking the address of an property function. 2 questions: 1. Was this proposal rejected, or have we just forgotten about it? 2. What are the actual use cases for taking the address of a property function? Unless I'm mistaken, the "entire mess" of &a.b would be solved if we simply recognized it as "but you aren't allowed to take the address of the function b, so why have a syntax to support it anyways"? In such circumstance, "&a.b" == "&(a.b)" == "the address of the thing obtaining by running a.b"
Feb 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 2:10 AM, monarch_dodra wrote:
 It was my understanding that once a function is declared a property, it
 is meant to emulate a field. In such circumstance, there were talks
 about plain and simply not allowing taking the address of an  property
 function.

 2 questions:

 1. Was this proposal rejected, or have we just forgotten about it?
Well I at least haven't forgotten. Generally in D we don't want to 100% disallow doing something sensible.
 2. What are the actual use cases for taking the address of a property
 function?

 Unless I'm mistaken, the "entire mess" of &a.b would be solved if we
 simply recognized it as "but you aren't allowed to take the address of
 the function b, so why have a syntax to support it anyways"? In such
 circumstance, "&a.b" == "&(a.b)" == "the address of the thing obtaining
 by running a.b"
Yes, if we disallowed address taking things would get a bit simpler. Andrei
Feb 04 2013
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 04 Feb 2013 06:47:26 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/4/13 2:10 AM, monarch_dodra wrote:
 It was my understanding that once a function is declared a property, it
 is meant to emulate a field. In such circumstance, there were talks
 about plain and simply not allowing taking the address of an  property
 function.

 2 questions:

 1. Was this proposal rejected, or have we just forgotten about it?
Well I at least haven't forgotten. Generally in D we don't want to 100% disallow doing something sensible.
 2. What are the actual use cases for taking the address of a property
 function?
Basically any time you have a use case for creating a delegate that returns a field or a property value. Instead of creating a wrapping delegate to call a function, it would make more sense to access the delegate directly. In other words, the use case isn't important, what we are doing here is creating an optimization. If the compiler could do that automatically, I think that would be fine too.
 Unless I'm mistaken, the "entire mess" of &a.b would be solved if we
 simply recognized it as "but you aren't allowed to take the address of
 the function b, so why have a syntax to support it anyways"? In such
 circumstance, "&a.b" == "&(a.b)" == "the address of the thing obtaining
 by running a.b"
Yes, if we disallowed address taking things would get a bit simpler.
Elsewhere you shot down my idea of __traits(getDelegate) generically because we already have this possibility: void foo(int) {} void foo(string) {} void delegate(string) dg = &foo; // select string overload What if we use the same exception for properties? property int foo(); auto x = &foo; // error int delegate() x = &foo; // ok -Steve
Feb 04 2013
next sibling parent "Tove" <tove fransson.se> writes:
On Monday, 4 February 2013 at 16:01:45 UTC, Steven Schveighoffer 
wrote:
  property int foo();

 auto x = &foo; // error
 int delegate() x = &foo; // ok

 -Steve
I was going to submit the same suggestion, but didn't find time to until just now. gets my vote.
Feb 04 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 11:01 AM, Steven Schveighoffer wrote:
  property int foo();

 auto x = &foo; // error
 int delegate() x = &foo; // ok
That's an interesting idea. I'm a bit weary about it though. At least for properties I'm inclined toward starting real tight with address-of disabled and relax the rules later. Andrei
Feb 04 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 04 Feb 2013 17:23:25 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/4/13 11:01 AM, Steven Schveighoffer wrote:
  property int foo();

 auto x = &foo; // error
 int delegate() x = &foo; // ok
That's an interesting idea. I'm a bit weary about it though. At least for properties I'm inclined toward starting real tight with address-of disabled and relax the rules later.
Did you mean wary? In any case, that certainly is a defensible plan. We do have the workaround of declaring an extra delegate (and someone probably can come up with some template magic which does it). If we make it illegal, it gives us the option of coming up with a good solution later if needed. -Steve
Feb 05 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 4 February 2013 at 11:47:25 UTC, Andrei Alexandrescu 
wrote:
 Yes, if we disallowed address taking things would get a bit 
 simpler.
The address taking of ?
Feb 04 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I'm unclear that's a problem.
The problem is you cannot replace a field with a property function without breaking user-code when you take into account operator overloading. Consider: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { S s; } void main() { M m; auto s = m.s & m.s; // ok } Suppose you want to turn 's' into a read-only property, so you write: struct S { S opBinary(string op : "&", S)(S s) { return this; } } struct M { property S s() { return _s; } private S _s; } void main() { M m; auto s = m.s & m.s; // fail } Now the user-code fails. I really don't understand the benefit of semantics based on whether there are parens involved. It's especially odd when we're arguing that functions can be called with or without parens (no semantic difference), yet getting an address depends on any parens involved. Requiring an address of a property function should be rare, therefore we shouldn't have to introduce special syntax rules for such a rare action. I'd argue we should introduce a trait or an .addrOf property.
Feb 04 2013
prev sibling parent kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Andrej Mitrovic <andrej.mitrovich gmail.com>

 On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I'm unclear that's a problem.
The problem is you cannot replace a field with a property function without breaking user-code when you take into account operator overloading. Consider:
As an essential question, how often occurs rewriting fields to property? As far as I thought, such rewriting will cause: 1. compile error by type mismatch (if you use &obj.field), 2. or, success of compilation *without any semantic breaking* (if you don't use &obj.field). I think the result is not so harmful.
 struct S
 {
     S opBinary(string op : "&", S)(S s)
     {
         return this;
     }
 }

 struct M
 {
     S s;
 }

 void main()
 {
     M m;
     auto s = m.s & m.s;  // ok
 }

 Suppose you want to turn 's' into a read-only property, so you write:

 struct S
 {
     S opBinary(string op : "&", S)(S s)
     {
         return this;
     }
 }

 struct M
 {
      property S s() { return _s; }
     private S _s;
 }

 void main()
 {
     M m;
     auto s = m.s & m.s;  // fail
 }

 Now the user-code fails.
This is not correct."m.s & m.s" is always parsed as binary bitwise AND expression. So there is no address expression. Kenji Hara
Feb 04 2013
prev sibling parent "ixid" <nuaccount gmail.com> writes:
 And how often do you think you'll find yourself in the 
 situation of needing to get a delegate from a property anyway? 
 Can't we just make » property getter expressions are always 
 equivalent to their return value« a hard (simple!) rule and add 
 something like __traits(propertyGetter, ...) for the rare cases 
 where you really need to get hold of the underlying function?
As a beginner D user this seems like a far better solution, it's much clearer and doesn't violate one's normal understanding of parentheses (which is exactly as you've outlined). &(a.b) feels very much like a hack.
Feb 05 2013
prev sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>

 On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
 [snip]

 Some more thinking got me to three simple principles that guide the
 proposed property design:


 2. A  property may have EXACTLY ONE or EXACTLY TWO parameters, counting
the implicit this parameter if at all. The ONE-parameter version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a setter. There's no variadics, defaulted parameters, and such. Unfortunately, I can present a counterexample. struct S { static int value; static property int foo() { return value; } static property void foo(int n) { value = n; } } void main() { int n = S.foo; S.foo = 1; } Should they be disallowed, as like module level properties? Kenji Hara
Feb 03 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 03:23 AM, kenji hara wrote:
 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org
 <mailto:SeeWebsiteForEmail erdani.org>>

     On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
     [snip]

     Some more thinking got me to three simple principles that guide the
     proposed property design:


     <http://wiki.dlang.org/DIP23#In_a_nutshell>


  > 2. A  property may have EXACTLY ONE or EXACTLY TWO parameters,
 counting the implicit this parameter if at all. The ONE-parameter
 version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a
 setter. There's no variadics, defaulted parameters, and such.

 Unfortunately, I can present a counterexample.

 struct S {
      static int value;
      static  property int foo() { return value; }
      static  property void foo(int n) { value = n; }

 }
 void main() {
      int n = S.foo;
      S.foo = 1;
 }

 Should they be disallowed, as like module level properties?

 Kenji Hara
Probably. (static essentially means module-level, but in a potentially nested name space.)
Feb 03 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Monday, 4 February 2013 at 02:36:41 UTC, Timon Gehr wrote:
 On 02/04/2013 03:23 AM, kenji hara wrote:
 Unfortunately, I can present a counterexample.

 struct S {
     static int value;
     static  property int foo() { return value; }
     static  property void foo(int n) { value = n; }

 }
 void main() {
     int n = S.foo;
     S.foo = 1;
 }

 Should they be disallowed, as like module level properties?

 Kenji Hara
Probably. (static essentially means module-level, but in a potentially nested name space.)
I disagree. Static properties can be allowed because they're not ambiguous. The problem with module-level: property void foo(int n) {} ...are the two interpretations of foo as either a setter taking an int or a getter property of int type. So, one of those interpretations must be disallowed. But, with static member properties, there aren't multiple interpretations.
Feb 03 2013
next sibling parent Johannes Pfau <nospam example.com> writes:
Am Mon, 04 Feb 2013 04:24:46 +0100
schrieb "TommiT" <tommitissari hotmail.com>:

 On Monday, 4 February 2013 at 02:36:41 UTC, Timon Gehr wrote:
 On 02/04/2013 03:23 AM, kenji hara wrote:
 Unfortunately, I can present a counterexample.

 struct S {
     static int value;
     static  property int foo() { return value; }
     static  property void foo(int n) { value = n; }

 }
 void main() {
     int n = S.foo;
     S.foo = 1;
 }

 Should they be disallowed, as like module level properties?

 Kenji Hara
Probably. (static essentially means module-level, but in a potentially nested name space.)
I disagree. Static properties can be allowed because they're not ambiguous. The problem with module-level: property void foo(int n) {} ...are the two interpretations of foo as either a setter taking an int or a getter property of int type. So, one of those interpretations must be disallowed. But, with static member properties, there aren't multiple interpretations.
"getter property of int type" But a getter shouldn't return void, right? So it's actually not ambiguous?
Feb 03 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 04:24 AM, TommiT wrote:
 On Monday, 4 February 2013 at 02:36:41 UTC, Timon Gehr wrote:
 On 02/04/2013 03:23 AM, kenji hara wrote:
 Unfortunately, I can present a counterexample.

 struct S {
     static int value;
     static  property int foo() { return value; }
     static  property void foo(int n) { value = n; }

 }
 void main() {
     int n = S.foo;
     S.foo = 1;
 }

 Should they be disallowed, as like module level properties?

 Kenji Hara
Probably. (static essentially means module-level, but in a potentially nested name space.)
I disagree.
Well, it is what the proposal says.
 Static properties can be allowed because they're not
 ambiguous. The problem with module-level:
  property void foo(int n) {}
 ...are the two interpretations of foo as either a setter taking an int
 or a getter property of int type. So, one of those interpretations must
 be disallowed. But, with static member properties, there aren't multiple
 interpretations.
You are right.
Feb 04 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/3/13 9:23 PM, kenji hara wrote:
 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org
 <mailto:SeeWebsiteForEmail erdani.org>>

     On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
     [snip]

     Some more thinking got me to three simple principles that guide the
     proposed property design:


     <http://wiki.dlang.org/DIP23#In_a_nutshell>


  > 2. A  property may have EXACTLY ONE or EXACTLY TWO parameters,
 counting the implicit this parameter if at all. The ONE-parameter
 version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a
 setter. There's no variadics, defaulted parameters, and such.

 Unfortunately, I can present a counterexample.

 struct S {
      static int value;
      static  property int foo() { return value; }
      static  property void foo(int n) { value = n; }

 }
 void main() {
      int n = S.foo;
      S.foo = 1;
 }

 Should they be disallowed, as like module level properties?
Yes. No static properties. Andrei
Feb 03 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, February 03, 2013 22:06:27 Andrei Alexandrescu wrote:
 Yes. No static properties.
So, properties such as Duration.max would simply be normal functions called without parens if they have they have to be property functions rather than variables or enums? - Jonathan M Davis
Feb 03 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Feb 2013 22:06:27 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 2/3/13 9:23 PM, kenji hara wrote:
 2013/2/4 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org
 <mailto:SeeWebsiteForEmail erdani.org>>

     On 2/3/13 3:16 AM, Andrei Alexandrescu wrote:
     [snip]

     Some more thinking got me to three simple principles that guide the
     proposed property design:


     <http://wiki.dlang.org/DIP23#In_a_nutshell>


  > 2. A  property may have EXACTLY ONE or EXACTLY TWO parameters,
 counting the implicit this parameter if at all. The ONE-parameter
 version is ALWAYS a getter, and the TWO-parameter version is ALWAYS a
 setter. There's no variadics, defaulted parameters, and such.

 Unfortunately, I can present a counterexample.

 struct S {
      static int value;
      static  property int foo() { return value; }
      static  property void foo(int n) { value = n; }

 }
 void main() {
      int n = S.foo;
      S.foo = 1;
 }

 Should they be disallowed, as like module level properties?
Yes. No static properties.
Hm... can't see the reason why. Static properties play no part in UFCS (which is what makes global properties confusing). I hope it's not because you like your new nutshell rules too much... Then again, properties are for syntax, easy enough to make functions instead. -Steve
Feb 03 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:
 Destroy.
Another thing to consider would be to allow putting property on a variable with the idea that variables marked as such would not be usable in any situation where a property function wouldn't be - such as taking their address or passing them by ref. That would reduce code breakage when switching between public variables and property functions. The alternative would be to make it so that putting property on a variable would lower it to property functions. So, struct S { property int prop; } becomes something like struct S { private int __prop; property int prop() safe inout pure nothrow { return __prop; } property int prop(int value) safe pure nothrow { return __prop = value; } } One of the main ideas behind properties is to make it so that you can make something a variable when you don't the extra boilerplate for setter and getter functions (e.g. because you don't need to check the value it's being set to), but it's still easy to swap it out with an actual getter and setter function later when you actually _do_ need extra stuff in those functions. And if we don't do something to indicate that a variable could be swapped out with a property function later, then you risk code doing stuff like taking its address or passing it by ref, and that code will then break if the variable ever does become a property function. - Jonathan M Davis
Feb 03 2013
parent "TommiT" <tommitissari hotmail.com> writes:
On Monday, 4 February 2013 at 04:45:27 UTC, Jonathan M Davis 
wrote:
 On Sunday, February 03, 2013 03:16:08 Andrei Alexandrescu wrote:
 Destroy.
Another thing to consider would be to allow putting property on a variable with the idea that variables marked as such would not be usable in any situation where a property function wouldn't be - such as taking their address or passing them by ref. [..]
If we consider a variable marked as property as a variable whose access is restricted, then the following should be also illegal uses of it: 1) calling its non-const method 2) mutating its data field If we consider a variable marked as property as lowered to getter and setter properties, then it doesn't have those restrictions. This is what I would advocate.
Feb 03 2013
prev sibling next sibling parent "Daniel Kozak" <kozzi11 gmail.com> writes:
 From DIP:
If prop is a property, &prop or a.prop obey the normal rules...

I think there missing '&' before a.prop:

If prop is a property, &prop or &a.prop obey the normal rules...
Feb 04 2013
prev sibling next sibling parent Chad Joan <chadjoan gmail.com> writes:
On 02/03/2013 03:16 AM, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23

 We got input from DIP21 (which we didn't want to clobber, hence the new
 DIP) and the recent discussion.

 The proposal probably won't be accepted in its current form because it
 breaks some code. We hope to bring it to good shape with everyone's help.

 In brief:

 * Optional parens stay.

 * Just mentioning a function or method without parens does NOT
 automatically take its address. (This is a change from the current
 behavior.)

 * Read properties (using  property) work as expected with the mention
 that they may NOT be called with the parens. Any parens would apply to
 the returned value.

 * Write properties (using  property) may only be used in the assignment
 form (no function-style call allowed).

 It is understood that the current proposal is just a draft and there
 must be quite a few corner cases it doesn't discuss. We also understand
 it's impossible to reconcile all viewpoints and please all tastes. Our
 hope is to get to a point where the rules are self-consistent,
 meaningful, and complete.


 Destroy.

 Andrei
This would be a huge step up from the current properties. Thank you for listening and being rigorous. ------ There are a couple things in the DIP that I might be able to destroy; here's the first: the property rewrite is chosen based on whether it compiles or not. I don't like the rule and its potential ambiguities. When I was attempting a property rewrite patch for DMD, one of the first things I did was match the different contexts a property expression may appear in: - read-only - read-write - write-only In read-only contexts, stuff like "q = prop;" or "auto foo(T)(T x); ... foo(prop);" should only call the getter. In read-write context, the full rewrite is applied. "prop++" expands to "(auto t = prop, t++, prop = t);". This could include things like appearing as the argument to a function's ref parameter, but I've been convinced at one point that it might be wiser to disallow that (unfortunately, I forget /why/). In write-only contexts, only the setter is applied. This is stuff like "prop = q;" or "auto foo(T)(out T x); ... foo(prop);". ------ I would suggest guaranteeing that the property rewrite will evaluate the getter/setter no more than once in an expression. ------ As Jonathan M Davis pointed out, it should be possible to mark fields as property and forbid address-of on such members. ------ I also think that allowing address-of on properties is dubious. I've mentioned that in another response. There is no easy way to make address-of do the same thing for variables and for properties, so to make properties work consistently in the transition between POD to calculated data, it is easiest to just forbid address-of. I think that allowing getters to return lvalues is dangerous in general. It could create ambiguities in the writer's intentions with getter/setter pairs: did they want prop++ to expand to (prop++) or (auto t = prop, t++, t = prop)? I think the latter should always be chosen, and the whole example should never compile if they only provide a getter.
Feb 04 2013
prev sibling next sibling parent reply "Rob T" <alanb ucora.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 Walter and I have had a discussion on how to finalize 
 properties.

 http://wiki.dlang.org/DIP23

 We got input from DIP21 (which we didn't want to clobber, hence 
 the new DIP) and the recent discussion.

 The proposal probably won't be accepted in its current form 
 because it breaks some code. We hope to bring it to good shape 
 with everyone's help.

 In brief:

 * Optional parens stay.

 * Just mentioning a function or method without parens does NOT 
 automatically take its address. (This is a change from the 
 current behavior.)

 * Read properties (using  property) work as expected with the 
 mention that they may NOT be called with the parens. Any parens 
 would apply to the returned value.

 * Write properties (using  property) may only be used in the 
 assignment form (no function-style call allowed).

 It is understood that the current proposal is just a draft and 
 there must be quite a few corner cases it doesn't discuss. We 
 also understand it's impossible to reconcile all viewpoints and 
 please all tastes. Our hope is to get to a point where the 
 rules are self-consistent, meaningful, and complete.


 Destroy.

 Andrei
IMO the concept of emulating a field with a function is proving to be an idea that should be simplified. Just look at the huge amount of wasted effort on these discussions, We have at least 5 threads open, two open DIPS and two superseded DIPS. As it stands, I don't even know why there's such a strong desire to have properties that emulate variables. I read the arguments in favor, and they are all very weak IMO, and probably will result in maintenance issues. We all seem to be getting along just fine without full variable emulation, and what we have now for property seems good enough (although I agree it could be done better with a few simple adjustments). If we must keep property, then my advice is to keep the emulation simple and restricted to the cases where it can work without acrobatics (eg no address taking, no pass by ref or return by ref). What I see being proposed is going too far for very little gain. BTW, I am wondering if the idea of "memberspaces" was considered, and if it was considered, then why was it dropped? I won't argue for them in here, just would like to know what the thinking is because I don't recall any feedback from Walter or Andrei. --rt
Feb 04 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 1:15 PM, Rob T wrote:
 BTW, I am wondering if the idea of "memberspaces" was considered, and if
 it was considered, then why was it dropped?
An idea that departs considerably from the current status in D has a disadvantage compared to an idea that makes things work within the property framework. Andrei
Feb 04 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, February 04, 2013 23:56:50 kenji hara wrote:
 2013/2/4 Andrej Mitrovic <andrej.mitrovich gmail.com>
 
 On 2/4/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I'm unclear that's a problem.
The problem is you cannot replace a field with a property function without breaking user-code when you take into account operator
 overloading. Consider:
As an essential question, how often occurs rewriting fields to property? As far as I thought, such rewriting will cause: 1. compile error by type mismatch (if you use &obj.field), 2. or, success of compilation *without any semantic breaking* (if you don't use &obj.field). I think the result is not so harmful.
There's also the issue a variable being able to be passed by ref, which a property function can't emulate, which is why it would be quite valuable to be able to mark a variable as property - either to indicate that it's illegal to do anything with it that you can't do with a property function or to make it so that it lowers to getter and setter property functions and therefore can't be used with anything which wouldn't work with a property function. But if we could guarantee that swapping out variables and property functions wouldn't break code, then we could get rid of a _lot_ of property functions (since many of them don't do anything other than set and/or return the variable that they're wrapping). Because we currently allow stuff which only works with a variable or a function, we can't just seamlessly between variables and property functions, and it's not going to happen anywhere near as often for fear of breaking code. And many more people will simply create useless wrapper property functions around variables in case they need to add more code to them later (e.g. to validate the argument to the setter). We'd be much better off if anything which wasn't legal for both variables and property functions was made illegal for property functions and added a way to do the same for variables which are supposed to be treated as properties rather than explicitly being intended to be public variables like in a POD type. We could save a lot of boilerplate code if we can simply make it variables and property functions guaranteed to be swappable without breaking code. - Jonathan M Davis
Feb 04 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
Feb 04 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, February 04, 2013 17:28:24 Andrei Alexandrescu wrote:
 On 2/4/13 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it variables
 and property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
Yes. There are things that propery functions need to emulate from normal variables (hence the rewrites with ++ and += and whatnot), and there are of course things that they can't emulate (like taking the address of a variable). But what we also need is a way to mark a variable as a property and then make it so such a variable and property functions have the same capabilities so that you're guaranteed to be able to swap between the two without breaking code. As soon as one of the two has capabilities that the other doesn't have, or there's a major semantic change between them (like taking the address works on one but not the other or the type returned by taking the address differs), then you can't do that. Which is why I would argue that we need to be able to mark variables with property (which either makes it so that you can't do anything with them that you can't do with a property function or makes it so that it lowers to property functions for getting and setting), and we need to disallow taking the address of property functions as well as anything else that you could do with a variable that we can't emulate with a property function. - Jonathan M Davis
Feb 04 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-04 23:52, Jonathan M Davis wrote:

 Which is why I would argue that we need to be able to mark variables with
  property (which either makes it so that you can't do anything with them that
 you can't do with a property function or makes it so that it lowers to
 property functions for getting and setting), and we need to disallow taking
 the address of property functions as well as anything else that you could do
 with a variable that we can't emulate with a property function.
They need to be lowered to methods. Otherwise you cannot switch from a method to a field, since methods are virtual and can be overridden in unknown subclasses. -- /Jacob Carlborg
Feb 05 2013
prev sibling parent reply Chad Joan <chadjoan gmail.com> writes:
On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
 On 2/4/13 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.
Feb 04 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/4/13 10:30 PM, Chad Joan wrote:
 On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
 On 2/4/13 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.
The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties. Andrei
Feb 04 2013
next sibling parent Chad Joan <chadjoan gmail.com> writes:
On 02/04/2013 11:18 PM, Andrei Alexandrescu wrote:
 On 2/4/13 10:30 PM, Chad Joan wrote:
 On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
 On 2/4/13 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.
The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties. Andrei
Why not allow one to change their mind back and forth? That would be far more useful from a design perspective. With what you're proposing, there is no migration path for variables. They are not swappable at all. Once someone takes the address of your "public int foo;" it will no longer be possible to turn it into a property without breaking API. Going even further, suppose we allow property variables and also allow address-of on property functions only (a subset relationship!). Now it is possible to make a "public property int foo;" that can be migrated to a full-fledged property later without some god-awful boilerplate. However, the developer will hesitate to make such a change: converting property variables to property functions is a liability. Once you convert, you can't convert back without breaking API. At that point the hypothetical developer wonders: "why am I using property variables in the first place? I can't migrate them because of the liability, which makes them no more useful than public variables that break encapsulation." At that point the whole concept goes out the window and we're back in Java writing drivel like this: class XYZ { int m_foo; int getFoo() { return m_foo; } void setFoo(int val) { m_foo = val; } ... } I'm arguing the point because I'd much rather write this: class XYZ { property int foo; ... }
Feb 04 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, February 04, 2013 23:18:57 Andrei Alexandrescu wrote:
 On 2/4/13 10:30 PM, Chad Joan wrote:
 On 02/04/2013 05:28 PM, Andrei Alexandrescu wrote:
 On 2/4/13 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables. Andrei
I agree with Jonathan. Please do not make them a subset. Make them as identical as possible. The subset thing makes them no longer "swappable". Allow variables to be marked with property to limit them to operations that property functions can do, and make sure property functions are limited to what property variables can do (ex: no address-of!). With that in hand, they'll be very swappable.
The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties.
One of the main purposes generally given for having properties is so that you can make them public variables when you don't need them to do anything but get and set the member variable, but you can still make it a function later when you need to add other stuff to it (such as checking the value that it's being set to). One of the primary reasons for making a property function act like a variable is precisely so that you can switch between variables and functions when refactoring without breaking code. Also, being able to mark variables as property would save us a lot of boilerplate. Instead, it's incredibly common to do stuff like struct S { property int prop() safe const pure nothrow { return _prop; } property int prop(int value) safe pure { return _prop = value; } private int _prop; } That's a lot of extra code just to buy some encapsulation. If we could do struct S { property int prop; } we could really reduce the amount of boilerplate code surrounding member variables. Even if putting property on a variable simply lowered to the property functions rather than it still be a variable, it would be a big help. But without either that or marking variables with property so that you can't do anything to them that you can't do to a property function, we lose the ability to make a property a variable when the getters and setters are unnecessary, and that means that we're stuck with a lot of extra boilerplate. - Jonathan M Davis
Feb 04 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-05 07:13, Jonathan M Davis wrote:

 One of the main purposes generally given for having properties is so that you
 can make them public variables when you don't need them to do anything but get
 and set the member variable, but you can still make it a function later when
 you need to add other stuff to it (such as checking the value that it's being
 set to). One of the primary reasons for making a property function act like a
 variable is precisely so that you can switch between variables and functions
 when refactoring without breaking code.

 Also, being able to mark variables as  property would save us a lot of
 boilerplate. Instead, it's incredibly common to do stuff like

 struct S
 {
       property int prop()  safe const pure nothrow
      { return _prop; }

       property int prop(int value)  safe pure
      { return _prop =  value; }

      private int _prop;
 }

 That's a lot of extra code just to buy some encapsulation. If we could do

 struct S
 {
       property int prop;
 }

 we could really reduce the amount of boilerplate code surrounding member
 variables. Even if putting  property on a variable simply lowered to the
 property functions rather than it still be a variable, it would be a big help.
 But without either that or marking variables with  property so that you can't
 do anything to them that you can't do to a property function, we lose the
 ability to make a property a variable when the getters and setters are
 unnecessary, and that means that we're stuck with a lot of extra boilerplate.
I fully agree. But they do need to be lowered to methods, see: http://forum.dlang.org/thread/kel6c8$1h5d$1 digitalmars.com?page=17#post-keqfol:242un9:241:40digitalmars.com -- /Jacob Carlborg
Feb 05 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 07:13, Jonathan M Davis wrote:

 One of the main purposes generally given for having properties is so that you
 can make them public variables when you don't need them to do anything but get
 and set the member variable, but you can still make it a function later when
 you need to add other stuff to it (such as checking the value that it's being
 set to). One of the primary reasons for making a property function act like a
 variable is precisely so that you can switch between variables and functions
 when refactoring without breaking code.

 Also, being able to mark variables as  property would save us a lot of
 boilerplate. Instead, it's incredibly common to do stuff like

 struct S
 {
       property int prop()  safe const pure nothrow
      { return _prop; }

       property int prop(int value)  safe pure
      { return _prop =  value; }

      private int _prop;
 }

 That's a lot of extra code just to buy some encapsulation. If we could do

 struct S
 {
       property int prop;
 }

 we could really reduce the amount of boilerplate code surrounding member
 variables. Even if putting  property on a variable simply lowered to the
 property functions rather than it still be a variable, it would be a big help.
 But without either that or marking variables with  property so that you can't
 do anything to them that you can't do to a property function, we lose the
 ability to make a property a variable when the getters and setters are
 unnecessary, and that means that we're stuck with a lot of extra boilerplate.
BTW, if it does get lowered to methods, do we want to be able to access the instance variable directly? I think it's good to be able to bypass the setter/getter sometimes internally. Alternatively there could be a __traits to access the instance variable. -- /Jacob Carlborg
Feb 05 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, February 05, 2013 09:34:06 Jacob Carlborg wrote:
 BTW, if it does get lowered to methods, do we want to be able to access
 the instance variable directly?
No, because the variable would presumably end up with a compiler-chosen name which would presumably be implementation-dependent. All that the programmer has defined is the name of the property, not the name of the underlying variable. And for the most part, it wouldn't matter. For structs, inlining would fix the problem, and for classes, if you really want to be able to access the member variable directly for efficiency, you can always declare the property functions explicitly. - Jonathan M Davis
Feb 05 2013
prev sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 02/05/2013 12:34 PM, Jacob Carlborg wrote:
 On 2013-02-05 07:13, Jonathan M Davis wrote:

 One of the main purposes generally given for having properties is so
 that you
 can make them public variables when you don't need them to do anything
 but get
 and set the member variable, but you can still make it a function
 later when
 you need to add other stuff to it (such as checking the value that
 it's being
 set to). One of the primary reasons for making a property function act
 like a
 variable is precisely so that you can switch between variables and
 functions
 when refactoring without breaking code.

 Also, being able to mark variables as  property would save us a lot of
 boilerplate. Instead, it's incredibly common to do stuff like

 struct S
 {
       property int prop()  safe const pure nothrow
      { return _prop; }

       property int prop(int value)  safe pure
      { return _prop =  value; }

      private int _prop;
 }

 That's a lot of extra code just to buy some encapsulation. If we could do

 struct S
 {
       property int prop;
 }

 we could really reduce the amount of boilerplate code surrounding member
 variables. Even if putting  property on a variable simply lowered to the
 property functions rather than it still be a variable, it would be a
 big help.
 But without either that or marking variables with  property so that
 you can't
 do anything to them that you can't do to a property function, we lose the
 ability to make a property a variable when the getters and setters are
 unnecessary, and that means that we're stuck with a lot of extra
 boilerplate.
BTW, if it does get lowered to methods, do we want to be able to access the instance variable directly? I think it's good to be able to bypass the setter/getter sometimes internally. Alternatively there could be a __traits to access the instance variable.
I like the general idea. But to access variable one can still use tupleof, so there should be a guarantee that the hidden field layout is the same as if it was declared as variable.
Feb 05 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-05 10:10, Dmitry Olshansky wrote:

 I like the general idea. But to access variable one can still use
 tupleof, so there should be a guarantee that the hidden field layout is
 the same as if it was declared as variable.
As long as accessing it via tupleof works it would be fine. A serializer would be quite crippled otherwise. -- /Jacob Carlborg
Feb 05 2013
prev sibling next sibling parent Chad Joan <chadjoan gmail.com> writes:
On 02/04/2013 11:18 PM, Andrei Alexandrescu wrote:
 On 2/4/13 10:30 PM, Chad Joan wrote:
 I agree with Jonathan.

 Please do not make them a subset. Make them as identical as possible.
 The subset thing makes them no longer "swappable". Allow variables to be
 marked with  property to limit them to operations that  property
 functions can do, and make sure  property functions are limited to what
  property variables can do (ex: no address-of!). With that in hand,
 they'll be very swappable.
The purpose is to replace members with properties, not to change one's mind back and forth. There will be no marking of variables with property as that can be easily achieved by actually making them properties. Andrei
Related: Is there some reason why we /need/ to be able to take the address of properties? Wouldn't something like 'someFunc(PropAccessor!"prop"(foo))' work in cases where we need a generic way to defer reads and writes? For clarity: auto PropAccessor(string propertyStr, T)( T tinstance ) { struct Accessor(string propertyStr, U) { private U tinstance; auto get() { mixin("return tinstance."~propertyStr~";"); } // I had to put system here to shut up a compiler error. Bug? system void set(V)(V val) { mixin("tinstance."~propertyStr~" = val;"); } } Accessor!(propertyStr, T) acc; acc.tinstance = tinstance; return acc; } auto PtrAccessor(T)( T* payload ) { struct Accessor(U) { private U* payload; U get() { return *payload; } U set(U val) { return *payload = val; } } Accessor!(T) acc; acc.payload = payload; return acc; } template isAccessor(Acc) { Acc a; static if ( __traits(compiles, { auto x = a.get(); } ) && __traits(compiles, a.set(a.get())) ) const bool isAccessor = true; else const bool isAccessor = false; } // Function that accepts the be-all-end-all of reference types. auto someFunc(Acc)(Acc qux) if ( isAccessor!(Acc) ) { auto x = qux.get(); x |= 0xF00D; qux.set(x); return qux.get(); } struct MyStruct { private int m_q; property int q() { return m_q; } property void q(int v) { m_q = v; } } unittest { MyStruct s; s.q = 0; int abc = 0; assert(someFunc(PtrAccessor(&abc)) == 0xF00D); assert(someFunc(PropAccessor!"q"(s)) == 0xF00D); } void main() { }
Feb 04 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-05 05:18, Andrei Alexandrescu wrote:

 The purpose is to replace members with properties, not to change one's
 mind back and forth. There will be no marking of variables with
  property as that can be easily achieved by actually making them
 properties.
Why not? That will just require needless boilerplate code, wrappers just forwarding to instance variables. I have wanted to have this since the introduction of the property keyword. -- /Jacob Carlborg
Feb 05 2013
prev sibling next sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Sunday, 3 February 2013 at 08:16:08 UTC, Andrei Alexandrescu 
wrote:
 Walter and I have had a discussion on how to finalize 
 properties.

 http://wiki.dlang.org/DIP23

 We got input from DIP21 (which we didn't want to clobber, hence 
 the new DIP) and the recent discussion.

 The proposal probably won't be accepted in its current form 
 because it breaks some code. We hope to bring it to good shape 
 with everyone's help.

 In brief:

 * Optional parens stay.

 * Just mentioning a function or method without parens does NOT 
 automatically take its address. (This is a change from the 
 current behavior.)

 * Read properties (using  property) work as expected with the 
 mention that they may NOT be called with the parens. Any parens 
 would apply to the returned value.

 * Write properties (using  property) may only be used in the 
 assignment form (no function-style call allowed).

 It is understood that the current proposal is just a draft and 
 there must be quite a few corner cases it doesn't discuss. We 
 also understand it's impossible to reconcile all viewpoints and 
 please all tastes. Our hope is to get to a point where the 
 rules are self-consistent, meaningful, and complete.


 Destroy.

 Andrei
http://forum.dlang.org/thread/ririagrqecshjljcdubd forum.dlang.org Smash.
Feb 04 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM, 
Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
This is the primary real-world proble to solve. If tackle it right we'd secure a sizable flow of Java converts simply because of this feature alone ;) More seriously I believe it's worth noting that properties can't emulate (in principle) exactly one aspect of variable - taking address as a pointer. Honestly I can't see a way to overcome it without introducing a user-defined way to impose this restriction on a field of a struct/class. Then keeping in mind __traits I have the following clause to add to the current proposal: Inside of aggregate a field marked with property indicate is semantically equivalent to compiler wrapping it with trivial getter and setter. Example: struct Foo{ property T x; } treated semantically as if: T __x; // hidden by compiler //templated to have deduced safe, pure, nothrow property T x()()inout{ return x; } property void x()(T val){ x = val; } --- Dmitry Olshansky
Feb 05 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/13 3:39 AM, Dmitry Olshansky wrote:
 On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM,
 Jonathan M Davis wrote:
  >> We could save a lot of boilerplate code if we can simply make it
  >> variables and
  >> property functions guaranteed to be swappable without breaking code.
  >
  > I think this is quite powerful. The way we can do this is by making
  > properties emulate a subset of actual variables.
  >

 This is the primary real-world proble to solve.
The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data. Andrei
Feb 05 2013
next sibling parent Chad Joan <chadjoan gmail.com> writes:
On 02/05/2013 08:31 AM, Andrei Alexandrescu wrote:
 On 2/5/13 3:39 AM, Dmitry Olshansky wrote:
 On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM,
 Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
This is the primary real-world proble to solve.
The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data. Andrei
Rare? What? No. Where is your data? My anecdotal experience is contradictory. I tend to end up with A LOT of things that I'd like to make into public variables but don't due to the risk of breaking encapsulation. The boilerplate can really suck. I would argue that being able to do the /right/ thing in a /convenient/ way is a very important feature. I also do not see how this would lead to more features. If anything, everyone seems to draw the line at address-of: it's a potential feature that we /don't/ want because it's too complicated and introduces harmful semantics. There are a finite amount of features that are needed to make D's property implementation very complete. Throw them all on the table and D will have /the best/ property implementation. If, instead, you are chintzy and give people only some of them, then you will get constant property discussions on the news group and it will /seem/ like you're having to implement an endless stream of features.
Feb 05 2013
prev sibling next sibling parent reply Chad Joan <chadjoan gmail.com> writes:
On 02/05/2013 08:31 AM, Andrei Alexandrescu wrote:
 On 2/5/13 3:39 AM, Dmitry Olshansky wrote:
 On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM,
 Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply make it
 variables and
 property functions guaranteed to be swappable without breaking code.
I think this is quite powerful. The way we can do this is by making properties emulate a subset of actual variables.
This is the primary real-world proble to solve.
The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data. Andrei
Hmmm. This statement that unchecked public members are rare makes me wonder if there is a fundamental difference of background here. Things I always get this feeling that Walter and Andrei never truly understood those programmers are very comfortable with properties and know how to use them. Properties are an alien concept in C programming, and probably C++ as well. As a result, I wouldn't be surprised at all of Walter and Andrei haven't really used properties in the same capacity as "unchecked public members are rare". This isn't a bashing post or an ad hominem; I'll try to be informative. ago when I used them (ignoring Java: those programmers use properties a lot, but it is a pain). They did not require an enormous amount of features to gain their power, and D shouldn't either. The primary differences are these: (3) Unambiguous property declaration syntax. implemented property rewrites. It didn't matter because value types are rare. (This may be dated by about 3 years.) I think that those differences are very solvable in D: (1) Disallow address-of on anything dealing with property. No one will miss it; they didn't expect it to exist in the first place. (2) Do semantic rewriting on properties. Once you have semantic rewriting, the value-type-properties problem is SOLVED and never needs to be revisited again. (Disallowing value types in properties would be poor course in a language where user-defined value types are very common.) (3) This is pretty much solved in DIP23 already. huge pain. Just because something /might/ be a property in the future, probably don't believe in "bags of values"; such things are nonsense if you want proper encapsulation! People coming from this background are going to LOVE having a shorthand like "public property int foo;" that removes all of the pain from properly encapsulating public state. Using properties in a properly-constrained system was actually very enjoyable. The above is why I don't see feature creep. The D designers probably don't see where it ends because they've never been to that edge. I worry that I could be totally wrong about Andrei/Walter's experiences in these arenas. I don't assert these notions as truth, but instead as a way of communicating my perceptions. I hope this is informative and not insulting.
Feb 05 2013
parent reply "Dicebot" <m.strashun gmail.com> writes:
On Tuesday, 5 February 2013 at 15:08:55 UTC, Chad Joan wrote:
 Hmmm.  This statement that unchecked public members are rare 
 makes me wonder if there is a fundamental difference of 
 background here.  Things might be much different if you came 

Well, Andrei background is easy to check: http://en.wikipedia.org/wiki/Andrei_Alexandrescu ;)
Feb 05 2013
parent Chad Joan <chadjoan gmail.com> writes:
On 02/05/2013 10:11 AM, Dicebot wrote:
 On Tuesday, 5 February 2013 at 15:08:55 UTC, Chad Joan wrote:
 Hmmm. This statement that unchecked public members are rare makes me
 wonder if there is a fundamental difference of background here. Things

Well, Andrei background is easy to check: http://en.wikipedia.org/wiki/Andrei_Alexandrescu ;)
I know I know ;) C++ guru, which is why I say what I say. It's still possible that he got a good dosage of property usage somewhere. If that happened and I based an argument off of it, then that would make me an ass. I also wouldn't notice because I don't stalk Andrei ;)
Feb 05 2013
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
05-Feb-2013 17:31, Andrei Alexandrescu пишет:
 On 2/5/13 3:39 AM, Dmitry Olshansky wrote:
 On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM,
 Jonathan M Davis wrote:
  >> We could save a lot of boilerplate code if we can simply make it
  >> variables and
  >> property functions guaranteed to be swappable without breaking code.
  >
  > I think this is quite powerful. The way we can do this is by making
  > properties emulate a subset of actual variables.
  >

 This is the primary real-world proble to solve.
The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that. Unprotected, unchecked member variables that can be get and set without any hooks into the enclosing structure are rare. That's not the case we should help and cater for. When that's the case, the entire object is legitimately a "bag of values" that has only public data.
Thinking more of it with proper properties it would be doable with a half-decent template mixin. Then it'd better be in Phobos one day as that would make it readily accessible but separate from the language. -- Dmitry Olshansky
Feb 05 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, February 05, 2013 08:31:46 Andrei Alexandrescu wrote:
 On 2/5/13 3:39 AM, Dmitry Olshansky wrote:
 On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 2:04 PM,
 
 Jonathan M Davis wrote:
  >> We could save a lot of boilerplate code if we can simply make it
  >> variables and
  >> property functions guaranteed to be swappable without breaking code.
  > 
  > I think this is quite powerful. The way we can do this is by making
  > properties emulate a subset of actual variables.
 
 This is the primary real-world proble to solve.
The problem with this approach is feature creep - there will always be yet another possible case in which a feature helps some case. We need to put a halt on that.
Being able to initially use a public variable and then swap it out later for property functions when refactoring is generally the reason that I've heard around here seem to think is a core feature of properties, and a core feature isn't feature creep. And if property on a variable makes it so that it lowers to getter and setter property functions (rather than leaving it as a public variable with certain restrictions on it), then we don't even have to worry about which features of a variable property functions do and don't emulate and whatever feature creep might appear there. The "variable" would immediately match due to the fact that you'd actually end up with property functions. You just wouldn't have had to do all the boilerplate for it.
 Unprotected, unchecked member variables that can be get and set without
 any hooks into the enclosing structure are rare. That's not the case we
 should help and cater for. When that's the case, the entire object is
 legitimately a "bag of values" that has only public data.
Really? In my experience they're quite common. It's usually the case that not all of the variables on a type have pass-through getters and setters, but it's quite common to have at least a few which do. It's been brought up a number of times in the past that it would be nice to have property on variables be used to avoid the boilerplate code in those cases. I suppose that we could use a mixin to solve that problem, but then you wouldn't get any documentation on it, since you can't document anything that's mixed in. - Jonathan M Davis
Feb 05 2013
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
2013/2/6 Jonathan M Davis <jmdavisProg gmx.com>
 Being able to initially use a public variable and then swap it out later
 for
 property functions when refactoring is generally the reason that I've heard

 people
 around here seem to think is a core feature of properties, and a core
 feature
 isn't feature creep. And if  property on a variable makes it so that it
 lowers
 to getter and setter property functions (rather than leaving it as a public
 variable with certain restrictions on it), then we don't even have to worry
 about which features of a variable property functions do and don't emulate
 and
 whatever feature creep might appear there. The "variable" would immediately
 match due to the fact that you'd actually end up with property functions.
 You
 just wouldn't have had to do all the boilerplate for it.
I fully agree with Andrei. I can see that swapping public data field to property function call is not rare, but in almost case, such refactoring also intends to add encapsulation. struct S { // Before swapping int _data; // After swapping private int _data; property int data() { return _data; } property void data(int n) { enforce(n > 0); _data = n; } } S s; int n = s.data; s.data = 1; //int* pdata = &s.data; // changed to disallowed ... it is mostly intended.
 Unprotected, unchecked member variables that can be get and set without
 any hooks into the enclosing structure are rare. That's not the case we
 should help and cater for. When that's the case, the entire object is
 legitimately a "bag of values" that has only public data.
Really? In my experience they're quite common. It's usually the case that not all of the variables on a type have pass-through getters and setters, but it's quite common to have at least a few which do. It's been brought up a number of times in the past that it would be nice to have property on variables be used to avoid the boilerplate code in those cases. I suppose that we could use a mixin to solve that problem, but then you wouldn't get any documentation on it, since you can't document anything that's mixed in.
Wrapping a field data with property function but also allow accessing to it directly through pointer is quite rare. struct S { // After swapping private int _data; property ref int data() { return _data; } // ref return property void data(int n) { enforce(n > 0); _data = n; } } S s; int n = s.data; // call getter s.data = 1; // call setter, enforce n > 0 int* pdata = &s.data; // But, if this is allowed, *pdata = -1; // this is accidentally allowed... Is this really intended? To me, it is just a encapsulation breaking. I'm not sure that it is what you would really expect. Kenji Hara
Feb 05 2013
prev sibling parent Robert <jfanatiker gmx.at> writes:
It is not feature creep, it is properties done right. If not done this
way, than honestly I don't know what properties are good for any way. We
could use set/get methods just as well.

If properties done right are feature creep, than properties per se are
feature creep, which is debatable. But if we keep them, we should do
them right.

Maybe you can elaborate what properties are good for, if not for
avoiding trivial set/get methods? -> Please really do that, because I am
having a hard time understanding your reasoning.



On Tue, 2013-02-05 at 08:31 -0500, Andrei Alexandrescu wrote:
 The problem with this approach is feature creep - there will always
 be 
 yet another possible case in which a feature helps some case. We need
 to 
 put a halt on that.
Feb 06 2013
prev sibling parent reply "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Tuesday, 5 February 2013 at 08:39:15 UTC, Dmitry Olshansky 
wrote:
 On 02/05/2013 02:28 AM, Andrei Alexandrescu wrote:> On 2/4/13 
 2:04 PM, Jonathan M Davis wrote:
 We could save a lot of boilerplate code if we can simply
make it
 variables and
 property functions guaranteed to be swappable without
breaking code.
 I think this is quite powerful. The way we can do this is by
making
 properties emulate a subset of actual variables.
This is the primary real-world proble to solve. If tackle it right we'd secure a sizable flow of Java converts simply because of this feature alone ;) More seriously I believe it's worth noting that properties can't emulate (in principle) exactly one aspect of variable - taking address as a pointer. Honestly I can't see a way to overcome it without introducing a user-defined way to impose this restriction on a field of a struct/class.
I'm not really sure which part of my article you are addressing here, but allowing 'opAddress' is available as a last resort. Also note that I had proposed 'cast(function)' instead of '&' to get the top-level function, which, unlike '&', can give: 'Error: not castable as a function'
 Then keeping in mind __traits I have the following clause to 
 add to the current proposal:

 Inside of aggregate a field marked with  property indicate is 
 semantically equivalent to compiler wrapping it with trivial 
 getter and setter. Example:
 struct Foo{
  property T x;
 }

 treated  semantically as if:
 T __x; // hidden by compiler
 //templated to have deduced safe, pure, nothrow
  property T x()()inout{ return x; }
  property void x()(T val){ x = val; }

 ---
 Dmitry Olshansky
While I appreciate your responding to my post, I'm a little confused which of its points you are addressing here.
Feb 05 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
05-Feb-2013 23:37, Zach the Mystic пишет:
[snip]
 While I appreciate your responding to my post, I'm a little confused
 which of its points you are addressing here.
Sorry, I posted reply to the wrong post. -- Dmitry Olshansky
Feb 05 2013
parent "Zach the Mystic" <reachBUTMINUSTHISzach gOOGLYmail.com> writes:
On Tuesday, 5 February 2013 at 19:44:03 UTC, Dmitry Olshansky 
wrote:
 05-Feb-2013 23:37, Zach the Mystic пишет:
 [snip]
 While I appreciate your responding to my post, I'm a little 
 confused
 which of its points you are addressing here.
Sorry, I posted reply to the wrong post.
I hope this doesn't end up being the primary reason people respond to my posts. :-)
Feb 05 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, February 06, 2013 09:56:40 kenji hara wrote:
 I fully agree with Andrei.
 I can see that swapping public data field to property function call is not
 rare, but in almost case, such refactoring also intends to add
 encapsulation.
 
 struct S {
     // Before swapping
     int _data;
 
     // After swapping
     private int _data;
      property int data() { return _data; }
      property void data(int n) { enforce(n > 0); _data = n; }
 }
 S s;
 int n = s.data;
 s.data = 1;
 //int* pdata = &s.data;
 // changed to disallowed ... it is mostly intended.
You misunderstand. We don't _want_ taking the address to work. We _want_ the encapsulation. We just don't want to have to write all of the boilerplate code. The idea is that you want to be able to just make it a variable first, because you don't need to do any extra checks or anything else but get or set the variable. So, having to declare the setters and getters is overkill. The problem is that if you just declare it a variable, then people can take the address of it or pass it by ref - which you don't want. You _want_ the encapsulation up-front. You just don't want to have to bother with all of the boilerplate code required to do it. That's why some of us have suggested making it so that you can mark variables with property. That then either makes it illegal to do anything with it which you couldn't do with a property function (e.g. take its address), or it simply lowers it to the getters and setters, making it so that you _do_ have the property functions in the beginning. You just don't have to write them explicitly. Then later, if refactoring requires that you add additional checks or other operations to the getter and/or setter, then you explicitly declare the property functions. - Jonathan M Davis
Feb 05 2013
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/6/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 That's why some of us have suggested
 making it so that you can mark variables with  property.
What Jonathan means is this: struct S { int var; // modifiable, can take address } Now suppose later you want to turn var into a property: struct S { property int var(); property void var(int); } This potentially breaks code if the user-code was using a pointer to the public var field in the previous version of your library. So instead we should have the ability to annotate fields with property: struct S { property int var; // modifiable, can *not* take address } There's no run-time cost, but it disallows taking the address of var, and it allows you to introduce property functions in the future without breaking user-code.
Feb 05 2013
parent "Tove" <tove fransson.se> writes:
On Wednesday, 6 February 2013 at 01:40:37 UTC, Andrej Mitrovic 
wrote:
 On 2/6/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 That's why some of us have suggested
 making it so that you can mark variables with  property.
What Jonathan means is this: struct S { int var; // modifiable, can take address } Now suppose later you want to turn var into a property: struct S { property int var(); property void var(int); } This potentially breaks code if the user-code was using a pointer to the public var field in the previous version of your library. So instead we should have the ability to annotate fields with property: struct S { property int var; // modifiable, can *not* take address } There's no run-time cost, but it disallows taking the address of var, and it allows you to introduce property functions in the future without breaking user-code.
It is also possible to first start with setters/getters and then switch to a public field(!) Which leads to the conclusion, in order for the property abstraction to be complete, address taking of *anything* annotated with property should either NOT be allowed... property int var(); // can *not* take address property void var(int); // can *not* take address property int var; // can *not* take address ... or we have to guarantee that the type remains unchanged... which is problematic due to different types of the getter and setter, which would force one to always specify the expected type rather than relying on auto. property int var; int delegate() d_get = &var; void delegate(int) d_set = &var;
Feb 10 2013
prev sibling parent Martin Nowak <code dawg.eu> writes:
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:
 Walter and I have had a discussion on how to finalize properties.

 http://wiki.dlang.org/DIP23
Could someone summarize the curent state and update the wiki pages accordingly. If the discussion has settled can we bless one of the 3 property DIPs with being approved? Otherwise what work has to be done to get there? http://wiki.dlang.org/DIP21 http://wiki.dlang.org/DIP23 http://wiki.dlang.org/DIP24
Dec 13 2013