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

August 02, 2009
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?