www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - property syntax strawman

reply Walter Bright <newshound1 digitalmars.com> writes:
Having optional parentheses does lead to unresolvable ambiguities. How 
much of a problem that really is is debatable, but let's assume it 
should be resolved. To resolve it, a property must be distinguishable 
from a regular function.

One way is to simply add a "property" attribute keyword:

   property bool empty() { ... }
   property void empty(bool b) { ... }

The problem is that:

1. there are a lot of keywords already
2. keywords are global things

The alternative is to have a unique syntax for properties. Ideally, the 
syntax should be intuitive and mimic its use. After much fiddling, and 
based on n.g. suggestions, Andrei and I penciled in:

   bool empty { ... }
   void empty=(bool b) { ... }

The only problem is when a declaration but not definition is desired:

   bool empty;

but oops! That defines a field. So we came up with essentially a hack:

   bool empty{}

i.e. the {} means the getter is declared, but defined elsewhere.

What do you think?
Aug 02 2009
next sibling parent reply Zhenyu Zhou <rinick gmail.com> writes:
Walter Bright Wrote:
 but oops! That defines a field. So we came up with essentially a hack:
 
    bool empty{}

weird syntax I'd rather use bool empty=() { ... } void empty=(bool b) { ... }
Aug 02 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Zhenyu Zhou wrote:
 Walter Bright Wrote:
 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

weird syntax

I agree, it's a wart.
 I'd rather use 
 
    bool empty=() { ... }
    void empty=(bool b) { ... }

I suggested that, but Andrei thought it looked unintuitive, and he has a point.
Aug 02 2009
parent reply Frank Benoit <keinfarbton googlemail.com> writes:
Walter Bright schrieb:
 Zhenyu Zhou wrote:
 Walter Bright Wrote:
 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

weird syntax

I agree, it's a wart.
 I'd rather use
    bool empty=() { ... }
    void empty=(bool b) { ... }

I suggested that, but Andrei thought it looked unintuitive, and he has a point.

Or how about making it a single method? bool empty=(bool* value){ if( value ) _empty = *value; return _empty; } The compiler rewrites the calling code to either pass the address or null.
Aug 02 2009
parent reply KennyTM~ <kennytm gmail.com> writes:
Frank Benoit wrote:
 Walter Bright schrieb:
 Zhenyu Zhou wrote:
 Walter Bright Wrote:
 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}


 I'd rather use
    bool empty=() { ... }
    void empty=(bool b) { ... }

point.

Or how about making it a single method? bool empty=(bool* value){ if( value ) _empty = *value; return _empty; } The compiler rewrites the calling code to either pass the address or null.

So properties can't be used in SafeD?
Aug 02 2009
parent reply Frank Benoit <keinfarbton googlemail.com> writes:
KennyTM~ schrieb:
 Frank Benoit wrote:
 Or how about making it a single method?

 bool empty=(bool* value){
     if( value ) _empty = *value;
     return _empty;
 }

 The compiler rewrites the calling code to either pass the address or
 null.

So properties can't be used in SafeD?

Hm, right pointers are not allowed there. So the "in" operator for AAs is also disallowed? That surprises me.
Aug 02 2009
parent reply grauzone <none example.net> writes:
Frank Benoit wrote:
 KennyTM~ schrieb:
 Frank Benoit wrote:
 Or how about making it a single method?

 bool empty=(bool* value){
     if( value ) _empty = *value;
     return _empty;
 }

 The compiler rewrites the calling code to either pass the address or
 null.


Hm, right pointers are not allowed there. So the "in" operator for AAs is also disallowed? That surprises me.

You could allow pointers in SafeD. You just can't allow pointer arithmetic, unless a pointer carries information on the upper and lower bounds of the memory block. By the way, the -safe in dmd2 switch doesn't seem to do anything yet and allows unsafe pointer operations.
Aug 02 2009
parent Don <nospam nospam.com> writes:
grauzone wrote:
 Frank Benoit wrote:
 KennyTM~ schrieb:
 Frank Benoit wrote:
 Or how about making it a single method?

 bool empty=(bool* value){
     if( value ) _empty = *value;
     return _empty;
 }

 The compiler rewrites the calling code to either pass the address or
 null.


Hm, right pointers are not allowed there. So the "in" operator for AAs is also disallowed? That surprises me.

You could allow pointers in SafeD. You just can't allow pointer arithmetic, unless a pointer carries information on the upper and lower bounds of the memory block. By the way, the -safe in dmd2 switch doesn't seem to do anything yet

Almost nothing. It disallows inline asm. and
 allows unsafe pointer operations.

Aug 03 2009
prev sibling next sibling parent KennyTM~ <kennytm gmail.com> writes:
Walter Bright wrote:
 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
   property bool empty() { ... }
   property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things
 

If the annotation (attribute) proposal is adopted (see DIP 6) then property can be considered a compile-time annotation (attribute) and no new global keyword is required. property pure const nothrow bool empty() { ... } or attribute(property,pure,const,nothrow) bool empty() { ... }
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
   bool empty { ... }
   void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
   bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
   bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

Ugly :)
Aug 02 2009
prev sibling next sibling parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Walter Bright wrote:

    bool empty { ... }
    void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
    bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
    bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

It is quite hack-ish. There are ways to have your cake and eat it too. I wouldn't settle for 'bool empty{}'. -------------------------------------------------- bool empty { void set(auto value) { ... } auto get() { ... } } empty = false; // empty.set(false) auto b = empty; // auto b = empty.get() -------------------------------------------------- for example, requires no hacks and no keywords. And has the added advantage that you can still use the getter and setter methods directly. To call them or get delegates from them. -- Michiel Helvensteijn
Aug 02 2009
next sibling parent OF <no spam.plz> writes:
Michiel Helvensteijn Wrote:

 Walter Bright wrote:
 
    bool empty { ... }
    void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
    bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
    bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

It is quite hack-ish. There are ways to have your cake and eat it too. I wouldn't settle for 'bool empty{}'. -------------------------------------------------- bool empty { void set(auto value) { ... } auto get() { ... } } empty = false; // empty.set(false) auto b = empty; // auto b = empty.get() -------------------------------------------------- for example, requires no hacks and no keywords. And has the added advantage that you can still use the getter and setter methods directly. To call them or get delegates from them. -- Michiel Helvensteijn

I think I like this version better than using 'bool var{}' (the var= looks ok IMO, though). Apparently very similar to the C# approach too (which is shorter, but uses an implicit variable): public int humanAge { get { return age; } set { age = value; } }
Aug 02 2009
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 02 Aug 2009 13:00:38 +0400, Michiel Helvensteijn  
<m.helvensteijn.remove gmail.com> wrote:

 Walter Bright wrote:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

It is quite hack-ish. There are ways to have your cake and eat it too. I wouldn't settle for 'bool empty{}'. -------------------------------------------------- bool empty { void set(auto value) { ... } auto get() { ... } } empty = false; // empty.set(false) auto b = empty; // auto b = empty.get() -------------------------------------------------- for example, requires no hacks and no keywords. And has the added advantage that you can still use the getter and setter methods directly. To call them or get delegates from them.

I agree, this is a better solution!
Aug 02 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Sun, 02 Aug 2009 13:00:38 +0400, Michiel Helvensteijn 
 <m.helvensteijn.remove gmail.com> wrote:
 
 Walter Bright wrote:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

It is quite hack-ish. There are ways to have your cake and eat it too. I wouldn't settle for 'bool empty{}'. -------------------------------------------------- bool empty { void set(auto value) { ... } auto get() { ... } } empty = false; // empty.set(false) auto b = empty; // auto b = empty.get() -------------------------------------------------- for example, requires no hacks and no keywords. And has the added advantage that you can still use the getter and setter methods directly. To call them or get delegates from them.

I agree, this is a better solution!

I'd like to have an easy enough syntax for defining read-only properties (often in my code). With the proposed syntax, one writes bool empty { ... } and calls it a day, but with the elaborate getters and setters there are two scopes to get through: bool empty { auto get() { ... } } which is quite some aggravation. Andrei
Aug 02 2009
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Andrei Alexandrescu wrote:

 I'd like to have an easy enough syntax for defining read-only properties
 (often in my code). With the proposed syntax, one writes
 
 bool empty { ... }
 
 and calls it a day, but with the elaborate getters and setters there are
 two scopes to get through:
 
 bool empty { auto get() { ... } }
 
 which is quite some aggravation.

The point is not really the grouping of elements within brackets. That just eliminates some redundancy. It can also look like the following: void empty.set(bool value) { ... } bool empty.get() { ... } and have the same meaning as my earlier example. -- Michiel Helvensteijn
Aug 02 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 I'd like to have an easy enough syntax for defining read-only properties
 (often in my code). With the proposed syntax, one writes

 bool empty { ... }

 and calls it a day, but with the elaborate getters and setters there are
 two scopes to get through:

 bool empty { auto get() { ... } }

 which is quite some aggravation.

The point is not really the grouping of elements within brackets. That just eliminates some redundancy. It can also look like the following: void empty.set(bool value) { ... } bool empty.get() { ... } and have the same meaning as my earlier example.

Yah, I was thinking the same. This is my #1 fave so far. Andrei
Aug 02 2009
next sibling parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Andrei Alexandrescu wrote:

 void empty.set(bool value) { ... }
 bool empty.get() { ... }

Yah, I was thinking the same. This is my #1 fave so far.

You should read my reply to myself, though. It describes an ambiguity in the approach. Several solutions are discussed. (Just translate them from grouping to non-grouping solutions.) -- Michiel Helvensteijn
Aug 02 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 void empty.set(bool value) { ... }
 bool empty.get() { ... }


You should read my reply to myself, though. It describes an ambiguity in the approach. Several solutions are discussed. (Just translate them from grouping to non-grouping solutions.)

My reader does not show that message. Andrei
Aug 02 2009
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Andrei Alexandrescu wrote:

 You should read my reply to myself, though. It describes an ambiguity in
 the approach. Several solutions are discussed. (Just translate them from
 grouping to non-grouping solutions.)

My reader does not show that message.

How strange. http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=94712 -- Michiel Helvensteijn
Aug 02 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 You should read my reply to myself, though. It describes an ambiguity in
 the approach. Several solutions are discussed. (Just translate them from
 grouping to non-grouping solutions.)


How strange. http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=94712

Oh, I do see it. But that message predates your other message, the one I was replying too. To summarize: bool empty { void set(auto value) { ... } bool get() { ... } } I would really really prefer to not have two scopes in there. It makes properties unduly arcane to define, particularly read-only properties. They should be about as easy to define as regular methods. Then in a later message you mention: bool empty.get() { ... } void empty.set(bool b) { ... } which I like and which does not seem to have difficulties; the names "get" and "set" will be never used as such. Andrei
Aug 02 2009
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Andrei Alexandrescu wrote:

 Then in a later message you mention:
 
 bool empty.get() { ... }
 void empty.set(bool b) { ... }
 
 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S). -- Michiel Helvensteijn
Aug 02 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 Then in a later message you mention:

 bool empty.get() { ... }
 void empty.set(bool b) { ... }

 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S).

I see. My view is that .get and .set are simply symbolic placeholders, but indeed some may get confused. Andrei
Aug 02 2009
next sibling parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Andrei Alexandrescu wrote:

 I see. My view is that .get and .set are simply symbolic placeholders,
 but indeed some may get confused.

In my design, they are actual functions with actual names. For D this doesn't really work. If you want symbolic placeholders, you may want to use something other than 'get' and 'set'. For example, 'in' and 'out' have been suggested by some. They are already keywords. -- Michiel Helvensteijn
Aug 02 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 15:07:37 -0400, Michiel Helvensteijn 
<m.helvensteijn.remove gmail.com> said:

 In my design, they are actual functions with actual names.
 
 For D this doesn't really work. If you want symbolic placeholders, you may
 want to use something other than 'get' and 'set'. For example, 'in'
 and 'out' have been suggested by some. They are already keywords.

One thing with in and out makes me uneasy. Imagine a setter/getter with a contract: int prop.out() out (result) { assert(result > 3); } body { return something; } void prop.in(int v) in { assert(v > 3); } body { something = v; } Wouldn't it be a little confusing having twice the same keyword so close but with a completly different meaning? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 02 2009
parent Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Michel Fortin wrote:

 In my design, they are actual functions with actual names.
 
 For D this doesn't really work. If you want symbolic placeholders, you
 may want to use something other than 'get' and 'set'. For example, 'in'
 and 'out' have been suggested by some. They are already keywords.

One thing with in and out makes me uneasy. Imagine a setter/getter with a contract: int prop.out() out (result) { assert(result > 3); } body { return something; } void prop.in(int v) in { assert(v > 3); } body { something = v; } Wouldn't it be a little confusing having twice the same keyword so close but with a completly different meaning?

I agree, it's far from ideal. Well, I'm sure a solution can be found. It's now just down to detail. -- Michiel Helvensteijn
Aug 02 2009
prev sibling parent reply John C <johnch_atms hotmail.com> writes:
Andrei Alexandrescu wrote:
 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 Then in a later message you mention:

 bool empty.get() { ... }
 void empty.set(bool b) { ... }

 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S).

I see. My view is that .get and .set are simply symbolic placeholders, but indeed some may get confused. Andrei

Does the ambiguity go away if we replace the '.' with a space? Declaration: bool empty get(); void empty set(bool); Declaration: bool empty get() { return empty_; } void empty set(bool b) { empty_ = b; }
Aug 02 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
John C wrote:
 Andrei Alexandrescu wrote:
 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 Then in a later message you mention:

 bool empty.get() { ... }
 void empty.set(bool b) { ... }

 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S).

I see. My view is that .get and .set are simply symbolic placeholders, but indeed some may get confused. Andrei

Does the ambiguity go away if we replace the '.' with a space? Declaration: bool empty get(); void empty set(bool); Declaration: bool empty get() { return empty_; } void empty set(bool b) { empty_ = b; }

That should work. Andrei
Aug 02 2009
prev sibling parent reply John C <johnch_atms hotmail.com> writes:
Steven Schveighoffer wrote:
 On Sun, 02 Aug 2009 15:23:44 -0400, John C <johnch_atms hotmail.com> wrote:
 
 Andrei Alexandrescu wrote:
 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 Then in a later message you mention:

 bool empty.get() { ... }
 void empty.set(bool b) { ... }

 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S).

placeholders, but indeed some may get confused. Andrei

Does the ambiguity go away if we replace the '.' with a space? Declaration: bool empty get(); void empty set(bool); Declaration: bool empty get() { return empty_; } void empty set(bool b) { empty_ = b; }

The ambiguity of declaration, not the ambiguity of usage, unless you want to use the space to denote the usage also? -Steve

Not sure where the ambiguity is with usage. To keep things simple, 'get' and 'set' should only be valid at the point of declaration. They're not really part of the function name.
Aug 03 2009
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Steven Schveighoffer wrote:

 So the poster who started this trail of the thread is assuming that
 
 t.property.get()
 
 identifies the property getter directly.  But what if the return type of
 t.property.get() contains a method get()?  Since t.property is an alis for
 t.property.get(), Should t.property.get() map to:
 
 ...
 
 That is the ambiguity.

I myself see great value in the ability to access the getter and setter functions directly. But because of the ambiguity you described, this is problematic for D. Andrei sees 'get' and 'set' as nothing more than declaration-side indications of the getter and setter. Not real functions. In that case, the ambiguity doesn't exist. To alleviate possible confusion, it has been suggested that a space be used, not a dot, between the name of the property and get/set in the declaration. -- Michiel Helvensteijn
Aug 03 2009
next sibling parent Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Steven Schveighoffer wrote:

 So your answer is, there is no ambiguity because it's not possible to
 access the getter/setter directly?  That poses a problem for existing code
 which uses delegates to such functions.  I'm not sure we want to lose that
 ability.

I agree. But it's hardly up to me, is it? :-) -- Michiel Helvensteijn
Aug 03 2009
prev sibling next sibling parent John C <johnch_atms hotmail.com> writes:
Steven Schveighoffer wrote:
 On Mon, 03 Aug 2009 10:25:02 -0400, Michiel Helvensteijn 
 <m.helvensteijn.remove gmail.com> wrote:
 
 Steven Schveighoffer wrote:

 So the poster who started this trail of the thread is assuming that

 t.property.get()

 identifies the property getter directly.  But what if the return type of
 t.property.get() contains a method get()?  Since t.property is an 
 alis for
 t.property.get(), Should t.property.get() map to:

 ...

 That is the ambiguity.

I myself see great value in the ability to access the getter and setter functions directly. But because of the ambiguity you described, this is problematic for D. Andrei sees 'get' and 'set' as nothing more than declaration-side indications of the getter and setter. Not real functions. In that case, the ambiguity doesn't exist. To alleviate possible confusion, it has been suggested that a space be used, not a dot, between the name of the property and get/set in the declaration.

So your answer is, there is no ambiguity because it's not possible to access the getter/setter directly? That poses a problem for existing code which uses delegates to such functions. I'm not sure we want to lose that ability. -Steve

Back to the drawing board.
Aug 03 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 On Mon, 03 Aug 2009 10:25:02 -0400, Michiel Helvensteijn 
 <m.helvensteijn.remove gmail.com> wrote:
 
 Steven Schveighoffer wrote:

 So the poster who started this trail of the thread is assuming that

 t.property.get()

 identifies the property getter directly.  But what if the return type of
 t.property.get() contains a method get()?  Since t.property is an 
 alis for
 t.property.get(), Should t.property.get() map to:

 ...

 That is the ambiguity.

I myself see great value in the ability to access the getter and setter functions directly. But because of the ambiguity you described, this is problematic for D. Andrei sees 'get' and 'set' as nothing more than declaration-side indications of the getter and setter. Not real functions. In that case, the ambiguity doesn't exist. To alleviate possible confusion, it has been suggested that a space be used, not a dot, between the name of the property and get/set in the declaration.

So your answer is, there is no ambiguity because it's not possible to access the getter/setter directly? That poses a problem for existing code which uses delegates to such functions. I'm not sure we want to lose that ability. -Steve

Now that I think of it, even if properties don't readily return delegates, they are trivially easy to obtain: class A { ... define property foo with whatever syntax ... } unittest { auto a = new A; auto getter = () { return a.foo; } auto setter = (int x) { a.foo = x; } setter(5); writeln(getter()); } I actually compiled and ran that with foo defined as a regular field. Andrei
Aug 03 2009
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-03 11:03:54 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Now that I think of it, even if properties don't readily return 
 delegates, they are trivially easy to obtain:
 
 class A
 {
      ... define property foo with whatever syntax ...
 }
 
 unittest
 {
      auto a = new A;
      auto getter = () { return a.foo; }
      auto setter = (int x) { a.foo = x; }
      setter(5);
      writeln(getter());
 }
 
 I actually compiled and ran that with foo defined as a regular field.

They're indeed very easy to obtain, and using this method improves compatibility with regular fields, so it's great. That said, can you see the property through reflection? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 03 2009
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Steven Schveighoffer wrote:
 So your answer is, there is no ambiguity because it's not possible to
 access the getter/setter directly?  That poses a problem for existing
 code which uses delegates to such functions.  I'm not sure we want to
 lose that ability.

You can't trivially disambiguate between the getter and the setter with the current system, either. How is this a new issue? Besides which, why can't you just add this: __traits(getter, aggregate.property) Problem solved.
Aug 03 2009
parent Benji Smith <dlanguage benjismith.net> writes:
Steven Schveighoffer wrote:
 On Mon, 03 Aug 2009 11:18:26 -0400, Daniel Keep 
 <daniel.keep.lists gmail.com> wrote:
 You can't trivially disambiguate between the getter and the setter with
 the current system, either.  How is this a new issue?

You can't *trivially* but you can do it (that's another issue that probably should be addressed in general for overloaded functions).

Agreed. I don't think this is so much an issue with properties as it's an issue with overloads. A good solution that works really well for overloads will work well for properties too.
 Besides which, why can't you just add this:

   __traits(getter, aggregate.property)

 Problem solved.

That works too. That's probably the most sensable solution I've seen. Has my vote. -Steve

Me too. --b
Aug 03 2009
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 12:32:16 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 The point is not really the grouping of elements within brackets. That just
 eliminates some redundancy. It can also look like the following:
 
 void empty.set(bool value) { ... }
 bool empty.get() { ... }
 
 and have the same meaning as my earlier example.

Yah, I was thinking the same. This is my #1 fave so far.

And as a bonus, it makes this look ridiculous: void popFront.get() { ... } which means it won't get so easily twisted for use by functions with no parameters. The only thing that can get confusing is getting the address of the setter and getter, because get and set aren't keywords and thus could be defined by the returned object. &empty.get; // address of what? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 02 2009
prev sibling parent Benji Smith <dlanguage benjismith.net> writes:
Andrei Alexandrescu wrote:
 Michiel Helvensteijn wrote:
 void empty.set(bool value) { ... }
 bool empty.get() { ... }

 and have the same meaning as my earlier example.

Yah, I was thinking the same. This is my #1 fave so far. Andrei

Agreed! I see the appeal of putting getter/setter pairs within a single pair of braces, since it groups them together as one logical unit. BUT... I think it's more valuable to define them as completely separate, since you sometimes want to define get/set properties with different access modifiers (protected setter & public getter == very nice). And then the brace-enclosed syntax looks kinda goofy to my eyes: property MyProperty int { public get; protected set; // WEIRD } --benji
Aug 03 2009
prev sibling next sibling parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Michiel Helvensteijn wrote:

 --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }
 
 empty = false; // empty.set(false)
 auto b = empty; // auto b = empty.get()
 --------------------------------------------------
 
 for example, requires no hacks and no keywords. And has the added
 advantage that you can still use the getter and setter methods directly.

It should be noted that there is an ambiguity if the type of the property is a struct/class with members named 'get' and 'set'. As I see it, there are three ways to resolve it: * Disallow properties with such a struct/class. This seems a little bit excessive and silly. But it is one way. * The 'set' and 'get' from the property are only used for the property-calling syntax. They can not be referenced directly. The members of the struct/class would all be accessable. This would work about the same way as, for example, the suggestion from John C in this thread. And if you go down this path, you might as well condense the syntax, as he did. * The 'set' and 'get' from the property are accessable functions and they overshadow possible member functions with those names. My language uses the third way, but there is no problem with overshadowing. The 'set' and 'get' functions have the same special purpose for every type, and the property is meant to override them. I guess D could do something similar using, instead of my 'get' and 'set', D's 'this' and 'opAssign' respectively. -- Michiel Helvensteijn
Aug 02 2009
parent reply JPF <johannespfau gmail.com> writes:
Michiel Helvensteijn schrieb:
 Michiel Helvensteijn wrote:
 
 --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }

 empty = false; // empty.set(false)
 auto b = empty; // auto b = empty.get()
 --------------------------------------------------

 for example, requires no hacks and no keywords. And has the added
 advantage that you can still use the getter and setter methods directly.

It should be noted that there is an ambiguity if the type of the property is a struct/class with members named 'get' and 'set'. As I see it, there are three ways to resolve it: * Disallow properties with such a struct/class. This seems a little bit excessive and silly. But it is one way. * The 'set' and 'get' from the property are only used for the property-calling syntax. They can not be referenced directly. The members of the struct/class would all be accessable. This would work about the same way as, for example, the suggestion from John C in this thread. And if you go down this path, you might as well condense the syntax, as he did. * The 'set' and 'get' from the property are accessable functions and they overshadow possible member functions with those names. My language uses the third way, but there is no problem with overshadowing. The 'set' and 'get' functions have the same special purpose for every type, and the property is meant to override them. I guess D could do something similar using, instead of my 'get' and 'set', D's 'this' and 'opAssign' respectively.

define the property as --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }


but rewrite empty.get/set to empty.__get/__set. As far as I know names beginning with __ are reserved, so the returned type of the property couldn't define it. Accessing the setter/getter directly could still be done using -------------------------------------------------- empty = false; // empty.__set(false) auto b = empty; // auto b = empty.__get() auto getter = &empty.__get() -------------------------------------------------- This also allows getting function pointers for the setter and the getter. As an addition -------------------------------------------------- auto b = &empty -------------------------------------------------- would then return a pointer to the returned value.
Aug 02 2009
next sibling parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
JPF wrote:

 There's at least one more solution:
 define the property as
 --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }


but rewrite empty.get/set to empty.__get/__set. As far as I know names beginning with __ are reserved, so the returned type of the property couldn't define it.

This may be acceptable. I don't much like that the double-underscore is necessary, but it may be the best solution there is.
 auto getter = &empty.__get()

You meant without the parentheses here, right?
 As an addition
 --------------------------------------------------
 auto b = &empty
 --------------------------------------------------
 would then return a pointer to the returned value.

That would be a pointer to a temporary value, though. Not very useful. But lexically, it works, yes. -- Michiel Helvensteijn
Aug 02 2009
parent JPF <johannespfau gmail.com> writes:
Michiel Helvensteijn wrote:
 JPF wrote:
 
 There's at least one more solution:
 define the property as
 --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }


but rewrite empty.get/set to empty.__get/__set. As far as I know names beginning with __ are reserved, so the returned type of the property couldn't define it.

This may be acceptable. I don't much like that the double-underscore is necessary, but it may be the best solution there is.
 auto getter = &empty.__get()

You meant without the parentheses here, right?

sure (damn copy & paste) ;-)
 As an addition
 --------------------------------------------------
 auto b = &empty
 --------------------------------------------------
 would then return a pointer to the returned value.

That would be a pointer to a temporary value, though. Not very useful. But lexically, it works, yes.

It was mentioned in another thread, that's why I mentioned it as well.
Aug 02 2009
prev sibling parent reply Oliver Hoog <kingboscop gmail.com> writes:
JPF schrieb:
 Michiel Helvensteijn schrieb:
 Michiel Helvensteijn wrote:

 --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }

 empty = false; // empty.set(false)
 auto b = empty; // auto b = empty.get()
 --------------------------------------------------

 for example, requires no hacks and no keywords. And has the added
 advantage that you can still use the getter and setter methods directly.

a struct/class with members named 'get' and 'set'. As I see it, there are three ways to resolve it: * Disallow properties with such a struct/class. This seems a little bit excessive and silly. But it is one way. * The 'set' and 'get' from the property are only used for the property-calling syntax. They can not be referenced directly. The members of the struct/class would all be accessable. This would work about the same way as, for example, the suggestion from John C in this thread. And if you go down this path, you might as well condense the syntax, as he did. * The 'set' and 'get' from the property are accessable functions and they overshadow possible member functions with those names. My language uses the third way, but there is no problem with overshadowing. The 'set' and 'get' functions have the same special purpose for every type, and the property is meant to override them. I guess D could do something similar using, instead of my 'get' and 'set', D's 'this' and 'opAssign' respectively.

define the property as --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }


but rewrite empty.get/set to empty.__get/__set. As far as I know names beginning with __ are reserved, so the returned type of the property couldn't define it. Accessing the setter/getter directly could still be done using -------------------------------------------------- empty = false; // empty.__set(false) auto b = empty; // auto b = empty.__get() auto getter = &empty.__get() -------------------------------------------------- This also allows getting function pointers for the setter and the getter. As an addition -------------------------------------------------- auto b = &empty -------------------------------------------------- would then return a pointer to the returned value.

But you would have to write more than necessary. Simpler is: --- bool foo { in(bar) { ... } out { return ... } } --- in is translated to: void in(bool bar) {...} out is translated to: bool out() {...} To get a delegate to in: auto f = &foo.in; foo = 5; is equivalent to foo.in(5); This way you don't need any new keywords or ugly (double) underscores. And it's unambiguous and pretty clear.
Aug 02 2009
next sibling parent Oliver Hoog <kingboscop gmail.com> writes:
 ---
 bool foo {
     in(bar) { ... }
     out { return ... }
 }
 ---

Actually it's also enough with the surrounding scope. And fast to write, just one line: bool foo in(bar) {...} out {...} Everyone that sees this for the first time can see what it means. And it's more intuitive syntax than bool empty { ... } void empty=(bool b) { ... } With the first syntax above you would have to specify the type (bool in this case) only once.
Aug 02 2009
prev sibling parent JPF <johannespfau gmail.com> writes:
Oliver Hoog wrote:
 JPF schrieb:
 Michiel Helvensteijn schrieb:
 Michiel Helvensteijn wrote:

 --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }

 empty = false; // empty.set(false)
 auto b = empty; // auto b = empty.get()
 --------------------------------------------------

 for example, requires no hacks and no keywords. And has the added
 advantage that you can still use the getter and setter methods
 directly.

property is a struct/class with members named 'get' and 'set'. As I see it, there are three ways to resolve it: * Disallow properties with such a struct/class. This seems a little bit excessive and silly. But it is one way. * The 'set' and 'get' from the property are only used for the property-calling syntax. They can not be referenced directly. The members of the struct/class would all be accessable. This would work about the same way as, for example, the suggestion from John C in this thread. And if you go down this path, you might as well condense the syntax, as he did. * The 'set' and 'get' from the property are accessable functions and they overshadow possible member functions with those names. My language uses the third way, but there is no problem with overshadowing. The 'set' and 'get' functions have the same special purpose for every type, and the property is meant to override them. I guess D could do something similar using, instead of my 'get' and 'set', D's 'this' and 'opAssign' respectively.

define the property as --------------------------------------------------
 bool empty {
     void set(auto value) { ... }
     auto get() { ... }
 }


but rewrite empty.get/set to empty.__get/__set. As far as I know names beginning with __ are reserved, so the returned type of the property couldn't define it. Accessing the setter/getter directly could still be done using -------------------------------------------------- empty = false; // empty.__set(false) auto b = empty; // auto b = empty.__get() auto getter = &empty.__get() -------------------------------------------------- This also allows getting function pointers for the setter and the getter. As an addition -------------------------------------------------- auto b = &empty -------------------------------------------------- would then return a pointer to the returned value.

But you would have to write more than necessary. Simpler is: --- bool foo { in(bar) { ... } out { return ... } } ---

better than the double underscores.
 in is translated to: void in(bool bar) {...}
 out is translated to: bool out() {...}
 
 To get a delegate to in:
 auto f = &foo.in;
 
 foo = 5; is equivalent to foo.in(5);
 
 This way you don't need any new keywords or ugly (double) underscores.
 And it's unambiguous and pretty clear.

Aug 02 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Sun, Aug 2, 2009 at 4:21 PM, Nick Sabalausky<a a.a> wrote:
 "Oliver Hoog" <kingboscop gmail.com> wrote in message
 news:h54ccl$1v3l$1 digitalmars.com...
 But you would have to write more than necessary. Simpler is:
 ---
 bool foo {
 in(bar) { ... }
 out { return ... }
 }
 ---
 in is translated to: void in(bool bar) {...}
 out is translated to: bool out() {...}

 To get a delegate to in:
 auto f =3D &foo.in;

 foo =3D 5; is equivalent to foo.in(5);

 This way you don't need any new keywords or ugly (double) underscores.
 And it's unambiguous and pretty clear.

Yes! Or wait, even better yet: static foo { static(static) { ... } static static { static ... } } In fact, let's *really* minimize the number of keywords in D: // From: int main(char[][] args) { =A0 =A0if(args.length =3D=3D 1) =A0 =A0 =A0 =A0return 1; =A0 =A0return 0; } // To: static static(static[][] static) { =A0 =A0static(static.static=3D=3D 1) =A0 =A0 =A0 =A0static 1; =A0 =A0static 0; } Perfect! Now we'll never have to worry about having too many keywords!

'static' is a woefully underused keyword. It really does need more uses.
Aug 02 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 02 Aug 2009 15:23:44 -0400, John C <johnch_atms hotmail.com> wrote:

 Andrei Alexandrescu wrote:
 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 Then in a later message you mention:

 bool empty.get() { ... }
 void empty.set(bool b) { ... }

 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S).

but indeed some may get confused. Andrei

Does the ambiguity go away if we replace the '.' with a space? Declaration: bool empty get(); void empty set(bool); Declaration: bool empty get() { return empty_; } void empty set(bool b) { empty_ = b; }

The ambiguity of declaration, not the ambiguity of usage, unless you want to use the space to denote the usage also? -Steve
Aug 03 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 10:14:14 -0400, John C <johnch_atms hotmail.com> wrote:

 Steven Schveighoffer wrote:
 On Sun, 02 Aug 2009 15:23:44 -0400, John C <johnch_atms hotmail.com>  
 wrote:

 Andrei Alexandrescu wrote:
 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 Then in a later message you mention:

 bool empty.get() { ... }
 void empty.set(bool b) { ... }

 which I like and which does not seem to have difficulties; the names
 "get" and "set" will be never used as such.

Yes, those are two notations for the same thing, and they have the same problem. Let me demonstrate: -------------------------------------------------- struct S { int get() { return 42; } }; struct T { S _s; S property.get() { return _s; } void property.set(S s) { _s = s; } } T t; auto X = t.property.get(); -------------------------------------------------- What is the type of X? It can be either S or int, depending on how D handles the situation. The ambiguity is in the possibility to directly reference the getter and setter methods. In that other subthread (the older one) I listed some possible solutions. The first is to make such a program an error. The second is not to allow a direct reference to a getter/setter (so X is an int). The third is to let the getter/setter overshadow S members (so X is an S).

placeholders, but indeed some may get confused. Andrei

Does the ambiguity go away if we replace the '.' with a space? Declaration: bool empty get(); void empty set(bool); Declaration: bool empty get() { return empty_; } void empty set(bool b) { empty_ = b; }

want to use the space to denote the usage also? -Steve

Not sure where the ambiguity is with usage. To keep things simple, 'get' and 'set' should only be valid at the point of declaration. They're not really part of the function name.

Currently, since properties are simply functions, you can take the delegate of a setter. So the poster who started this trail of the thread is assuming that t.property.get() identifies the property getter directly. But what if the return type of t.property.get() contains a method get()? Since t.property is an alis for t.property.get(), Should t.property.get() map to: t.property or (t.property).get() // get the property, then call it's get function. That is the ambiguity. -Steve
Aug 03 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 10:25:02 -0400, Michiel Helvensteijn  
<m.helvensteijn.remove gmail.com> wrote:

 Steven Schveighoffer wrote:

 So the poster who started this trail of the thread is assuming that

 t.property.get()

 identifies the property getter directly.  But what if the return type of
 t.property.get() contains a method get()?  Since t.property is an alis  
 for
 t.property.get(), Should t.property.get() map to:

 ...

 That is the ambiguity.

I myself see great value in the ability to access the getter and setter functions directly. But because of the ambiguity you described, this is problematic for D. Andrei sees 'get' and 'set' as nothing more than declaration-side indications of the getter and setter. Not real functions. In that case, the ambiguity doesn't exist. To alleviate possible confusion, it has been suggested that a space be used, not a dot, between the name of the property and get/set in the declaration.

So your answer is, there is no ambiguity because it's not possible to access the getter/setter directly? That poses a problem for existing code which uses delegates to such functions. I'm not sure we want to lose that ability. -Steve
Aug 03 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 11:03:54 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 On Mon, 03 Aug 2009 10:25:02 -0400, Michiel Helvensteijn  
 <m.helvensteijn.remove gmail.com> wrote:

 Steven Schveighoffer wrote:

 So the poster who started this trail of the thread is assuming that

 t.property.get()

 identifies the property getter directly.  But what if the return type  
 of
 t.property.get() contains a method get()?  Since t.property is an  
 alis for
 t.property.get(), Should t.property.get() map to:

 ...

 That is the ambiguity.

I myself see great value in the ability to access the getter and setter functions directly. But because of the ambiguity you described, this is problematic for D. Andrei sees 'get' and 'set' as nothing more than declaration-side indications of the getter and setter. Not real functions. In that case, the ambiguity doesn't exist. To alleviate possible confusion, it has been suggested that a space be used, not a dot, between the name of the property and get/set in the declaration.

access the getter/setter directly? That poses a problem for existing code which uses delegates to such functions. I'm not sure we want to lose that ability. -Steve

Now that I think of it, even if properties don't readily return delegates, they are trivially easy to obtain: class A { ... define property foo with whatever syntax ... } unittest { auto a = new A; auto getter = () { return a.foo; } auto setter = (int x) { a.foo = x; } setter(5); writeln(getter()); } I actually compiled and ran that with foo defined as a regular field.

Yes, that works. Now make it so I don't have to go through 2 function calls :) But the few times that you need a delegate to a getter/setter probably makes this kludge a valid solution. It might even be possible to make a template, like: PropertyDelegate!(T...) delegateOf(a.foo) One thing I dislike about D sometimes is how it forces me to go through extra layers to make the syntax valid, when a direct route is clearly possible. Yes, I know it doesn't add too much bloat/overhead, but it is supposed to be a systems language after all... -Steve
Aug 03 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 11:18:26 -0400, Daniel Keep  
<daniel.keep.lists gmail.com> wrote:

 Steven Schveighoffer wrote:
 So your answer is, there is no ambiguity because it's not possible to
 access the getter/setter directly?  That poses a problem for existing
 code which uses delegates to such functions.  I'm not sure we want to
 lose that ability.

You can't trivially disambiguate between the getter and the setter with the current system, either. How is this a new issue?

You can't *trivially* but you can do it (that's another issue that probably should be addressed in general for overloaded functions). Aside from Andrei's wrapper trick, you *can't* do it with the proposed property syntax.
 Besides which, why can't you just add this:

   __traits(getter, aggregate.property)

 Problem solved.

That works too. That's probably the most sensable solution I've seen. Has my vote. -Steve
Aug 03 2009
prev sibling next sibling parent Johan Granberg <lijat.meREM OVEgmail.com> writes:
Walter Bright wrote:

 Having optional parentheses does lead to unresolvable ambiguities. How
 much of a problem that really is is debatable, but let's assume it
 should be resolved. To resolve it, a property must be distinguishable
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
    property bool empty() { ... }
    property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things
 
 The alternative is to have a unique syntax for properties. Ideally, the
 syntax should be intuitive and mimic its use. After much fiddling, and
 based on n.g. suggestions, Andrei and I penciled in:
 
    bool empty { ... }
    void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
    bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
    bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

It solvs the ambiguities so it would work, might be nicer syntaxes out their but it solvs the main problem.
Aug 02 2009
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 03:43:43 -0400, Walter Bright <newshound1 digitalmars.com> said:

 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
    property bool empty() { ... }
    property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things

Glad to see you're giving it some tought. :-)
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
    bool empty { ... }
    void empty=(bool b) { ... }

I like that. But then (just a question) can you do: void empty+=(bool b) { ... } void empty++ { ... } void ++empty { ... } ?
 The only problem is when a declaration but not definition is desired:
 
    bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
    bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I'd prefer this, which can't be misinterpreted as an empty statement: bool empty { ... } It also happens to scale well to any function delcation: void foo() { ... } void empty=(bool b) { ... } The way I see it, the other function declaration syntax would still work, except for property getters where you'd need this special one. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 02 2009
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 06:27:27 -0400, Michel Fortin <michel.fortin michelf.com> said:

    bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I'd prefer this, which can't be misinterpreted as an empty statement: bool empty { ... }

In the same vein, I'm now realizing that "bool empty {}" syntax for a declaration is also a little dangerous and inconsistent: contrary to other functions with a return value, the compiler can't issue an error to say you forgot to return a value if you leave the body empty, it'd silently transform it to a declaration instead. Again, the elipsis solves this. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 02 2009
prev sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Michel Fortin wrote:
 On 2009-08-02 03:43:43 -0400, Walter Bright <newshound1 digitalmars.com>
 said:
 
 The alternative is to have a unique syntax for properties. Ideally,
 the syntax should be intuitive and mimic its use. After much fiddling,
 and based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

I like that. But then (just a question) can you do: void empty+=(bool b) { ... } void empty++ { ... } void ++empty { ... } ?

If we apply rewriting rules to expressions that are mutated (either by a unary operator or by being the left-hand side of some kind of assignment expression) then we get these for free. I'd really like to /not/ have to define these extra operations. Otherwise we end up with one of the downsides of current operator overloads: defining all of them is a serious pain in the butt, and getting the compiler to define all of them for you is ugly.
Aug 02 2009
prev sibling next sibling parent reply John C <johnch_atms hotmail.com> writes:
Walter Bright wrote:
 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
   property bool empty() { ... }
   property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things

Well, property probably isn't too common a variable name, so it shouldn't impact existing code.
 
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
   bool empty { ... }
   void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
   bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
   bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.

Would unimplemented setters look like this: void empty = (bool b) {} ?
 
 What do you think?

Looks a bit odd. Perhaps it's just the unfamiliarity of the syntax. Most of us got used to templates, eventually. My own syntax suggestion requires no new keywords (contextual or otherwise). interface INameable { string name { (); (value); } } class Person : INameable { private string name_; string name { () { return name_; } (value) { name_ = value; } } } In the above example, "value" could be anything the class designer wants - to the compiler, empty parentheses () represent the getter, (blah) the setter.
Aug 02 2009
parent Oliver Hoog <kingboscop gmail.com> writes:
John C schrieb:
 Walter Bright wrote:
 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.

 One way is to simply add a "property" attribute keyword:

   property bool empty() { ... }
   property void empty(bool b) { ... }

 The problem is that:

 1. there are a lot of keywords already
 2. keywords are global things

Well, property probably isn't too common a variable name, so it shouldn't impact existing code.
 The alternative is to have a unique syntax for properties. Ideally, 
 the syntax should be intuitive and mimic its use. After much fiddling, 
 and based on n.g. suggestions, Andrei and I penciled in:

   bool empty { ... }
   void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

   bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

   bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

Would unimplemented setters look like this: void empty = (bool b) {} ?
 What do you think?

Looks a bit odd. Perhaps it's just the unfamiliarity of the syntax. Most of us got used to templates, eventually. My own syntax suggestion requires no new keywords (contextual or otherwise). interface INameable { string name { (); (value); } } class Person : INameable { private string name_; string name { () { return name_; } (value) { name_ = value; } } } In the above example, "value" could be anything the class designer wants - to the compiler, empty parentheses () represent the getter, (blah) the setter.

Looks good. You could have wrapper properties like: --- class Clock { private int sec_; int min { () {return sec_ / 60;} (m) {sec_ = m * 60;} } } --- auto c = new Clock; c.min = 2; ++c.min; // gets translated to "c.min = c.min + 1;" and evaluates to c.min called after that call c.min++; // gets translated to "c.min = c.min + 1;" and evaluates to c.min called before that call // same with other ops unless they are explicitely otherwise defined --- (And all non-property functions shouldn't be allowed to be called in assign-style or without parentheses.)
Aug 02 2009
prev sibling next sibling parent Zhenyu Zhou <rinick gmail.com> writes:
Walter Bright Wrote:
 One way is to simply add a "property" attribute keyword:
 
    property bool empty() { ... }
    property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things

Have you thought about reusing existing keywords? like "in" and "out"
Aug 02 2009
prev sibling next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Sun, Aug 2, 2009 at 3:43 AM, Walter Bright<newshound1 digitalmars.com> w=
rote:
 Having optional parentheses does lead to unresolvable ambiguities. How mu=

 of a problem that really is is debatable, but let's assume it should be
 resolved. To resolve it, a property must be distinguishable from a regula=

 function.

 One way is to simply add a "property" attribute keyword:

 =A0property bool empty() { ... }
 =A0property void empty(bool b) { ... }

 The problem is that:

 1. there are a lot of keywords already
 2. keywords are global things

 The alternative is to have a unique syntax for properties. Ideally, the
 syntax should be intuitive and mimic its use. After much fiddling, and ba=

 on n.g. suggestions, Andrei and I penciled in:

 =A0bool empty { ... }
 =A0void empty=3D(bool b) { ... }

The *very* first thing I thought of when I saw this was: virtual void foo() =3D 0; I mean, why do we need the abstract keyword when C++ already has a perfectly obvious, eminently understandable syntax for it? Right?
 The only problem is when a declaration but not definition is desired:

 =A0bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

 =A0bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I think this feels like a desperate grasping-at-straws attempt to not add a keyword (even though pure, nothrow, shared, __gshared, and immutable all seem to have made it in without any great fanfare). Throwing esoteric syntax at it complicates the grammar and the parser, and you end up with this wad of symbols that doesn't intuitively indicate that it is a property. Yes, you can get used to anything. People get used to Perl, too. I think it's funny that for a week, Andrei has been arguing against throwing around new syntax to solve this problem, and that's exactly what you guys have come up with. Really, how much more complicated would this make the parser, compared to adding a new attribute?
Aug 02 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 I think it's funny that for a week, Andrei has been arguing against
 throwing around new syntax to solve this problem, and that's exactly
 what you guys have come up with.  Really, how much more complicated
 would this make the parser, compared to adding a new attribute?

We couldn't find a good solution without adding new syntax, so this is now on the table. Adding syntax or keywords is the next thing to look at. I'd still be unsatisfied if: (a) there would be significant syntactic noise to defining a read-only property (b) we had to add a keyword Andrei
Aug 02 2009
next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el  2 de agosto a las 11:02 me escribiste:
 Jarrett Billingsley wrote:
I think it's funny that for a week, Andrei has been arguing against
throwing around new syntax to solve this problem, and that's exactly
what you guys have come up with.  Really, how much more complicated
would this make the parser, compared to adding a new attribute?

We couldn't find a good solution without adding new syntax, so this is now on the table. Adding syntax or keywords is the next thing to look at. I'd still be unsatisfied if: (a) there would be significant syntactic noise to defining a read-only property (b) we had to add a keyword

Againg, what about DIP6? b) won' happen, even more, D could get rid of a *lot* of keywords if it works out. a) this not that bad, right? property bool empty() { return _len == 0; } (we can use prop if property is too long) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- <o_O> parakenotengobarraespaciadora <o_O> aver <o_O> estoyarreglandolabarraporkeserompiounapatita
Aug 02 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Robert Jacques wrote:
 On Sun, 02 Aug 2009 12:02:22 -0400, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Jarrett Billingsley wrote:
 I think it's funny that for a week, Andrei has been arguing against
 throwing around new syntax to solve this problem, and that's exactly
 what you guys have come up with.  Really, how much more complicated
 would this make the parser, compared to adding a new attribute?

We couldn't find a good solution without adding new syntax, so this is now on the table. Adding syntax or keywords is the next thing to look at. I'd still be unsatisfied if: (a) there would be significant syntactic noise to defining a read-only property (b) we had to add a keyword Andrei

I'd also still like to be able to do stuff like this: auto data = std.file.readText(filename).chomp.split;

I love that too. Unfortunately, the way the water is moving, it looks like we'll lose some or all of that. Andrei
Aug 02 2009
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Andrei Alexandrescu wrote:

 auto data = std.file.readText(filename).chomp.split;

I love that too. Unfortunately, the way the water is moving, it looks like we'll lose some or all of that.

That's not really true. Some of those no-parameter functions are just meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split; -- Michiel Helvensteijn
Aug 03 2009
next sibling parent reply KennyTM~ <kennytm gmail.com> writes:
Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 auto data = std.file.readText(filename).chomp.split;

like we'll lose some or all of that.

That's not really true. Some of those no-parameter functions are just meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split;

So to allow omission of the parenthesis of these "read-only properties" we do property string chomped (string x) { ... } ? I don't think Walter's syntax is capable of introducing "properties" to these free methods, but the property attribute can. (However, this may make chomped = "abcd" valid, which is not what we want.)
Aug 03 2009
parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
KennyTM~ wrote:

 auto data = std.file.readText(filename).chomp.split;

I love that too. Unfortunately, the way the water is moving, it looks like we'll lose some or all of that.

That's not really true. Some of those no-parameter functions are just meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split;

So to allow omission of the parenthesis of these "read-only properties" we do

No, it's not "allowing omission", it's "forcing omission". That's what properties are.
  property string chomped (string x) { ... }
 
 ? I don't think Walter's syntax is capable of introducing "properties"
 to these free methods, but the property attribute can.

I still think an identifier is either property or function, but not both. And judging by the way the wind is blowing, attributes/annotations will not be used for properties.
 (However, this may make
 
 chomped = "abcd"
 
 valid, which is not what we want.)

No, it wouldn't, since it'd be a read-only property. That means you can only read, not write. -- Michiel Helvensteijn
Aug 03 2009
parent KennyTM~ <kennytm gmail.com> writes:
Michiel Helvensteijn wrote:
 KennyTM~ wrote:
 
 auto data = std.file.readText(filename).chomp.split;

like we'll lose some or all of that.

meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split;

we do

No, it's not "allowing omission", it's "forcing omission". That's what properties are.

Ok. So to allow forced removal of parenthesis etc etc.
  property string chomped (string x) { ... }

 ? I don't think Walter's syntax is capable of introducing "properties"
 to these free methods, but the property attribute can.

I still think an identifier is either property or function, but not both. And judging by the way the wind is blowing, attributes/annotations will not be used for properties.

Too bad. Attributes is much cleaner than the equal sign hack.
 (However, this may make

 chomped = "abcd"

 valid, which is not what we want.)

No, it wouldn't, since it'd be a read-only property. That means you can only read, not write.

Unless global properties are disabled. (It should.)
Aug 03 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:
 
 auto data = std.file.readText(filename).chomp.split;

like we'll lose some or all of that.

That's not really true. Some of those no-parameter functions are just meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split;

Sure you meant: auto data = std.file.textFrom(filename).chomped.splat; :o) Andrei
Aug 03 2009
parent reply Sergey Gromov <snake.scaly gmail.com> writes:
Mon, 03 Aug 2009 11:06:53 -0400, Steven Schveighoffer wrote:

 I just thought of another issue with property definitions.  How do you  
 declare a property of an array?  Today it's:
 
 char[] chomped(char[] input);
 
 Note that any getter property contains an argument which is the object  
 you're calling the property on (normally implied because the definition is  
 inside an aggregate definition).  But with arrays it's explicit.
 
 So how does this fit in Walter's proposed syntax?
 
 char[] chomped {...}
 
 Where does the input go?

I proposed a keyword, 'inject', a year ago. Or it could be an annotation. I suppose such a keyword might significantly simplify implmentation of external functions and properties: inject property char[] chomped(char[] arr) {...} inject void sort!(alias pred, T)(T[] arr) {...} Though prepending 'this' to the first parameter may also work, C# style.
Aug 03 2009
parent Sergey Gromov <snake.scaly gmail.com> writes:
Tue, 4 Aug 2009 01:15:45 +0400, Sergey Gromov wrote:

 Mon, 03 Aug 2009 11:06:53 -0400, Steven Schveighoffer wrote:
 
 I just thought of another issue with property definitions.  How do you  
 declare a property of an array?  Today it's:
 
 char[] chomped(char[] input);
 
 Note that any getter property contains an argument which is the object  
 you're calling the property on (normally implied because the definition is  
 inside an aggregate definition).  But with arrays it's explicit.
 
 So how does this fit in Walter's proposed syntax?
 
 char[] chomped {...}
 
 Where does the input go?

I proposed a keyword, 'inject', a year ago. Or it could be an annotation. I suppose such a keyword might significantly simplify implmentation of external functions and properties: inject property char[] chomped(char[] arr) {...} inject void sort!(alias pred, T)(T[] arr) {...} Though prepending 'this' to the first parameter may also work, C# style.

Or, this can work with Walter's syntax: extension!char[] char[] chomped {...}
Aug 04 2009
prev sibling parent Benji Smith <dlanguage benjismith.net> writes:
Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 I think it's funny that for a week, Andrei has been arguing against
 throwing around new syntax to solve this problem, and that's exactly
 what you guys have come up with.  Really, how much more complicated
 would this make the parser, compared to adding a new attribute?

We couldn't find a good solution without adding new syntax, so this is now on the table. Adding syntax or keywords is the next thing to look at. I'd still be unsatisfied if: (a) there would be significant syntactic noise to defining a read-only property (b) we had to add a keyword Andrei

The nice thing about a keyword (or an attribute) is that it's greppable. Syntax, not so much. --b
Aug 03 2009
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Jarrett Billingsley wrote:
 I think it's funny that for a week, Andrei has been arguing against
 throwing around new syntax to solve this problem, and that's exactly
 what you guys have come up with.

That's in the nature of debating in order to try to figure out the best solution. It's hard to think of all the ramifications, positives, negatives, and corner cases all at the same time.
 Really, how much more complicated
 would this make the parser, compared to adding a new attribute?

Neither of these proposals is a particular problem for the parser.
Aug 02 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Jarrett Billingsley wrote:
 What about my other points?  Do you have a response?

I talked with Derek about the same issue. He pointed out cases where the principles conflicted with the actual design. I replied that in real engineering work, *everything* is a compromise between multiple competing principles. For example, auto company executives will say that "safety is our top priority." Of course it isn't, as such a principle will produce unusable cars that cannot move an inch. The art of engineering, and it is an art, is to balance the competing principles and find the best compromise. It's not a binary thing - violating principle A over here is in no way saying A is worthless, and is not a justification for violating it over there.
 I almost had
 trouble believing this proposal wasn't a joke, given how contrived and
 unintuitive it is.  Shouldn't that be an important consideration?

Of course it is important. It is far from the only consideration, though. Someone changing their mind about something after extensive debate is a good indication they are engaging in an honest and productive discussion.
Aug 02 2009
prev sibling parent grauzone <none example.net> writes:
 I think this feels like a desperate grasping-at-straws attempt to not
 add a keyword (even though pure, nothrow, shared, __gshared, and
 immutable all seem to have made it in without any great fanfare).

Don't forget the introduction of ref and macro, which broke backwards compatibility in D1. macro is still unused in both D1 and D2. Comedy.
Aug 02 2009
prev sibling next sibling parent Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:

 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.

I have not been following the property discussion. As far as syntactic ambiguities, is there anything else besides returning a delegate? If proprties are added to D, will a class designer decide when parenthesis should be added/omitted for zero argument functions?
Aug 02 2009
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 03:43:43 -0400, Walter Bright <newshound1 digitalmars.com> said:

 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
    bool empty { ... }
    void empty=(bool b) { ... }

Looking at it more carefully, this looks like an invitation to omit parenthesis for functions with no argument. I mean, look at this and tell me what it is? T transform { ... } Is this a transform property (returning and affine transform) or an action function returning transform? I'd guess it's a property since it has no parenthesis, but nothing makes this very clear. And could you do this? Would Andrei be tempted by this? void popFront { ... } Note that I'm brigning this as an observation. Style guidelines can be written mandating parenthesis for actions functions, which means my problem of writing a coherent naming guideline is solved. But who read the style guidelines? While I like this syntax, the "getProperty()"/"setProperty()" syntax (and also the "property" keyword syntax) has one advantage over this one: it forces the interface to explicitly say "this is a getter/setter" or "this is a property", which I expect would reduce abuses. It's the same difference between as "opAdd" vs. "op+". -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 02 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michel Fortin wrote:
 On 2009-08-02 03:43:43 -0400, Walter Bright <newshound1 digitalmars.com> 
 said:
 
 The alternative is to have a unique syntax for properties. Ideally, 
 the syntax should be intuitive and mimic its use. After much fiddling, 
 and based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

Looking at it more carefully, this looks like an invitation to omit parenthesis for functions with no argument. I mean, look at this and tell me what it is? T transform { ... } Is this a transform property (returning and affine transform) or an action function returning transform? I'd guess it's a property since it has no parenthesis, but nothing makes this very clear. And could you do this? Would Andrei be tempted by this? void popFront { ... }

Good point! I continue to be unhappy about the designer having to think about inconsequentials like this.
 Note that I'm brigning this as an observation. Style guidelines can be 
 written mandating parenthesis for actions functions, which means my 
 problem of writing a coherent naming guideline is solved. But who read 
 the style guidelines?

Yes, yes, excellent point.
 While I like this syntax, the "getProperty()"/"setProperty()" syntax 
 (and also the "property" keyword syntax) has one advantage over this 
 one: it forces the interface to explicitly say "this is a getter/setter" 
 or "this is a property", which I expect would reduce abuses. It's the 
 same difference between as "opAdd" vs. "op+".

Walter made a compiler writer's point - now many symbols would have to be looked up twice instead of once. That is quite out of sync with everything else in the language. Andrei
Aug 02 2009
prev sibling next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sun, 02 Aug 2009 09:39:41 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2009-08-02 03:43:43 -0400, Walter Bright <newshound1 digitalmars.com>  
 said:

 The alternative is to have a unique syntax for properties. Ideally, the  
 syntax should be intuitive and mimic its use. After much fiddling, and  
 based on n.g. suggestions, Andrei and I penciled in:
     bool empty { ... }
    void empty=(bool b) { ... }

Looking at it more carefully, this looks like an invitation to omit parenthesis for functions with no argument. I mean, look at this and tell me what it is? T transform { ... } Is this a transform property (returning and affine transform) or an action function returning transform? I'd guess it's a property since it has no parenthesis, but nothing makes this very clear. And could you do this? Would Andrei be tempted by this? void popFront { ... } Note that I'm brigning this as an observation. Style guidelines can be written mandating parenthesis for actions functions, which means my problem of writing a coherent naming guideline is solved. But who read the style guidelines? While I like this syntax, the "getProperty()"/"setProperty()" syntax (and also the "property" keyword syntax) has one advantage over this one: it forces the interface to explicitly say "this is a getter/setter" or "this is a property", which I expect would reduce abuses. It's the same difference between as "opAdd" vs. "op+".

I also like the idea of omitting parenthesis for functions with no argument.
Aug 02 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 20:18:51 -0400, "Robert Jacques" <sandford jhu.edu> said:

 I also like the idea of omitting parenthesis for functions with no  argument.

I like it too. But the problem with the current approach D are: 1. A syntax that permits function to be called both without and with empty parenthesis creates ambiguities when it returns a callable type (a delegate or an object with an opCall member). 2. We want properties to be nouns, and actions to be verbs. In english a lot of words are both nouns and verbs, which makes it impractical to distinguish a property from a function by its name alone. Solving 1 involves having a way to say functions that can and must be called without parenthesis. Unless we want to force all functions with no parameter to be called without "()", we must have some kind of flag to tell us that a function expects or does not expect "()". Solving 2 involves making a difference in the call syntax between property and action functions. Since the idea behind a property is to mimic a field, it follows that the best differentiator for properties is the lack of parenthesis. I'd be glad too if we could continue to skip parenthesis for calls to functions with no arguments, but I think fixing the two problems above is more important. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 02 2009
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-02 23:19:50 -0400, "Robert Jacques" <sandford jhu.edu> said:

 On Sun, 02 Aug 2009 20:53:35 -0400, Michel Fortin  
 <michel.fortin michelf.com> wrote:
 
 On 2009-08-02 20:18:51 -0400, "Robert Jacques" <sandford jhu.edu> said:
 
 I also like the idea of omitting parenthesis for functions with no   argument.

I like it too. But the problem with the current approach D are: 1. A syntax that permits function to be called both without and with empty parenthesis creates ambiguities when it returns a callable type (a delegate or an object with an opCall member). 2. We want properties to be nouns, and actions to be verbs. In english a lot of words are both nouns and verbs, which makes it impractical to distinguish a property from a function by its name alone. Solving 1 involves having a way to say functions that can and must be called without parenthesis. Unless we want to force all functions with no parameter to be called without "()", we must have some kind of flag to tell us that a function expects or does not expect "()". Solving 2 involves making a difference in the call syntax between property and action functions. Since the idea behind a property is to mimic a field, it follows that the best differentiator for properties is the lack of parenthesis. I'd be glad too if we could continue to skip parenthesis for calls to functions with no arguments, but I think fixing the two problems above is more important.

I agree 1) is an issue, but I view it as a corner case. (I use zero/one arg functions all the time and make use of the 'property' syntax left right and center, but I've never run into the opCall problem) It would be nice if it were fixed, but we may be cutting off the nose to spite the face, as it were. (Or alternatively, taking the scientific instead of engineering approach) Problem 2) I think is a major logical flaw: a property is a function. So I see no need to distinguish between the two. Properties, in fact, can be a very expensive functions that takes locks/do database lock-up/etc. So making syntax changes that make 'properties' look cheap and 'functions' look expensive is worse than what we have today. Today, at least, everyone knows that no parenthesis doesn't mean necessarily cheap O(1) operation.

And I agree with you: properties are functions. But problem number 2 isn't about whether properties are functions or not. It's about the meaning of a name. Say you have a "transform" function, you'll have some expectations about what it does based on the name. So I ask you: is a "transform" function an *action* (a verb) in the sense that it applies some transformation to an object, or is it a *property* (a noun or adjective) in the sense that it returns something like an affine transform associated with an object? The semantics of the two are completely different, yet they share the same name. The real ambiguity here is the English language, were many nouns and adjectives are also verbs. We could switch to a natural language that does not have this problem for function name -- say French: "transform" becomes "transformer" (action, verb) or "transformation" (property, noun); "empty" becomes "vider" (action, verb) or "vide" (property, adjective) -- but that doesn't seem like a very practical option. So, beside switching to a non-English language, we have two other options. First we could write a guideline saying properties (nouns and adjectives) should start with some prefix. I tried it[1]. I couldn't come with anything sane that works for non-boolean properties. In addition, most people don't read guidelines, and educating people to write "is", "has" or a modal verb in front of boolean properties would be a major effort. It works in Objective-C, but Objective-C function naming conventions are very different. [1]: http://prowiki.org/wiki4d/wiki.cgi?DProgrammingGuidelines So the only option left, assuming we still want to solve the problem, is to introduce a formal syntax in D to distinguish properties (nouns and adjectives) from actions (verbs). A natural fit for that at the call site is to use the syntax without tailing empty parenthesis for properties, mimicking fields, and use the inherited function syntax from C-derived languages for actions. Choosing the right syntax for property definitions is a greater challenge since we want a simple syntax that helps people make the right choice depending on wether they want a property or an action, but we (Andrei, me, some others) don't want to deviate too much from a regular function either. As for whether properties should be cheap (not perform anything heavyweight) or not, that's another debate result in a guideline. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 03 2009
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-03 10:39:17 -0400, "Robert Jacques" <sandford jhu.edu> said:

 Thank you for the very elegant expression of the problem and for 
 posting  the programming guidelines wiki. My criticism is that you're 
 defining your  context to narrowly. A function/property/field isn't 
 just defined by it's  name, but also by it's type and the context it's 
 in. A 'transform' of type  void or typeof(this) is obviously an action, 
 while a 'transform' of type  Matrix might be a coordinate frame. The 
 object's type also conveys context  information; a 'transform' on an 
 autobot might be an action, while a  'transform' on it's 3D model might 
 be a coordinate frame. Even if you  don't know the return type off the 
 top of you're head (i.e. you're doing a  code review), 'transform;' or 
 'object.transform;' are obviously actions  while 'auto a = 
 object.transform;' or 'object.transform = a' is a noun.  English solves 
 it language ambiguity issues with context, so why can't the  same 
 solution apply to programming languages? Sure, pathological examples  
 are possible, just as they're possible in English, but that's no reason 
 to  switch to a different language.

Interesting remark. You're right of course about the transform example is much clearer in context. I'll conceed that point. But take note you let the user of the API do the disambiguation instead of the designer who wrote the function in the first place. I believe the later is better placed to decide. That said, it's rather a minor point in my opinion. I'm more concerned by the ambiguity when returning callable objects or delegates when functions have omittable parentheses. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 03 2009
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-08-03 10:06:23 -0400, "Robert Jacques" <sandford jhu.edu> said:

 On Mon, 03 Aug 2009 00:27:45 -0400, Nick Sabalausky <a a.a> wrote:
 
 "Robert Jacques" <sandford jhu.edu> wrote in message
 news:op.ux2gvcvi26stm6 sandford.myhome.westell.com...
 
 I agree 1) is an issue, but I view it as a corner case. (I use zero/one
 arg functions all the time and make use of the 'property' syntax left
 right and center, but I've never run into the opCall problem) It would  be
 nice if it were fixed, but we may be cutting off the nose to spite the
 face, as it were. (Or alternatively, taking the scientific instead of
 engineering approach)
 

It'll become a major PITA when D gets used for heavy functional-style stuff.

Maybe. But how often will people return zero-argument opCalls (function pointers/delegates/structs) from zero-argument functions? (i.e. how often do you run into this today?)

The compiler isn't as smart as you think. This doesn't compile, it requires an empty pair of parenthesis: void delegate(int) func(); func(1); And I somewhat doubt it should be smart enough for this, because if you then add a overloaded function "func" that takes an int you're silently chaning the meaning of the code. Solve this for fun: void delegate() func(int); void delegate(int) func(); func(1); // which one? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 03 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Sun, 02 Aug 2009 20:53:35 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2009-08-02 20:18:51 -0400, "Robert Jacques" <sandford jhu.edu> said:

 I also like the idea of omitting parenthesis for functions with no   
 argument.

I like it too. But the problem with the current approach D are: 1. A syntax that permits function to be called both without and with empty parenthesis creates ambiguities when it returns a callable type (a delegate or an object with an opCall member). 2. We want properties to be nouns, and actions to be verbs. In english a lot of words are both nouns and verbs, which makes it impractical to distinguish a property from a function by its name alone. Solving 1 involves having a way to say functions that can and must be called without parenthesis. Unless we want to force all functions with no parameter to be called without "()", we must have some kind of flag to tell us that a function expects or does not expect "()". Solving 2 involves making a difference in the call syntax between property and action functions. Since the idea behind a property is to mimic a field, it follows that the best differentiator for properties is the lack of parenthesis. I'd be glad too if we could continue to skip parenthesis for calls to functions with no arguments, but I think fixing the two problems above is more important.

I agree 1) is an issue, but I view it as a corner case. (I use zero/one arg functions all the time and make use of the 'property' syntax left right and center, but I've never run into the opCall problem) It would be nice if it were fixed, but we may be cutting off the nose to spite the face, as it were. (Or alternatively, taking the scientific instead of engineering approach) Problem 2) I think is a major logical flaw: a property is a function. So I see no need to distinguish between the two. Properties, in fact, can be a very expensive functions that takes locks/do database lock-up/etc. So making syntax changes that make 'properties' look cheap and 'functions' look expensive is worse than what we have today. Today, at least, everyone knows that no parenthesis doesn't mean necessarily cheap O(1) operation. Solution 1 is what I thought you were proposing. Again, I like it, though it does make zero-arg function pointers and delegates behave differently than other functions. And disallowing free_function = expression; would also address another concern many people have expressed. (Strangely enough, using the invalid code snippet: writeln = 5)
Aug 02 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 03 Aug 2009 00:27:45 -0400, Nick Sabalausky <a a.a> wrote:

 "Robert Jacques" <sandford jhu.edu> wrote in message
 news:op.ux2gvcvi26stm6 sandford.myhome.westell.com...
 I agree 1) is an issue, but I view it as a corner case. (I use zero/one
 arg functions all the time and make use of the 'property' syntax left
 right and center, but I've never run into the opCall problem) It would  
 be
 nice if it were fixed, but we may be cutting off the nose to spite the
 face, as it were. (Or alternatively, taking the scientific instead of
 engineering approach)

It'll become a major PITA when D gets used for heavy functional-style stuff.

Maybe. But how often will people return zero-argument opCalls (function pointers/delegates/structs) from zero-argument functions? (i.e. how often do you run into this today?)
Aug 03 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 03 Aug 2009 07:04:52 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2009-08-02 23:19:50 -0400, "Robert Jacques" <sandford jhu.edu> said:

 On Sun, 02 Aug 2009 20:53:35 -0400, Michel Fortin   
 <michel.fortin michelf.com> wrote:

 On 2009-08-02 20:18:51 -0400, "Robert Jacques" <sandford jhu.edu> said:

 I also like the idea of omitting parenthesis for functions with no    
 argument.

1. A syntax that permits function to be called both without and with empty parenthesis creates ambiguities when it returns a callable type (a delegate or an object with an opCall member). 2. We want properties to be nouns, and actions to be verbs. In english a lot of words are both nouns and verbs, which makes it impractical to distinguish a property from a function by its name alone. Solving 1 involves having a way to say functions that can and must be called without parenthesis. Unless we want to force all functions with no parameter to be called without "()", we must have some kind of flag to tell us that a function expects or does not expect "()". Solving 2 involves making a difference in the call syntax between property and action functions. Since the idea behind a property is to mimic a field, it follows that the best differentiator for properties is the lack of parenthesis. I'd be glad too if we could continue to skip parenthesis for calls to functions with no arguments, but I think fixing the two problems above is more important.

zero/one arg functions all the time and make use of the 'property' syntax left right and center, but I've never run into the opCall problem) It would be nice if it were fixed, but we may be cutting off the nose to spite the face, as it were. (Or alternatively, taking the scientific instead of engineering approach) Problem 2) I think is a major logical flaw: a property is a function. So I see no need to distinguish between the two. Properties, in fact, can be a very expensive functions that takes locks/do database lock-up/etc. So making syntax changes that make 'properties' look cheap and 'functions' look expensive is worse than what we have today. Today, at least, everyone knows that no parenthesis doesn't mean necessarily cheap O(1) operation.

And I agree with you: properties are functions. But problem number 2 isn't about whether properties are functions or not. It's about the meaning of a name. Say you have a "transform" function, you'll have some expectations about what it does based on the name. So I ask you: is a "transform" function an *action* (a verb) in the sense that it applies some transformation to an object, or is it a *property* (a noun or adjective) in the sense that it returns something like an affine transform associated with an object? The semantics of the two are completely different, yet they share the same name. The real ambiguity here is the English language, were many nouns and adjectives are also verbs. We could switch to a natural language that does not have this problem for function name -- say French: "transform" becomes "transformer" (action, verb) or "transformation" (property, noun); "empty" becomes "vider" (action, verb) or "vide" (property, adjective) -- but that doesn't seem like a very practical option. So, beside switching to a non-English language, we have two other options. First we could write a guideline saying properties (nouns and adjectives) should start with some prefix. I tried it[1]. I couldn't come with anything sane that works for non-boolean properties. In addition, most people don't read guidelines, and educating people to write "is", "has" or a modal verb in front of boolean properties would be a major effort. It works in Objective-C, but Objective-C function naming conventions are very different. [1]: http://prowiki.org/wiki4d/wiki.cgi?DProgrammingGuidelines So the only option left, assuming we still want to solve the problem, is to introduce a formal syntax in D to distinguish properties (nouns and adjectives) from actions (verbs). A natural fit for that at the call site is to use the syntax without tailing empty parenthesis for properties, mimicking fields, and use the inherited function syntax from C-derived languages for actions. Choosing the right syntax for property definitions is a greater challenge since we want a simple syntax that helps people make the right choice depending on wether they want a property or an action, but we (Andrei, me, some others) don't want to deviate too much from a regular function either. As for whether properties should be cheap (not perform anything heavyweight) or not, that's another debate result in a guideline.

Thank you for the very elegant expression of the problem and for posting the programming guidelines wiki. My criticism is that you're defining your context to narrowly. A function/property/field isn't just defined by it's name, but also by it's type and the context it's in. A 'transform' of type void or typeof(this) is obviously an action, while a 'transform' of type Matrix might be a coordinate frame. The object's type also conveys context information; a 'transform' on an autobot might be an action, while a 'transform' on it's 3D model might be a coordinate frame. Even if you don't know the return type off the top of you're head (i.e. you're doing a code review), 'transform;' or 'object.transform;' are obviously actions while 'auto a = object.transform;' or 'object.transform = a' is a noun. English solves it language ambiguity issues with context, so why can't the same solution apply to programming languages? Sure, pathological examples are possible, just as they're possible in English, but that's no reason to switch to a different language.
Aug 03 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 03 Aug 2009 11:42:51 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2009-08-03 10:06:23 -0400, "Robert Jacques" <sandford jhu.edu> said:

 On Mon, 03 Aug 2009 00:27:45 -0400, Nick Sabalausky <a a.a> wrote:

 "Robert Jacques" <sandford jhu.edu> wrote in message
 news:op.ux2gvcvi26stm6 sandford.myhome.westell.com...
  I agree 1) is an issue, but I view it as a corner case. (I use  
 zero/one
 arg functions all the time and make use of the 'property' syntax left
 right and center, but I've never run into the opCall problem) It  
 would  be
 nice if it were fixed, but we may be cutting off the nose to spite the
 face, as it were. (Or alternatively, taking the scientific instead of
 engineering approach)

functional-style stuff.

(function pointers/delegates/structs) from zero-argument functions? (i.e. how often do you run into this today?)

The compiler isn't as smart as you think. This doesn't compile, it requires an empty pair of parenthesis: void delegate(int) func(); func(1); And I somewhat doubt it should be smart enough for this, because if you then add a overloaded function "func" that takes an int you're silently chaning the meaning of the code. Solve this for fun: void delegate() func(int); void delegate(int) func(); func(1); // which one?

Ah. Thank you for the informative post. That is a fairly big deficiency. However, isn't that really a bug? There's a similar one with ref return properties. According to the spec, there's nothing (I think) preventing DMD from doing the right thing. As for your example, 'void delegate() func(int);' would end up being called. But it's pretty obvious 'void delegate(int) func();' was meant. This particular example looks very pathological, if both funcs are part of the same module. Ultimately, this is just another form of function hijacking. Detecting this would require all combinations of call variations to enter into the lookup tree, but from there it's trivial to detect a collision, and issue an error. That would work for both out of module and in module double definitions. I don't know how difficult that is for the compiler, but it sounds fairly straight-forward.
Aug 03 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 03 Aug 2009 11:57:40 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2009-08-03 10:39:17 -0400, "Robert Jacques" <sandford jhu.edu> said:

 Thank you for the very elegant expression of the problem and for  
 posting  the programming guidelines wiki. My criticism is that you're  
 defining your  context to narrowly. A function/property/field isn't  
 just defined by it's  name, but also by it's type and the context it's  
 in. A 'transform' of type  void or typeof(this) is obviously an action,  
 while a 'transform' of type  Matrix might be a coordinate frame. The  
 object's type also conveys context  information; a 'transform' on an  
 autobot might be an action, while a  'transform' on it's 3D model might  
 be a coordinate frame. Even if you  don't know the return type off the  
 top of you're head (i.e. you're doing a  code review), 'transform;' or  
 'object.transform;' are obviously actions  while 'auto a =  
 object.transform;' or 'object.transform = a' is a noun.  English solves  
 it language ambiguity issues with context, so why can't the  same  
 solution apply to programming languages? Sure, pathological examples   
 are possible, just as they're possible in English, but that's no reason  
 to  switch to a different language.

Interesting remark. You're right of course about the transform example is much clearer in context. I'll conceed that point. But take note you let the user of the API do the disambiguation instead of the designer who wrote the function in the first place. I believe the later is better placed to decide. That said, it's rather a minor point in my opinion. I'm more concerned by the ambiguity when returning callable objects or delegates when functions have omittable parentheses.

I believe in a systems language, the default should be to user choice. That said, having a way for an api designer to enforce a particular usage, isn't necessarily bad thing either. The lack of an either-or/flexible option is, in my opinion, a flaw in all of the proposals so far.
Aug 03 2009
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 03 Aug 2009 21:32:25 -0400, Robert Jacques <sandford jhu.edu>  
wrote:
 On Mon, 03 Aug 2009 11:42:51 -0400, Michel Fortin  
 <michel.fortin michelf.com> wrote:

 On 2009-08-03 10:06:23 -0400, "Robert Jacques" <sandford jhu.edu> said:

 On Mon, 03 Aug 2009 00:27:45 -0400, Nick Sabalausky <a a.a> wrote:

 "Robert Jacques" <sandford jhu.edu> wrote in message
 news:op.ux2gvcvi26stm6 sandford.myhome.westell.com...
  I agree 1) is an issue, but I view it as a corner case. (I use  
 zero/one
 arg functions all the time and make use of the 'property' syntax left
 right and center, but I've never run into the opCall problem) It  
 would  be
 nice if it were fixed, but we may be cutting off the nose to spite  
 the
 face, as it were. (Or alternatively, taking the scientific instead of
 engineering approach)

functional-style stuff.

(function pointers/delegates/structs) from zero-argument functions? (i.e. how often do you run into this today?)

The compiler isn't as smart as you think. This doesn't compile, it requires an empty pair of parenthesis: void delegate(int) func(); func(1); And I somewhat doubt it should be smart enough for this, because if you then add a overloaded function "func" that takes an int you're silently chaning the meaning of the code. Solve this for fun: void delegate() func(int); void delegate(int) func(); func(1); // which one?

Ah. Thank you for the informative post. That is a fairly big deficiency. However, isn't that really a bug? There's a similar one with ref return properties. According to the spec, there's nothing (I think) preventing DMD from doing the right thing. As for your example, 'void delegate() func(int);' would end up being called. But it's pretty obvious 'void delegate(int) func();' was meant. This particular example looks very pathological, if both funcs are part of the same module. Ultimately, this is just another form of function hijacking. Detecting this would require all combinations of call variations to enter into the lookup tree, but from there it's trivial to detect a collision, and issue an error. That would work for both out of module and in module double definitions. I don't know how difficult that is for the compiler, but it sounds fairly straight-forward.

I just found the related bugs in bugzilla: http://d.puremagic.com/issues/show_bug.cgi?id=2409 http://d.puremagic.com/issues/show_bug.cgi?id=2152 http://d.puremagic.com/issues/show_bug.cgi?id=2159
Aug 03 2009
prev sibling next sibling parent reply Marianne Gagnon <auria.mg gmail.com> writes:
 
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
    bool empty { ... }
    void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
    bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
    bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I liked the original idea... but this declaration syntax is a total can of worms. Like others pointed out, would the compiler automatically turn all functions with empty bodies into declarations? Would empty setters be considered a declaration? What if I actually *want* to use an empty body as definition? Or what if I accidentally leave a body empty when I didn't want to? Like someone else pointed out, existing keywords could be reused : bool empty { in(bool value) { _my_empty = value; } out { return _my_empty; } } I like this quite a bit. I never wrote any compiler, granted, but I don't think it'd be that hard to implement - and doesn't introduce any new keyword. Or, alternatively, if you really wish to keep them separate, bool empty= { ... } isn't intuitive, as Andrei pointed out, but is already less error-prone than the empty-body declaration idea I believe
Aug 02 2009
next sibling parent John C <johnch_atms hotmail.com> writes:
Marianne Gagnon wrote:
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I liked the original idea... but this declaration syntax is a total can of worms. Like others pointed out, would the compiler automatically turn all functions with empty bodies into declarations? Would empty setters be considered a declaration? What if I actually *want* to use an empty body as definition? Or what if I accidentally leave a body empty when I didn't want to? Like someone else pointed out, existing keywords could be reused : bool empty { in(bool value) { _my_empty = value; } out { return _my_empty; } } I like this quite a bit. I never wrote any compiler, granted, but I don't think it'd be that hard to implement - and doesn't introduce any new keyword.

I'd be more than happy with that.
 
 Or, alternatively, if you really wish to keep them separate, bool empty= { ...
} isn't intuitive, as Andrei pointed out, but is already less error-prone than
the empty-body declaration idea I believe

Aug 02 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Marianne Gagnon wrote:
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I liked the original idea... but this declaration syntax is a total can of worms. Like others pointed out, would the compiler automatically turn all functions with empty bodies into declarations? Would empty setters be considered a declaration? What if I actually *want* to use an empty body as definition? Or what if I accidentally leave a body empty when I didn't want to? Like someone else pointed out, existing keywords could be reused : bool empty { in(bool value) { _my_empty = value; } out { return _my_empty; } } I like this quite a bit. I never wrote any compiler, granted, but I don't think it'd be that hard to implement - and doesn't introduce any new keyword.

Please, please, could we look at something that does NOT go through two scopes to get to the code?
 Or, alternatively, if you really wish to keep them separate, bool empty= { ...
} isn't intuitive, as Andrei pointed out, but is already less error-prone than
the empty-body declaration idea I believe

I think void empty=(bool b) { ... } is a net win, which the forced bool empty=() diminishes. It would be great to keep the setter and find something as nice for a getter. Andrei
Aug 02 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Andrei Alexandrescu escribió:
 Marianne Gagnon wrote:
 The alternative is to have a unique syntax for properties. Ideally, 
 the syntax should be intuitive and mimic its use. After much 
 fiddling, and based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I liked the original idea... but this declaration syntax is a total can of worms. Like others pointed out, would the compiler automatically turn all functions with empty bodies into declarations? Would empty setters be considered a declaration? What if I actually *want* to use an empty body as definition? Or what if I accidentally leave a body empty when I didn't want to? Like someone else pointed out, existing keywords could be reused : bool empty { in(bool value) { _my_empty = value; } out { return _my_empty; } } I like this quite a bit. I never wrote any compiler, granted, but I don't think it'd be that hard to implement - and doesn't introduce any new keyword.

Please, please, could we look at something that does NOT go through two scopes to get to the code?
 Or, alternatively, if you really wish to keep them separate, bool 
 empty= { ... } isn't intuitive, as Andrei pointed out, but is already 
 less error-prone than the empty-body declaration idea I believe

I think void empty=(bool b) { ... } is a net win, which the forced bool empty=() diminishes. It would be great to keep the setter and find something as nice for a getter. Andrei

int =empty() { } // getter int empty=(int value) { } // setter
Aug 02 2009
next sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
Ary Borenszweig escribió:
 Andrei Alexandrescu escribió:
 Marianne Gagnon wrote:
 The alternative is to have a unique syntax for properties. Ideally, 
 the syntax should be intuitive and mimic its use. After much 
 fiddling, and based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I liked the original idea... but this declaration syntax is a total can of worms. Like others pointed out, would the compiler automatically turn all functions with empty bodies into declarations? Would empty setters be considered a declaration? What if I actually *want* to use an empty body as definition? Or what if I accidentally leave a body empty when I didn't want to? Like someone else pointed out, existing keywords could be reused : bool empty { in(bool value) { _my_empty = value; } out { return _my_empty; } } I like this quite a bit. I never wrote any compiler, granted, but I don't think it'd be that hard to implement - and doesn't introduce any new keyword.

Please, please, could we look at something that does NOT go through two scopes to get to the code?
 Or, alternatively, if you really wish to keep them separate, bool 
 empty= { ... } isn't intuitive, as Andrei pointed out, but is already 
 less error-prone than the empty-body declaration idea I believe

I think void empty=(bool b) { ... } is a net win, which the forced bool empty=() diminishes. It would be great to keep the setter and find something as nice for a getter. Andrei

int =empty() { } // getter int empty=(int value) { } // setter

Hmm... where's the "undo send" button? I can't find it... I saw it in gmail, but why isn't it here?
Aug 02 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Ary Borenszweig wrote:
 Andrei Alexandrescu escribió:
 Marianne Gagnon wrote:
 The alternative is to have a unique syntax for properties. Ideally, 
 the syntax should be intuitive and mimic its use. After much 
 fiddling, and based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I liked the original idea... but this declaration syntax is a total can of worms. Like others pointed out, would the compiler automatically turn all functions with empty bodies into declarations? Would empty setters be considered a declaration? What if I actually *want* to use an empty body as definition? Or what if I accidentally leave a body empty when I didn't want to? Like someone else pointed out, existing keywords could be reused : bool empty { in(bool value) { _my_empty = value; } out { return _my_empty; } } I like this quite a bit. I never wrote any compiler, granted, but I don't think it'd be that hard to implement - and doesn't introduce any new keyword.

Please, please, could we look at something that does NOT go through two scopes to get to the code?
 Or, alternatively, if you really wish to keep them separate, bool 
 empty= { ... } isn't intuitive, as Andrei pointed out, but is already 
 less error-prone than the empty-body declaration idea I believe

I think void empty=(bool b) { ... } is a net win, which the forced bool empty=() diminishes. It would be great to keep the setter and find something as nice for a getter. Andrei

int =empty() { } // getter

I suggested that but Walter mentioned there may be parsing problems when int is replaced with an elaborate type. (I am not seeing any.) Andrei
Aug 02 2009
prev sibling next sibling parent Marianne Gagnon <auria.mg gmail.com> writes:
Andrei Alexandrescu Wrote:
 Marianne Gagnon wrote:
 Or, alternatively, if you really wish to keep them separate, bool empty= { ...
} isn't intuitive, as Andrei pointed out, but is already less error-prone than
the empty-body declaration idea I believe

I think void empty=(bool b) { ... } is a net win, which the forced bool empty=() diminishes. It would be great to keep the setter and find something as nice for a getter.

If { ... } becomes the new standard way of declaring a function, that's fine with me; but if { ... } ended up being used only for properties, that would be somewhat inconsistent
Aug 02 2009
prev sibling parent Marianne Gagnon <auria.mg gmail.com> writes:
Ah, and also :

Andrei Alexandrescu Wrote:

 Marianne Gagnon wrote:
 Like someone else pointed out, existing keywords could be reused :
 
 bool empty
 {
     in(bool value)
     {
         _my_empty = value;
     }
     out
     {
         return _my_empty;
     }
 }
 
 I like this quite a bit.  I never wrote any compiler, granted, but I don't
think it'd be that hard to implement - and doesn't introduce any new keyword.

Please, please, could we look at something that does NOT go through two scopes to get to the code?

Sure, that was just an exampel of keyword re-use, you can do the exact same without scores : out int foo() { return m_foo; } in int foo(int value) { m_foo = foo; } Many variations possible on this theme ;) So not wanting a new keyword is not a show-stopper for solutions involving the use of keywords, in and out can be used there with no ambiguity i can think of (maybe others will though)
Aug 02 2009
prev sibling next sibling parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Walter Bright wrote:
 Having optional parentheses does lead to unresolvable ambiguities. How
 much of a problem that really is is debatable, but let's assume it
 should be resolved. To resolve it, a property must be distinguishable
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
   property bool empty() { ... }
   property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things
 
 The alternative is to have a unique syntax for properties. Ideally, the
 syntax should be intuitive and mimic its use. After much fiddling, and
 based on n.g. suggestions, Andrei and I penciled in:
 
   bool empty { ... }
   void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
   bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
   bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I don't mind the syntax myself. I'm even sorta surprised the ng responded to it with such negativity. What I care more about is that some kind of rewriting rules are implemented on expressions that undergo some kind of mutation. The important thing being that whenever a property is mutated or a (possibly indirect) member of a property is mutated, then the setter is guaranteed to be invoked. This is the only way I've read so far to make things like "array.length++;" work without hacky things like proxy structs with exhaustive operator overloading, or exhaustive overload defining in the property itself. I'll put examples of the rewriting here, including a couple extras I've found. //================ // The basics; property member mutation: a.b.c = 3; // rewritten as auto t = a.b; t.c = 3; a.b = t; //================ // Deeper nesting: a.b.c.d = 3; // rewritten as auto t2 = a.b; auto t1 = t2.c; t1.d = 3; t2.c = t1; a.b = t2; //================ // Direct property mutations (++,--,+=,-=,*=,etc): a.b++; // rewritten as auto t = a.b; t++; a.b = t; //================ // More direct mutations a.b.c += 42; // rewritten as auto t2 = a.b; auto t1 = t2.c; t1 += 42; t2.c = t1; a.b = t2; //================ // Complicated lvalues: s[s.length ++] = foo; // rewritten as auto t = s.length; t++; s[(s.length = t)] = foo; // Yes this will make a bounds error. They totally deserve it ;) // If this is unacceptable, then more complicated rules could be created // for operations like ++ and -- that are calculated after being read. // The expression would have to be evaluated with the getter's value, // then the setter would be called after the temporary is mutated. // Like so: auto t = s.length; s[t] = foo; t++; s.length = t; //================ // Unary Expressions: class Foo { int count(){ return cnt++; } } Foo aFoo = new Foo; int i = aFoo.count++; //i = ? // rewritten as auto t = aFoo.count; t++; int i = (aFoo.count = t); //================ // rvalues such as a.b.c.d are /not/ rewritten: int foo = a.b.c.d; // a.b.c.d is not being mutated in any way, only read. //=========== [end] One interesting thing I realized about this is that you can probably apply this without special property syntax. With omissible parentheses and expression rewrites, almost everything would just work. /almost/. Yes, delegates would still be given the short end due to the parentheses ambiguity. Oh, and it would still be difficult/impossible for IDEs to determine which things are properties and which are not. Also, you'd be able to migrate fields to properties but not the other way around. If you were willing to implement attribute syntax, then you could probably please almost everyone (I hope). The omissible parentheses could be left in. It would be possible to create these entities that are both functions and properties at the same time. They wouldn't be hazardous anymore. property could be used to mark a strict property declaration. Such a declaration would forbid being called with parentheses, and thus allow better enforcement of API conventions, better analysis by 3rd party tools and generative code, and allow delegates to be returned from properties. Fields could be migrated to properties or strict properties with very little API breakage, while only strict properties could be migrated to fields with (maybe) zero API breakage.
Aug 02 2009
parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Chad J wrote:
 
 If you were willing to implement attribute syntax, then you could
 probably please almost everyone (I hope).  The omissible parentheses
 could be left in.   It would be possible to create these entities that
 are both functions and properties at the same time.  They wouldn't be
 hazardous anymore.   property could be used to mark a strict property
 declaration.  Such a declaration would forbid being called with
 parentheses, and thus allow better enforcement of API conventions,
 better analysis by 3rd party tools and generative code, and allow
 delegates to be returned from properties.  Fields could be migrated to
 properties or strict  properties with very little API breakage, while
 only strict  properties could be migrated to fields with (maybe) zero
 API breakage.

I should clarify that this paragraph assumes the aforementioned expression rewriting were implemented.
Aug 02 2009
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Walter Bright wrote:
 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
   property bool empty() { ... }
   property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things
 
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
   bool empty { ... }
   void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
   bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
   bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I promised myself I'd never use this emoticon, but it's time to break that rule: <3 <3 <3 <3 Excellent solution.
Aug 02 2009
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sun, Aug 02, 2009 at 12:43:43AM -0700, Walter Bright wrote:
 What do you think?

I'd prefer to work with what we have now as much as possible without introducing new syntax. -- Adam D. Ruppe http://arsdnet.net
Aug 02 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Sun, 02 Aug 2009 03:43:43 -0400, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Having optional parentheses does lead to unresolvable ambiguities. How  
 much of a problem that really is is debatable, but let's assume it  
 should be resolved. To resolve it, a property must be distinguishable  
 from a regular function.

 One way is to simply add a "property" attribute keyword:

    property bool empty() { ... }
    property void empty(bool b) { ... }

 The problem is that:

 1. there are a lot of keywords already
 2. keywords are global things

 The alternative is to have a unique syntax for properties. Ideally, the  
 syntax should be intuitive and mimic its use. After much fiddling, and  
 based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I find the fact 'bool empty{}' has no return value very confusing. 'void empty=(bool b)' is hackish but okay, though 'typeof(this) empty=(bool b)' is more consistent with value types. I have found Omissible Parentheses (see the associated thread) to be a good thing when working with std.string and std.algorithm. In my own code, I'd end up converting any zero-parameter function to the new syntax, and greatly lament my inability to call things with default parameters without parentheses. As an alternative, I'd recommend reserving () for delegate calls, and disallow calling functions with (). That would also solve the problem, (the backwards breakage introduced would be about the same) and the only ambiguity I've though of so far is &class.func which could be resolved with &(class.func) if you want the return value's address.
Aug 02 2009
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Walter Bright escribió:
 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
   property bool empty() { ... }
   property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things
 
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
   bool empty { ... }
   void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
   bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
   bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I like this. Of course there are better solutions, but this one is the one that involves less changes in the compiler. It will also probably allow later to define things like: int property+=(int value) { ... } int property-=(int value) { ... } int property*=(int value) { ... } Of course it's very tedious to define all of these. What I'd like the compiler to do, if you don't define property+=, is to transform this: 1. foo.property += 2; into this: 2. foo.property = foo.property + 2; only if a getter is also available. And if you do define property+=, then it is rewritten into: foo.property+=(2); This allows you to optimize some things. For example in C# there's no way to do this, if I'm not wrong. Walter: what are the technical reasons for not transforming 1 into 2 already?
Aug 02 2009
next sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Ary Borenszweig wrote:
 
 What I'd like the compiler to do, if you don't define property+=, is to
 transform this:
 
 1. foo.property += 2;
 
 into this:
 
 2. foo.property = foo.property + 2;
 

Be careful. It's actually better to transform it into auto t = foo.property; t += 2; foo.property = t; The reason is because typeof(t) may have opAddAssign defined, but no definition for opAdd or opAdd_r. Other than that, I'm totally with you.
Aug 02 2009
prev sibling parent Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
Ary Borenszweig wrote:

 What I'd like the compiler to do, if you don't define property+=, is to
 transform this:
 
 1. foo.property += 2;
 
 into this:
 
 2. foo.property = foo.property + 2;

 Walter: what are the technical reasons for not transforming 1 into 2
 already?

Because there is no guarantee that += and + are implemented consistently by user-defined types (even though they should be). A better transformation, suggested by several people, is: { auto temp = foo.property; temp += 2; foo.property = temp; } -- Michiel Helvensteijn
Aug 02 2009
prev sibling next sibling parent Sergey Gromov <snake.scaly gmail.com> writes:
Sun, 02 Aug 2009 00:43:43 -0700, Walter Bright wrote:

 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.
 
 One way is to simply add a "property" attribute keyword:

 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things
 
 The alternative is to have a unique syntax for properties. Ideally, the 
 syntax should be intuitive and mimic its use. After much fiddling, and 
 based on n.g. suggestions, Andrei and I penciled in:
 
    bool empty { ... }
    void empty=(bool b) { ... }
 
 [snip]
 
    bool empty{}

I don't like this part. When I look at this syntax I think about weird corner cases which will surface sooner or later. You still didn't voice your opinion on annotations. But if you do consider them useful and think that they will get into the compiler sooner or later, I propose this solution: 1. Hack the front-end to allow ' ' in *keywords* 2. Add a " property" keyword This solution: * Cancels the "keywords are global" concern: property can never interfere with user-defined symbols * Does not add a keyword to the specs: property being a keyword is merely an implementation detail which goes away as soon as arbitrary annotations are supported by the compiler * Implementation complexity is roughly the same as for simple keyword addition which I believe is less complex than specialized syntaxes like prop=()
Aug 02 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el  2 de agosto a las 00:43 me escribiste:
 Having optional parentheses does lead to unresolvable ambiguities. How
 much of a problem that really is is debatable, but let's assume it
 should be resolved. 
 To resolve it, a property must be distinguishable from a regular function.
 
 One way is to simply add a "property" attribute keyword:
 
   property bool empty() { ... }
   property void empty(bool b) { ... }
 
 The problem is that:
 
 1. there are a lot of keywords already
 2. keywords are global things

What about DIP6 for a more general solution. DIP6 should be: 1) Easy to implement in a first basic stage 2) Backward compatible 3) Doesn't need a new keyword, even more, it will help to reduce the number of keywords in the future.
 The alternative is to have a unique syntax for properties. Ideally, the
 syntax should be intuitive and mimic its use. After much fiddling, and
 based on n.g.  suggestions, Andrei and I penciled in:
 
   bool empty { ... }
   void empty=(bool b) { ... }
 
 The only problem is when a declaration but not definition is desired:
 
   bool empty;
 
 but oops! That defines a field. So we came up with essentially a hack:
 
   bool empty{}
 
 i.e. the {} means the getter is declared, but defined elsewhere.
 
 What do you think?

I think it's a bad idea to ignore all the other proposals in this NG. Why did you dismissed the other proposals? What is better in this proposal comparing it to the others? I find this very odd, is like saying everybody is wrong except you. What's wrong with the other proposals (other than the "property" keyword proposal)? You have virtually not participated in the discussion and now you came up with a brand new syntax. That's not quite supporting the DIPs, that's more like ignoring them. Even (several) votings were done with alternative property syntax. What should we do now? Repeat all the voting again adding this one? Bummer! =( -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- I've always been mad, I know I've been mad, like the most of us... very hard to explain why you're mad, even if you're not mad...
Aug 02 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Sun, Aug 2, 2009 at 2:55 PM, Walter Bright<newshound1 digitalmars.com> wrote:
 Jarrett Billingsley wrote:
 I think it's funny that for a week, Andrei has been arguing against
 throwing around new syntax to solve this problem, and that's exactly
 what you guys have come up with.

That's in the nature of debating in order to try to figure out the best solution. It's hard to think of all the ramifications, positives, negatives, and corner cases all at the same time.
 Really, how much more complicated
 would this make the parser, compared to adding a new attribute?

Neither of these proposals is a particular problem for the parser.

What about my other points? Do you have a response? I almost had trouble believing this proposal wasn't a joke, given how contrived and unintuitive it is. Shouldn't that be an important consideration?
Aug 02 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Sun, 02 Aug 2009 12:02:22 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Jarrett Billingsley wrote:
 I think it's funny that for a week, Andrei has been arguing against
 throwing around new syntax to solve this problem, and that's exactly
 what you guys have come up with.  Really, how much more complicated
 would this make the parser, compared to adding a new attribute?

We couldn't find a good solution without adding new syntax, so this is now on the table. Adding syntax or keywords is the next thing to look at. I'd still be unsatisfied if: (a) there would be significant syntactic noise to defining a read-only property (b) we had to add a keyword Andrei

I'd also still like to be able to do stuff like this: auto data = std.file.readText(filename).chomp.split;
Aug 02 2009
prev sibling next sibling parent Rainer Deyke <rainerd eldwood.com> writes:
Nick Sabalausky wrote:
 "Walter Bright" <newshound1 digitalmars.com> wrote in message 
 news:h53g3i$elk$1 digitalmars.com...
   bool empty { ... }
   void empty=(bool b) { ... }

I think that if D starts to make a habit of aping the ugly C++ approach to adding new features (as this does), then we may as well just use C++.

'prop=' for property setters is used by Io, not C++. D already much closer to C++ than Io. (BTW, Io doesn't have operators in the same sense that C++ and D do. '+' and 'prop=' are just identifiers in Io.) -- Rainer Deyke - rainerd eldwood.com
Aug 02 2009
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Nick Sabalausky wrote:
 "Walter Bright" <newshound1 digitalmars.com> wrote in message 
 news:h53g3i$elk$1 digitalmars.com...
   bool empty { ... }
   void empty=(bool b) { ... }

 What do you think?

I think that if D starts to make a habit of aping the ugly C++ approach to adding new features (as this does), then we may as well just use C++.

Let's not forget that C++ got very conservative about adding keywords after a keyword spree (class that is essentially same as struct, namespace, xyz_cast, oh yes typename, and, or, not plus other useful names that I probably forgot). We don't want to get there. Andrei
Aug 02 2009
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 02 Aug 2009 03:43:43 -0400, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Having optional parentheses does lead to unresolvable ambiguities. How  
 much of a problem that really is is debatable, but let's assume it  
 should be resolved. To resolve it, a property must be distinguishable  
 from a regular function.

 One way is to simply add a "property" attribute keyword:

    property bool empty() { ... }
    property void empty(bool b) { ... }

 The problem is that:

 1. there are a lot of keywords already
 2. keywords are global things

 The alternative is to have a unique syntax for properties. Ideally, the  
 syntax should be intuitive and mimic its use. After much fiddling, and  
 based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I have to confess, I thought I wrote my last reply for property debate... As for the proposed syntax, the setter syntax looks acceptable, but I don't really like the getter syntax. I can't think of a really good analagous setter symbol to =. Some of the other syntaxes I've seen show promise such as: bool empty.get { ... } void empty.set(bool b) {...} One thing to consider is if it should be possible to take a delegate of a property setter or getter, how do you identify the property function itself? This solution provides an easy way: &empty.get &empty.set The only issue with this is if the type returned from the getter actually defines a get field or method. While having a method called get might be a likely possibility, having that on a type that is likely to be returned as a property is probably unlikely. There is of course a workaround: empty.get().get(); -or- auto tmp = empty; tmp.get(); to call the underlying method. Another option is to name the getter and setter something less likely to be used, such as opGet/opSet or _get/_set. Finally, you could have a renaming rule that would allow access to the function. For example empty.get translates to get_empty(), so if you called get_empty() it would call the getter. C# does something like this. Yet another option is to involve some sort of punctuation, e.g.: empty.get(); // call the returned type's get function &empty get; // delegate to the getter. Note that the only one of these that makes a lot of sense for the property keyword solution (or your solution) is the renaming empty to get_empty(). I'm glad to see that this might actually be addressed. -Steve
Aug 03 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 On Sun, 02 Aug 2009 03:43:43 -0400, Walter Bright 
 <newshound1 digitalmars.com> wrote:
 
 Having optional parentheses does lead to unresolvable ambiguities. How 
 much of a problem that really is is debatable, but let's assume it 
 should be resolved. To resolve it, a property must be distinguishable 
 from a regular function.

 One way is to simply add a "property" attribute keyword:

    property bool empty() { ... }
    property void empty(bool b) { ... }

 The problem is that:

 1. there are a lot of keywords already
 2. keywords are global things

 The alternative is to have a unique syntax for properties. Ideally, 
 the syntax should be intuitive and mimic its use. After much fiddling, 
 and based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I have to confess, I thought I wrote my last reply for property debate... As for the proposed syntax, the setter syntax looks acceptable, but I don't really like the getter syntax. I can't think of a really good analagous setter symbol to =. Some of the other syntaxes I've seen show promise such as: bool empty.get { ... } void empty.set(bool b) {...} One thing to consider is if it should be possible to take a delegate of a property setter or getter, how do you identify the property function itself? This solution provides an easy way: &empty.get &empty.set The only issue with this is if the type returned from the getter actually defines a get field or method. While having a method called get might be a likely possibility, having that on a type that is likely to be returned as a property is probably unlikely. There is of course a workaround: empty.get().get(); -or- auto tmp = empty; tmp.get(); to call the underlying method. Another option is to name the getter and setter something less likely to be used, such as opGet/opSet or _get/_set. Finally, you could have a renaming rule that would allow access to the function. For example empty.get translates to get_empty(), so if you called get_empty() it would call the getter. C# does something like this. Yet another option is to involve some sort of punctuation, e.g.: empty.get(); // call the returned type's get function &empty get; // delegate to the getter. Note that the only one of these that makes a lot of sense for the property keyword solution (or your solution) is the renaming empty to get_empty(). I'm glad to see that this might actually be addressed. -Steve

That's one place where rewriting shines :o). There's no need to even think of how to do it when properties work as get_empty() and set_empty(bool) - the means are already in the language. Andrei
Aug 03 2009
prev sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Steven Schveighoffer wrote:
 ...
 
 The only issue with this is if the type returned from the getter
 actually defines a get field or method.  While having a method called
 get might be a likely possibility, having that on a type that is likely
 to be returned as a property is probably unlikely. There is of course a
 workaround:
 
 ...
 
 -Steve

Or you could just use __traits and avoid having to invent increasingly obtuse layers of syntax.
Aug 03 2009
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 03 Aug 2009 04:13:24 -0400, KennyTM~ <kennytm gmail.com> wrote:

 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 auto data = std.file.readText(filename).chomp.split;

like we'll lose some or all of that.

meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split;

So to allow omission of the parenthesis of these "read-only properties" we do property string chomped (string x) { ... } ? I don't think Walter's syntax is capable of introducing "properties" to these free methods, but the property attribute can. (However, this may make chomped = "abcd" valid, which is not what we want.)

Why does ' chomped = "abcd" ' matter? It's a completely non-sensible statement that does absolutely nothing.
Aug 03 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 10:45:10 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Michiel Helvensteijn wrote:
 Andrei Alexandrescu wrote:

 auto data = std.file.readText(filename).chomp.split;

like we'll lose some or all of that.

meant to be read-only properties instead of functions. auto data = std.file.textFrom(filename).chomped.split;

Sure you meant: auto data = std.file.textFrom(filename).chomped.splat;

This brings up a good point. split is one of those rare words where split without parens and split() with parens mean exactly the same thing. That is, split as a property is an adjective, meaning "give me this data in a split form" , and as an adjective, split means "split this data", the result of which is the split data. So split maybe is one word that is an exception -- it's meaning is clear for both a property and a function, AND the implied meaning is the same for both. I don't think this means we should take this one exception to invalidate the whole idea of separating function from property, but maybe there could be ways to annotate such functions as callable both ways. I'm sure the number of functions that have this property is few such that the pain of annotating "call this both ways" is minimial. Or else, allow defining a property and a function with the same name (*gulp*). One thing is for certain -- I'd rather have to deal with this quandry as an author of code than deal with the ambiguity of the current design as a user of code. --------- I just thought of another issue with property definitions. How do you declare a property of an array? Today it's: char[] chomped(char[] input); Note that any getter property contains an argument which is the object you're calling the property on (normally implied because the definition is inside an aggregate definition). But with arrays it's explicit. So how does this fit in Walter's proposed syntax? char[] chomped {...} Where does the input go? -Steve
Aug 03 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 11:06:53 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 That is, split as a property is an adjective, meaning "give me this data  
 in a split form" , and as an adjective, split means "split this data",  
 the result of which is the split data.

Oops, that second part of the sentence should read split as a *verb*. -Steve
Aug 03 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 03 Aug 2009 11:24:54 -0400, Daniel Keep  
<daniel.keep.lists gmail.com> wrote:

 Steven Schveighoffer wrote:
 ...

 The only issue with this is if the type returned from the getter
 actually defines a get field or method.  While having a method called
 get might be a likely possibility, having that on a type that is likely
 to be returned as a property is probably unlikely. There is of course a
 workaround:

 ...

 -Steve

Or you could just use __traits and avoid having to invent increasingly obtuse layers of syntax.

Yes. As I said elsewhere, this has my vote. -Steve
Aug 03 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 02 Aug 2009 03:43:43 -0400, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Having optional parentheses does lead to unresolvable ambiguities. How  
 much of a problem that really is is debatable, but let's assume it  
 should be resolved. To resolve it, a property must be distinguishable  
 from a regular function.

 One way is to simply add a "property" attribute keyword:

    property bool empty() { ... }
    property void empty(bool b) { ... }

 The problem is that:

 1. there are a lot of keywords already
 2. keywords are global things

 The alternative is to have a unique syntax for properties. Ideally, the  
 syntax should be intuitive and mimic its use. After much fiddling, and  
 based on n.g. suggestions, Andrei and I penciled in:

    bool empty { ... }
    void empty=(bool b) { ... }

 The only problem is when a declaration but not definition is desired:

    bool empty;

 but oops! That defines a field. So we came up with essentially a hack:

    bool empty{}

 i.e. the {} means the getter is declared, but defined elsewhere.

 What do you think?

I stated it elsewhere, but I'll bring it up to the front. I don't think the getter syntax is viable without parentheses, since that precludes array properties, e.g.: string asUpper(string s); usage: string s = "abcde".asUpper; It wouldn't be possible to define this as a property using your syntax, unless you want to introduce a syntax for extending types... -Steve
Aug 04 2009