February 03, 2013
Am Sun, 03 Feb 2013 03:16:08 -0500
schrieb Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:


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

"If a function returns a reference, then assignment through the paren-less call should work: "

This is the only part where I would disagree. Why is this special rule necessary if we have full @property support? I think this would still allow too many false positives.

One important aspect that this proposal doesn't cover yet is whether we want to allow "semantic rewriting" for properties:
----
Struct a;
a.property++; //would this be legal?
----

for other corner cases this list is a good start: http://wiki.dlang.org/Property_Discussion_Wrap-up#Implementation_concerns

* Can we get a reference to the property? What does
  &x.property mean?
* How can we get the getter / setter functions? Do we need to get those?
* What is the type of the property? Return type, setter function type
  or getter function type? How to get the other types?
* What does x.property++ do?
  ([http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/Property#Semanticrewritingofproperties
  Semantic rewriting])
* Is returning ref values from the getter OK?
* Is taking ref values in the setter OK?
* Should all properties be nothrow? pure? getter const?
** Probably better as a rule for style guide.
* Are UFCS properties possible? How do they work exactly?
* How do you disambiguate property functions when they're free
  functions which conflict?
** Normal UFCS functions can be force
  called by using their fully qualified name. That's not possible for
  properties if function call syntax is disallowed?
* How many parameters are allowed for property functions?
** Are default parameters allowed?
** Especially consider the example about __FILE__ and __LINE__
* Are templated properties allowed?
** The access syntax for properties doesn't allow providing types

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

> Walter and I have had a discussion on how to finalize properties.
>
> http://wiki.dlang.org/DIP23

I agree with everything in this.  This looks exactly like what I wanted a few days ago.  Thank you!

One aspect not addressed is free-function properties:

@property int foo(int x) {return x * 5;}

could be interpreted as:

foo = 2; // not correct (for this example)

int x = 2.foo; // correct

Note that:

@property int foo();
@property void foo(int x, int y);

are both unambiguous.

==================

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

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

Therefore, if you wish to write a UFCS getter, omit the @property designation.

int foo(int x) {return x * 5;}

foo = 2; // illegal
int x = 2.foo; // OK, sets x to 10
int x = foo(2); // same as above

@property int foo(int x) {_foo = x;}

foo = 2; // OK, sets _foo to 2
int x = 2.foo; // illegal
int x = foo(2); // illegal

I know this is not a complete solution, and can be confusing, but we have little options at this point, given existing code.  Also note that we already have a way to specify a getter property on a user-defined type, UFCS isn't entirely necessary for that.

This will break SOME declarations, but removing @property should result in compiling code I think.

-Steve
February 03, 2013
On 2013-02-03 09:16, Andrei Alexandrescu wrote:
> Walter and I have had a discussion on how to finalize properties.
>
> http://wiki.dlang.org/DIP23

What about:

writeln = "asd";

Allowed or not?

-- 
/Jacob Carlborg
February 03, 2013
2013/2/3 Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>

> Walter and I have had a discussion on how to finalize properties.
>
> http://wiki.dlang.org/DIP23


Awesome!!

After reading it, I thought that there is some consistent rules.

1. When a function is annotated with @property, it cannot be called with
parenthesis syntax.
2. 0-arg functions which not annotated with @property can be called without
parentheses.
3. Ref return getter can make "auxiliary setter", if formal getter is
missing.
4. `typeof(exp)` never returns "function type". In other words, the actual
type of `exp` and `typeof(exp)` should be same.
5. Both `&prop` and `&func` should return function pointer / delegate object
6. UFCS CAN NOT call global setter by getter syntax.

I think that 4 to 6 are important points of this DIP. Based on the rules, I could write an exhaustive test case.

alias Type = int;

unittest
{
    struct S
    {
        @property Type foo();       // formal getter
        @property void bar(Type);   // formal setter
        @property ref Type baz();   // ref return getter == auxiliary setter
    }
    S s;
    static assert( __traits(compiles, { s.foo;     }));
    static assert(!__traits(compiles, { s.foo();   }));
    static assert(is(typeof(s.foo) == Type));
    static assert(is(typeof(&s.foo) == Type delegate()));

    static assert( __traits(compiles, { s.bar = 1; }));
    static assert(!__traits(compiles, { s.bar(1);  }));
    static assert(is(typeof(s.bar)) == false);
    static assert(is(typeof(&s.bar) == void delegate(Type)));

    static assert( __traits(compiles, { s.baz;     }));
    static assert(!__traits(compiles, { s.baz();   }));
    static assert( __traits(compiles, { s.baz = 1; }));
    static assert(is(typeof(s.baz) == Type));
    static assert(is(typeof(&s.foo) == ref Type delegate()));
}
unittest
{
    struct S
    {
        Type foo();         // 0-arg function
        void bar(Type n);   // 1-arg function
        ref Type baz();     // 0-arg ref return function
    }
    S s;
    static assert( __traits(compiles, { s.foo;     }));
    static assert( __traits(compiles, { s.foo();   }));
    static assert(is(typeof(s.foo) == Type));
    static assert(is(typeof(&s.foo) == Type delegate()));

    static assert(!__traits(compiles, { s.bar = 1; }));
    static assert( __traits(compiles, { s.bar(1);  }));
    static assert(is(typeof(s.bar)) == false);
    static assert(is(typeof(&s.bar) == void delegate(Type)));

    static assert( __traits(compiles, { s.baz;     }));
    static assert( __traits(compiles, { s.baz = 1; }));
    static assert( __traits(compiles, { s.baz();   }));
    static assert(is(typeof(s.baz) == Type));
    static assert(is(typeof(&s.baz) == ref Type delegate()));
}

@property Type foo();
@property void bar(Type);
@property ref Type baz();

unittest
{
    static assert( __traits(compiles, { foo;     }));
    static assert(!__traits(compiles, { foo();   }));
    static assert(is(typeof(foo) == Type));
    static assert(is(typeof(&foo) == Type function()));

    static assert( __traits(compiles, { bar = 1; }));
    static assert(!__traits(compiles, { bar(1);  }));
    static assert(is(typeof(bar)) == false);
    static assert(is(typeof(&bar) == Type function()));

    static assert( __traits(compiles, { baz;       }));
    static assert(!__traits(compiles, { baz();     }));
    static assert( __traits(compiles, { baz = 1;   }));
    static assert(!__traits(compiles, { baz() = 1; }));
    static assert(is(typeof(baz) == Type));
    static assert(is(typeof(&baz) == ref Type function()));
}

@property Type foh(Type);
@property void bah(Type n, Type m);
@property ref Type bas(Type);

Type hoo(Type);
void var(Type, Type);
ref Type vaz(Type);

unittest
{
    static assert( __traits(compiles, { foh = 1; })     &&
!__traits(compiles, { hoo = 1; }));
    static assert(!__traits(compiles, { foh(1);  })     &&
 __traits(compiles, { hoo(1);  }));
    static assert(!__traits(compiles, { 1.foh;   })     &&
 __traits(compiles, { 1.hoo;   }));
    static assert(!__traits(compiles, { 1.foh(); })     &&
 __traits(compiles, { 1.hoo(); }));

    static assert(!__traits(compiles, { bah(1, 2); })   &&
 __traits(compiles, { var(1, 2); }));
    static assert( __traits(compiles, { 1.bah = 2; })   &&
!__traits(compiles, { 1.var = 2; }));
    static assert(!__traits(compiles, { 1.bah(2);  })   &&
 __traits(compiles, { 1.var(2);  }));

    static assert( __traits(compiles, { bas = 1;     }) &&
!__traits(compiles, { vaz = 1;     }));
    static assert(!__traits(compiles, { bas(1);      }) &&
 __traits(compiles, { vaz(1);      }));
    static assert(!__traits(compiles, { bas(1) = 2;  }) &&
 __traits(compiles, { vaz(1) = 2;  }));
    static assert(!__traits(compiles, { 1.bas;       }) &&
 __traits(compiles, { 1.vaz;       }));
    static assert(!__traits(compiles, { 1.bas = 2;   }) &&
 __traits(compiles, { 1.vaz = 2;   }));
    static assert(!__traits(compiles, { 1.bas();     }) &&
 __traits(compiles, { 1.vaz();     }));
    static assert(!__traits(compiles, { 1.bas() = 2; }) &&
 __traits(compiles, { 1.vaz() = 2; }));
}

Is this correct?

Kenji Hara


February 03, 2013
2013/2/3 Steven Schveighoffer <schveiguy@yahoo.com>

> I have a possible suggestion to fix this within your proposal:
>
> @property on single-arg free functions ONLY enables a setter mode, it does not work as a UFCS getter.

 [snip]

>
I was thinking the exact same thing.

Kenji Hara


February 03, 2013
On Sunday, February 03, 2013 13:34:14 Jacob Carlborg wrote:
> On 2013-02-03 09:16, Andrei Alexandrescu wrote:
> > Walter and I have had a discussion on how to finalize properties.
> > 
> > http://wiki.dlang.org/DIP23
> 
> What about:
> 
> writeln = "asd";
> 
> Allowed or not?

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

-----------
In order to use the assignment operator "=" property-style, the @property annotation MUST be used.
-----------

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

> On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Walter and I have had a discussion on how to finalize properties.
>>
>> http://wiki.dlang.org/DIP23
>
> I agree with everything in this.  This looks exactly like what I wanted a few days ago.  Thank you!
>
> One aspect not addressed is free-function properties:

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

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

-Steve
February 03, 2013
On 02/03/2013 09:16 AM, Andrei Alexandrescu wrote:
> Walter and I have had a discussion on how to finalize properties.
>
> http://wiki.dlang.org/DIP23
> ...

Looks good. Two things:

What about eg:

@property T front(T)(T[] arr){ return arr[0]; }

And:

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

The DIP does not fix the first issue.

pragma(msg, typeof(*(int x)=>x)); // pure nothrow @safe int(int x)

February 03, 2013
2013/2/3 Steven Schveighoffer <schveiguy@yahoo.com>

> On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer < schveiguy@yahoo.com> wrote:
>
>  On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu <
>> SeeWebsiteForEmail@erdani.org**> wrote:
>>
>>  Walter and I have had a discussion on how to finalize properties.
>>>
>>> http://wiki.dlang.org/DIP23
>>>
>>
>> I agree with everything in this.  This looks exactly like what I wanted a few days ago.  Thank you!
>>
>> One aspect not addressed is free-function properties:
>>
>
> I thought of one other problem with this proposal.  You can no longer get a delegate of a property.  Like it or not, there will be existing code that does get a delegate to properties (it is allowed now).
>
> I think we should provide a __traits accessor for this.  Otherwise, there is no way to port said code to the new style.
>

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

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

If I am correct, there is no need for special enhancement like __traits.

Kenji Hara


February 03, 2013
On 02/03/2013 01:49 PM, Steven Schveighoffer wrote:
> On Sun, 03 Feb 2013 07:16:17 -0500, Steven Schveighoffer
> <schveiguy@yahoo.com> wrote:
>
>> On Sun, 03 Feb 2013 03:16:08 -0500, Andrei Alexandrescu
>> <SeeWebsiteForEmail@erdani.org> wrote:
>>
>>> Walter and I have had a discussion on how to finalize properties.
>>>
>>> http://wiki.dlang.org/DIP23
>>
>> I agree with everything in this.  This looks exactly like what I
>> wanted a few days ago.  Thank you!
>>
>> One aspect not addressed is free-function properties:
>
> I thought of one other problem with this proposal.  You can no longer
> get a delegate of a property.  Like it or not, there will be existing
> code that does get a delegate to properties (it is allowed now).
>
> I think we should provide a __traits accessor for this.  Otherwise,
> there is no way to port said code to the new style.
>
> -Steve

T delegate() f = &a.prop -> auto f = ()=>a.prop;
T delegate(T) f = &a.prop -> auto f = (T x)=>a.prop=x;