August 26, 2022
On Thursday, 25 August 2022 at 14:49:51 UTC, Salih Dincer wrote:
> On Thursday, 25 August 2022 at 13:23:25 UTC, bauss wrote:
>> Currently @property doesn't really do anything in this regard, so I imagine that the code would work the same without @property, no?
>
> One benefit of @property is that it allows the compiler to infer automatically.  So it behaves like auto but superior! For example:
>

That has nothing to do with @property, it works with @("") too.
August 26, 2022
>

On Thursday, 25 August 2022 at 14:49:51 UTC, Salih Dincer wrote:
One benefit of @property is that it allows the compiler to infer automatically. So it behaves like auto but superior! For example:

import std.stdio,
       std.format : conv = format;

            //version = 1;
void main()
{
  char[6] text = "abcDEF".dup;
  auto VERSION = VerA!6(text); // sub-versions

  // range for sure (all version!)
  foreach(c; VERSION) c.write;
  "(empty == true)".writeln;

  // VerA.0, VerB.0: front() => D (one character)
  // VerA.1, VerB.1: toString() => abcDEF (all)
  //VERSION.writeln;/*

    VerA!6(text).writeln;
    VerB!6(text).writeln;
  //*/
}

struct VerA(int len)
{
  char[len] bytes;
  int index = len / 2;

  @property/*
  @system//*/
  {
    alias front this;

    bool empty() { return index == len; }
    char front() { return bytes[index]; }
    void popFront() { ++index; }
  }
  version(1) {
    string toString() { return conv("%s", bytes); }
  }
}

struct VerB(int len)
{
  char[len] bytes;
  int index = len / 2;

  alias front this;

  @property/*
  @system//*/
  {
    bool empty() { return index == len; }
    char front() { return bytes[index]; }
    void popFront() { ++index; }
  }
  version(1) {
    string toString() { return conv("%s", bytes); }
  }
}

I discovered another feature of @property while accessing it with writeln(). You need the alias and InputRange elements to see this...

Have I got it right? When accessing the structure with writeln(), if there is toString(), it is executed first, otherwise InputRange elements come into play. Just like we did with foreach().

If you scope the InputRange elements into the @property scope, the alias becomes priority. It's the opposite when you scope it to @system.

SDB@79

August 28, 2022

On Thursday, 25 August 2022 at 03:49:07 UTC, Steven Schveighoffer wrote:

>

It does just about nothing. The only discernable difference is typeof:

struct S
{
    int prop1() { return 1; }
    @property int prop2() { return 2; }
}

pragma(msg, typeof(S.prop1)); // int()
pragma(msg, typeof(S.prop2)); // int

The function has parameters, the difference you're pointing isn't even visible :)

struct S
{
    int prop1(int a) { return a; }
    @property int prop2(int b) { return b; }
}

pragma(msg, typeof(S.prop1(1))); // int
pragma(msg, typeof(S.prop2(2))); // int

PS. I could not work my last code in the playground. The reason is writeln's choices. I guess new version doesn't get along well with @property...

SDB@79

August 28, 2022

On 8/28/22 9:43 AM, Salih Dincer wrote:

>

On Thursday, 25 August 2022 at 03:49:07 UTC, Steven Schveighoffer wrote:

>

It does just about nothing. The only discernable difference is typeof:

struct S
{
    int prop1() { return 1; }
    @property int prop2() { return 2; }
}

pragma(msg, typeof(S.prop1)); // int()
pragma(msg, typeof(S.prop2)); // int

The function has parameters, the difference you're pointing isn't even visible :)

struct S
{
     int prop1(int a) { return a; }
     @property int prop2(int b) { return b; }
}

pragma(msg, typeof(S.prop1(1))); // int
pragma(msg, typeof(S.prop2(2))); // int

You are asking for the type of the expression which calls the function. (i.e. typeof(s.prop2(1)) instead of typeof(s.prop2). However, typeof(s.prop2) is going to fail, because the compiler is requiring property functions to be used when using typeof (and only when using typeof).

I'm trying to tell you this is the only thing @property does. In all other cases, it's indistinguishable from a normal function/method.

-Steve

August 28, 2022

On Sunday, 28 August 2022 at 15:36:41 UTC, Steven Schveighoffer wrote:

>

In all other cases, it's indistinguishable from a normal function/method.

We still need @property where specified here . When you compile the example in the code window below, you get the following error:

>

onlineapp.d(17): Error: variable onlineapp.main.test1 cannot be declared to be a function

struct S {
  //@property
  float Float() {
    return .0;
  }

  @property
  double Double() {
    return .0;
  }
}

void main()
{
    S s;

    typeof(s.Float) test1 = s.Float;
    typeof(s.Double) test2 = s.Double;

    import std.stdio;

    typeid(test1).writeln(": ", test1);
    typeid(test2).writeln(": ", test2);
}

This is what I wanted to talk about above. So it changes dignity of function (correct word?).

SDB@79

August 29, 2022
On 8/28/22 6:36 PM, Steven Schveighoffer wrote:
> On 8/28/22 9:43 AM, Salih Dincer wrote:
>> On Thursday, 25 August 2022 at 03:49:07 UTC, Steven Schveighoffer wrote:
>>> It does just about nothing. The only discernable difference is `typeof`:
>>>
>>> ```d
>>> struct S
>>> {
>>>     int prop1() { return 1; }
>>>     @property int prop2() { return 2; }
>>> }
>>>
>>> pragma(msg, typeof(S.prop1)); // int()
>>> pragma(msg, typeof(S.prop2)); // int
>>> ```
>>
>> The function has parameters, the difference you're pointing isn't even visible :)
>> ```d
>> struct S
>> {
>>      int prop1(int a) { return a; }
>>      @property int prop2(int b) { return b; }
>> }
>>
>> pragma(msg, typeof(S.prop1(1))); // int
>> pragma(msg, typeof(S.prop2(2))); // int
>> ```
> 
> You are asking for the type of the expression which calls the function. (i.e. `typeof(s.prop2(1))` instead of `typeof(s.prop2)`. However, `typeof(s.prop2)` is going to fail, because the compiler is requiring property functions to be used when using `typeof` (and only when using `typeof`).
> 
> I'm trying to tell you this is the *only thing `@property` does*. In all other cases, it's indistinguishable from a normal function/method.

I think this should be immortalized and made very clear in the docs. It's an FAQ. (FWIW it's also a sign that the feature is not very helpful.)

One possibility to make it more useful would be to have @property disallow function signatures that cannot possibly be used as properties (e.g. multiple non-defaulted parameters).

Also properties that return UDTs by value are suspect because they lead to confusing code. Consider:

struct Widget { int a; }
@property Widget w() { return Widget.init; } // should be disallowed
void main() {
    w.a = 42; // does nothing, looks like it's assigning a value
}

Assigning values to fields of rvalues is a distinct long-standing problem.
August 29, 2022
On 25.08.22 15:18, Andrey Zherikov wrote:
> 
> I have no objections to deprecate `@property` attribute but I believe D must support the use case when `obj.mem` expression calls `obj.mem()` function (this is usually called property functions).

dmd.50 docs (2002):

--
All this is quite a bit of typing, and it tends to make code unreadable by filling it with getProperty() and setProperty() calls. In D, get'ers and set'ers take advantage of the idea that an lvalue is a set'er, and an rvalue is a get'er:
   class Abc
   {  int myprop;
      void property(int newproperty) { myprop = newproperty; } // set'er
      int property() { return myprop; }   // get'er
   }

which is used as:
   Abc a;
   a.property = 3;      // equivalent to a.property(3)
   int x = a.property;      // equivalent to int x = a.property()

Thus, in D you can treat a property like it was a simple field name. A property can start out actually being a simple field name, but if later if becomes necessary to make getting and setting it function calls, no code needs to be modified other than the class definition.
--

August 29, 2022

On Monday, 29 August 2022 at 08:40:51 UTC, Andrei Alexandrescu wrote:

>

One possibility to make it more useful would be to have @property disallow function signatures that cannot possibly be used as properties (e.g. multiple non-defaulted parameters).

Nitpick - this actually does work:

void prop(int i, float f, string s) {}


void main() {
    import std.typecons : tuple;
    import std.meta : AliasSeq;
    prop = tuple(1, 2.0, "foo").expand;
    prop = AliasSeq!(1, 2.0, "foo");
}

Should it, though? Probably not.

--
Simen

August 29, 2022
On Monday, 29 August 2022 at 08:40:51 UTC, Andrei Alexandrescu wrote:
>
> I think this should be immortalized and made very clear in the docs. It's an FAQ. (FWIW it's also a sign that the feature is not very helpful.)

So this is the state of @property:

- takes valuable time to discuss, over and over, for years
- serve no purpose other than "documentation", so it could be a phobos/druntime UDA
- it creeps up in code and PR, and each time needs an explanation

This is a net negative feature.
August 30, 2022
On 30/08/2022 2:45 AM, Guillaume Piolat wrote:
> On Monday, 29 August 2022 at 08:40:51 UTC, Andrei Alexandrescu wrote:
>>
>> I think this should be immortalized and made very clear in the docs. It's an FAQ. (FWIW it's also a sign that the feature is not very helpful.)
> 
> So this is the state of @property:
> 
> - takes valuable time to discuss, over and over, for years
> - serve no purpose other than "documentation", so it could be a phobos/druntime UDA
> - it creeps up in code and PR, and each time needs an explanation
> 
> This is a net negative feature.

It only does two things:

1. I can't remember the (single) semantic behavior
2. Create threads like this one

Time to go.