www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Struct fields and properties as alias members

reply Ben Jones <fake fake.fake> writes:
I'm trying to use a property member of a struct as a template 
alias parameter and I don't really understand how to fix the 
error message I'm seeing (I also tried the simpler case of a 
plain struct member, and that didn't work either).  Is what I'm 
trying to do possible?  It seems like maybe I'd have to pass s as 
a runtime parameter to get it to work?

```
import std.stdio;

struct S{
     int a = 1;
     int b = 2;

      property int c(){ return a; }
      property int c(int newc) { a = newc; return a;}
}	

void func(alias field)(){
  	writeln(field);
         field = 5;
}
void main(){
     S s;
     func!(s.a)();
     func!(s.b)();

     func!(s.c)();
}
```
Runnable link here: https://run.dlang.io/is/WHM1Er

Errors:
```
onlineapp.d(17): Error: need `this` for `func` of type ` safe 
void()`
onlineapp.d(18): Error: need `this` for `func` of type ` safe 
void()`
onlineapp.d(12): Error: need `this` for `c` of type ` property 
int()`
onlineapp.d(13): Error: need `this` for `c` of type ` property 
int(int newc)`
onlineapp.d(20): Error: template instance `onlineapp.func!(c)` 
error instantiating
```
Dec 08 2021
next sibling parent reply Ben Jones <fake fake.fake> writes:
On Wednesday, 8 December 2021 at 17:19:32 UTC, Ben Jones wrote:

I considered just having a `ref int` parameter, but I didn't 
think that would work if I was actually calling a property 
function, rather than just modifying a struct member.

I also tried to use a template mixin, but couldn't get that to 
work either.
Dec 08 2021
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 08, 2021 at 05:21:49PM +0000, Ben Jones via Digitalmars-d-learn
wrote:
[...]
 I considered just having a `ref int` parameter, but I didn't think
 that would work if I was actually calling a property function, rather
 than just modifying a struct member.
[...] Why not pass the entire struct by ref? T -- Who told you to swim in Crocodile Lake without life insurance??
Dec 08 2021
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Dec 08, 2021 at 05:19:32PM +0000, Ben Jones via Digitalmars-d-learn
wrote:
 I'm trying to use a property member of a struct as a template alias
 parameter and I don't really understand how to fix the error message
 I'm seeing (I also tried the simpler case of a plain struct member,
 and that didn't work either).  Is what I'm trying to do possible?  It
 seems like maybe I'd have to pass s as a runtime parameter to get it
 to work?
It might help if you elaborate a bit more on what exactly you're trying to achieve here. Why can't you just pass the value of the field to the function as a runtime parameter, for example, which would be the usual way of doing it? Is there something specific you're trying to achieve here that requires using a template parameter? T -- Being forced to write comments actually improves code, because it is easier to fix a crock than to explain it. -- G. Steele
Dec 08 2021
parent Ben Jones <fake fake.fake> writes:
On Wednesday, 8 December 2021 at 17:29:19 UTC, H. S. Teoh wrote:
 On Wed, Dec 08, 2021 at 05:19:32PM +0000, Ben Jones via 
 Digitalmars-d-learn wrote:
 I'm trying to use a property member of a struct as a template 
 alias parameter and I don't really understand how to fix the 
 error message I'm seeing (I also tried the simpler case of a 
 plain struct member, and that didn't work either).  Is what 
 I'm trying to do possible?  It seems like maybe I'd have to 
 pass s as a runtime parameter to get it to work?
It might help if you elaborate a bit more on what exactly you're trying to achieve here. Why can't you just pass the value of the field to the function as a runtime parameter, for example, which would be the usual way of doing it? Is there something specific you're trying to achieve here that requires using a template parameter? T
It's a CPU simulator and the function needs to operate on half of a register (the CPU has 16 bit AF register, but I want to operate on A). I've implemented the "A" part of the register as a pair of property functions: ``` property ubyte a() const { return getHigh!af; } property ubyte a(ubyte val) { return setHigh!af(val); } ``` There are CPU instructions for each of the combined (AF, BC, DE, etc) and half(A, B, C, D, E, etc) registers, so I think either the half registers or the full registers would have to be implemented as property functions (from my reading of the spec, using unions seemed like technically it would be UB?) Basically I want to write one template for the operation (increment, load, etc), and then instantiate it for each register (inc a, inc b, inc c, load a, load b, etc)
Dec 08 2021
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 8 December 2021 at 17:19:32 UTC, Ben Jones wrote:
 It seems like maybe I'd have to pass s as a runtime parameter 
 to get it to work?
yes, you do. the alias param passes the abstract idea of the variable instead of the variable:
 void main(){
     S s;
     func!(s.a)();
See, you said `s` here, but the compiler ACTUALLY passes `S.a` - the type reference instead of the instance reference. That's why it complains about missing `this` - the compiler dropped it. The `this` is a runtime reference, and the alias works on compile time references. You can pass a runtime reference in addition to the alias and put them back together with __traits(child), but be warned, the compiler also can get pretty stupid when pass so you need to make `func` static since when it sees the alias it assumes it must be a member. Weird but easy fix: ``` import std.stdio; struct S{ int a = 1; int b = 2; property int c(){ return a; } property int c(int newc) { a = newc; return a;} } // made static, added a ref S to act as `this` static void func(alias field)(ref S s){ // now the traits child re-attaches `s` as the this // reference to the alias writeln(__traits(child, s, field)); __traits(child, s, field) = 5; } void main(){ S s; func!(s.a)(s); // passing both ct alias and runtime this func!(s.b)(s); func!(s.c)(s); } ```
Dec 08 2021
parent reply Ben Jones <fake fake.fake> writes:
On Wednesday, 8 December 2021 at 17:44:47 UTC, Adam D Ruppe wrote:
 On Wednesday, 8 December 2021 at 17:19:32 UTC, Ben Jones wrote:
Gotcha, thanks. I tried using `S.field` before and that didn't work, `__traits(child)` was the key. Since I reuse the field a few times I tried to alias the result: `alias theProp = __traits(child, s, field);` But everywhere I use `theProp` I get the same error as before (need this...). Is there a way to avoid using the full `__traits(child)` expression everywhere?
Dec 08 2021
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 8 December 2021 at 18:07:32 UTC, Ben Jones wrote:
 Since I reuse the field a few times I tried to alias the result:

 `alias theProp = __traits(child, s, field);`
yeah won't work since the alias again drops the `this`, this is the same thing as the template param. You could make a couple helper functions though. Like void set(typeof(field) v) { __traits(child, s, field) = v; } typeof(field) get() { return __traits(child, s, field); } just declare them nested inside the function and then you can use get and set as-needed. You could make a mixin or whatever if there's a bunch of functions doing this. Of course another idea is to make a helper struct that just wraps the field with opAssign and alias this or something but then it needs to keep a pointer back to s inside that object.
Dec 08 2021
parent Ben Jones <fake fake.fake> writes:
On Wednesday, 8 December 2021 at 18:23:25 UTC, Adam D Ruppe wrote:
 On Wednesday, 8 December 2021 at 18:07:32 UTC, Ben Jones wrote:
I went with the mixin approach, which seems to work fine except that I couldn't declare the mixin inside a function, so the definition is pretty far away from use, but that's not a showstopper. Thanks for your excellent explanations + suggestions
Dec 08 2021