Thread overview
Struct fields and properties as alias members
Dec 08, 2021
Ben Jones
Dec 08, 2021
Ben Jones
Dec 08, 2021
H. S. Teoh
Dec 08, 2021
H. S. Teoh
Dec 08, 2021
Ben Jones
Dec 08, 2021
Adam D Ruppe
Dec 08, 2021
Ben Jones
Dec 08, 2021
Adam D Ruppe
Dec 08, 2021
Ben Jones
December 08, 2021

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
December 08, 2021

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.

December 08, 2021
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
December 08, 2021
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??
December 08, 2021
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)
December 08, 2021
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);
}
```
December 08, 2021

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?

December 08, 2021
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.
December 08, 2021
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