www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to disable assigning a value to a property?

reply Jack Applegame <japplegame gmail.com> writes:
Code:
```d
import std.stdio;

struct Field {
     void opAssign(int a) {
         writefln("Field.opAssign(%s)", a);
     }
}

struct Register {
     Field clock(int a) {
         writefln("Register.clock(%s)", a);
         return Field();
     }
}


void main() {
     Register register;
     register.clock(1) = 10; // works, good
     register.clock = 10;    // works too, how to disable it?
}
```
How to disable `register.clock = 10;` but allow 
`register.clock(1) = 10;`?
I want to get a compilation error on `register.clock = 10;`
Jul 06
next sibling parent reply drug <drug2004 bk.ru> writes:
06.07.2021 13:06, Jack Applegame пишет:
 Code:
 ```d
 import std.stdio;
 
 struct Field {
      void opAssign(int a) {
          writefln("Field.opAssign(%s)", a);
      }
 }
 
 struct Register {
      Field clock(int a) {
          writefln("Register.clock(%s)", a);
          return Field();
      }
 }
 
 
 void main() {
      Register register;
      register.clock(1) = 10; // works, good
      register.clock = 10;    // works too, how to disable it?
 }
 ```
 How to disable `register.clock = 10;` but allow `register.clock(1) = 10;`?
 I want to get a compilation error on `register.clock = 10;`
 
Something like using different types for arguments in `Register.clock` and `Field.opAssign`?
Jul 06
parent Jack Applegame <japplegame gmail.com> writes:
On Tuesday, 6 July 2021 at 10:24:45 UTC, drug wrote:
 Something like using different types for arguments in 
 `Register.clock` and `Field.opAssign`?
I've been thinking about it. Unfortunately, this is not always convenient.
Jul 06
prev sibling next sibling parent reply Dennis <dkorpel gmail.com> writes:
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote:
 How to disable `register.clock = 10;` but allow 
 `register.clock(1) = 10;`?
 I want to get a compilation error on `register.clock = 10;`
We're [still awaiting formal assessment on dip1038](https://forum.dlang.org/thread/sojvxakgruzfvbigzhiu forum.dlang.org), but if that gets in, you can mark `clock` or `Field` ` nodicard`. Otherwise I don't know of a way.
Jul 06
parent Jack Applegame <japplegame gmail.com> writes:
On Tuesday, 6 July 2021 at 10:25:28 UTC, Dennis wrote:
 We're [still awaiting formal assessment on 
 dip1038](https://forum.dlang.org/thread/sojvxakgruzfvbigzhiu forum.dlang.org),
but if that gets in, you can mark `clock` or `Field` ` nodicard`. Otherwise I
don't know of a way.
Yes, it would help.
Jul 06
prev sibling next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote:
 How to disable `register.clock = 10;`
You don't. The language always allows `a = b;` to be rewritten as `a(b);`. Best you can do is use different types for the two arguments. Maybe clock could take a struct Clock { int x; } or something instead.
Jul 06
parent reply Jack Applegame <japplegame gmail.com> writes:
On Tuesday, 6 July 2021 at 12:33:20 UTC, Adam D Ruppe wrote:
 The language always allows `a = b;` to be rewritten as `a(b);`.
And that's sad. It should happen for properties only.
Jul 06
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 6 July 2021 at 13:27:43 UTC, Jack Applegame wrote:
 And that's sad. It should happen for properties only.
Totally disagree. This is one of my favorite D features.
Jul 06
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/6/21 9:27 AM, Jack Applegame wrote:
 On Tuesday, 6 July 2021 at 12:33:20 UTC, Adam D Ruppe wrote:
 The language always allows `a = b;` to be rewritten as `a(b);`.
And that's sad. It should happen for properties only.
Yes, I lament that there is no way to control how people call your function. It can result in surprising things, and it means as a library designer you have to consider this usage when picking names. There are a few "draft" DIP proposals (under the old DIP system) here: https://wiki.dlang.org/DIPs But I think the time of being able to make such a disruptive change has passed. For better or worse we have the half-implemented near-useless meaning of ` property`, and basically it's unneeded. -Steve
Jul 06
prev sibling next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote:
 How to disable `register.clock = 10;` but allow 
 `register.clock(1) = 10;`?
 I want to get a compilation error on `register.clock = 10;`
Some options: 1. return a temporary struct with an opIndex ```d import std.stdio; struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct ClockAssign { Field opIndex(int a) { writefln("Register.clock(%s)", a); return Field(); } } struct Register { ClockAssign clock() { return ClockAssign(); } } void main() { Register register; register.clock[1] = 10; // works, good //register.clock = 10; // error } ``` 2. https://run.dlang.io/is/bkV64U - keep track of fields and fail at runtime if a field was never initialized (because it was silently discarded in this case). 3. https://run.dlang.io/is/AJM6Vg - hybrid where ClockAssign has an unsafe pointer that the compiler complains about :/
Jul 06
parent jfondren <julian.fondren gmail.com> writes:
On Tuesday, 6 July 2021 at 15:24:37 UTC, jfondren wrote:
 3. https://run.dlang.io/is/AJM6Vg - hybrid where ClockAssign 
 has an unsafe pointer that the compiler complains about :/
4. ```d import std.stdio; struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct ClockAssign { Field[] clocks; void opIndexAssign(int a, int b) { writefln("Register.clock(%s)", a); clocks ~= Field(); clocks[$-1] = b; } } struct Register { ClockAssign clock; } void main() { Register register; register.clock[1] = 10; // register.clock = 10; // error } ```
Jul 06
prev sibling parent Tejas <notrealemail gmail.com> writes:
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote:
 
Here's another way using ``` std.typecons ``` ```d import std.stdio; import std.typecons; alias input = Typedef!int; //new code struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct Register { Field clock(input a) { writefln("Register.clock(%s)", cast(int)a); //note the cast return Field(); } } void main() { input ip = 1; Register register; register.clock(ip) = 10; // works, good //register.clock = 10; // works too, how to disable it? EDIT: Now it doesn't work :) } ``` You will have to either cast your literal, or provide a variable with the new type as input though, so it is also not perfect.
Jul 06