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

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

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

Sure you meant:

auto data = std.file.textFrom(filename).chomped.splat;

:o)


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

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

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