August 03, 2009
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/

August 03, 2009
Michiel Helvensteijn wrote:
> 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.
> 

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.)
August 03, 2009
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).
>>  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; }

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

-Steve
August 03, 2009
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
August 03, 2009
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?)
August 03, 2009
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;
>>> 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
>
> @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.
August 03, 2009
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).
>>>  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; }
> 
> 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.
August 03, 2009
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).
>>>>  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; }
>>  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.

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
August 03, 2009
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

August 03, 2009
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