#How come I can't get a mutable field in a struct

1 messages · Page 1 of 1 (latest)

near scarab
#

Hello, coming from a C# background I am having trouble getting my head around zig's struct system.

How come this doesn't work on https://godbolt.org/ ?

    var vector: @Vector(3, f32) = @Vector(3, f32) { 0, 0, 0 };

    pub fn add(self: @This(), other: f32_3) f32_3 {
        return self.vector + other.vector;
    }
};

I am not super familiar with pointers so maybe I have to dereference something or somewhat??

It throws this error error: no field named 'vector' in struct '

stone ruin
#

when you use var or const in a struct it makes it a decl rather than a field, idk about c# but theyre like static members in c++

#
const f32_3 = struct {
    vector: @Vector(3, f32) = @Vector(3, f32) { 0, 0, 0 },

    pub fn add(self: @This(), other: f32_3) f32_3 {
        return .{ .vector = self.vector + other.vector };
    }
};
#

also, you sent the wrong link :p

near scarab
#

Sweeeet, that got it working. Is this not going to cause a new memory allocation. I want to make sure I am doing the add on the self and not creating a new self.

stone ruin
#

that is creating a new one

near scarab
#

Hmmm, how would I just access the field and then add the other value to the field then? I gotta go fast.

stone ruin
#
    pub fn add(self: *@This(), other: f32_3) void {
        self.vector += other.vector;
    }
#

you need to take it in as a pointer to modify it

near scarab
#

ahhhh much better. Still not used to pointers

#

Although it looks like the assembly for the first one is less instructions

Creating a new struct and returning it

        push    rbp
        mov     rbp, rsp
        mov     rax, rdi
        vmovaps xmm0, xmmword ptr [rsi]
        vmovaps xmm1, xmmword ptr [rdx]
        vaddps  xmm0, xmm0, xmm1
        vextractps      dword ptr [rdi + 8], xmm0, 2
        vmovq   qword ptr [rdi], xmm0
        pop     rbp
        ret```

Modifying the struct passed in
```example.f32_3.add:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     qword ptr [rbp - 16], rdi
        mov     qword ptr [rbp - 8], rdi
        mov     rax, qword ptr [rbp - 8]
        vmovaps xmm0, xmmword ptr [rax]
        vmovaps xmm1, xmmword ptr [rsi]
        vaddps  xmm0, xmm0, xmm1
        vextractps      dword ptr [rax + 8], xmm0, 2
        vmovq   qword ptr [rax], xmm0
        add     rsp, 16
        pop     rbp
        ret```
#

Thank you for the help!

clever goblet
near scarab
clever goblet
# near scarab Oh right. Still learning about memory and allocation after being a C# person for...

Creating something on the stack is so cheap as to basically be free, so the only concern is about the quantity of data on the stack at any one time.
The optimizer will generally reuse stack space once its value is no longer used though, so while semantically everything is on the stack until the end of the scope, it may not ultimately be quite that way in the end.
Similarly, there are special CPU slots called "registers" that primitive values (like i32) will be put in, which bypasses the stack altogether -- and because registers are literally inside the CPU itself, they are VERY fast to access and use.

#

The stack is generally faster than any-old-memory simply because it's touched a lot by your program.
CPUs have memory caches which they copy data that was in actual memory down into based on frequency of use.
Similarly to registers, each level of cache (there's at least 3 levels of it) is generally much faster than the level above, and even the slowest level is an order of magnitude faster to access than accessing actual memory.
The stack is touched every time you read/write a variable that really is on the stack, or call/return from a function -- indeed, the lines of assembly above that involve square brackets are accessing memory.

#

Matrices are generally large enough where copying them around a bunch that it will be slower than just mutating the one you've got.

#

A decent rule of thumb for the size threshold with situations like this is 16 bytes (<=16 -> copy, >16 -> mutate) -- but measuring is the ultimate authority here in the end.