Why can't values of a struct containing function fields be run-time mutable?

For example, the following code doesn’t compile.

const Foo = struct {
    x: bool,
    comptime y: u8 = 123,
    f: fn() void = bar, // compiles okay if this line is removed
};

fn bar() void {}

pub fn main() !void {
    var foo = Foo{.x = true};
    foo.x = false;
}

You need to use a function pointer. Documentation - The Zig Programming Language

See the example code in the language reference for functions. There is no dedicated section for function pointers.

4 Likes

I’m aware of this. I just don’t get the reason now.

the type of f above is not a function pointer type but only a bare function type. You need to place a * before the type. Note that because fonction pointers point to constant data, you also need to place a const.

Here is an example from one of my projects:

pub const Pointer = *const fn (?*anyopaque, []VmValue) anyerror!VmValue;

I believe the reasoning here is the same as for other pointers: the pointee type is separated from the pointer type.

Note that in hardware, function pointers are the same as other pointers: these are adresses of something inside the computer’s RAM

1 Like

Ah, if the function field is annotated with comptime, then it compiles.

const Foo = struct {
    x: bool,
    comptime y: u8 = 123,
    comptime f: fn() void = bar, // compiles okay now
};

fn bar() void {}

pub fn main() !void {
    var foo = Foo{.x = true};
    foo.x = false;
}

I thought function fields are comptime implicitly before. So it looks this understanding is wrong.

I still haven’t got the reason why the code in the first comment fails to compile.

You already got your answer:
Function-body types can only be used at comptime.

But your original example tried to use them at run-time.

Function-body types are essentially only an identity that represents some function at compile time, once these functions get compiled into a program you can convert that identity to the corresponding pointer to the code of that function (wherever the compiler decides to put it) with the & address operator.

It is a struct field, function fields don’t exist.

1 Like

I mean “fields of function types”.

The original example doesn’t use the field of function type at run-time.
But maybe you are right, it can be potentially used at run-time, at least from the semantic level. That is why the field needs an explicit comptime annotation.

Yes, you should be able to use the original Foo struct in a comptime var, but aren’t allowed to use it in a normal var, because then you could change the .f field at runtime which is impossible because values of its type don’t exist at runtime.

1 Like

Technically in hardware, pointers don’t exist. You just tell the hardware to use some number as an address and that’s it.

Well, with the exception of CHERI hardware of course.

2 Likes