I am trying to do some “comptime struct injection”.
Of course it does not compile.
error: unable to resolve comptime value var mg = Gen(Storage).init(&storage);
I know it must be possible.
The idea is that I can put in different mechanisms to store outside of Gen
.
const Storage = struct {
fn store(self: *Storage) void {
_ = self;
std.debug.print("hello", .{});
}
};
fn Gen(comptime S: type) type {
return struct {
const Self = @This();
const StorageType = @TypeOf(S);
storage: *StorageType,
fn init(storage: *StorageType) Self {
return Self {
.storage = storage,
};
}
fn store(self: *Self) void {
self.storage.store();
}
};
}
fn test_storage() void {
var storage = Storage {};
var mg = Gen(Storage).init(&storage);
mg.store();
}
dimdin
April 27, 2025, 7:23pm
2
S
is already a type, const StorageType = S;
is enough.
OMG Thanks it works.
How on earth does Zig know that struct function call in “store”
const Storage = struct
{
count: usize = 0,
fn store(self: *Storage) void
{
self.count += 1;
std.debug.print("hello {}, ", .{self.count});
}
};
fn Gen(comptime S: type) type
{
return struct
{
const Self = @This();
storage: *S,
fn init(storage: *S) Self
{
return Self
{
.storage = storage,
};
}
fn store(self: *Self) void
{
self.storage.store();
}
};
}
fn test_storage() void
{
var storage = Storage {};
var mg = Gen(Storage).init(&storage);
mg.store();
mg.store();
mg.store();
}
I don’t actually understand how any of this could work without making the functions pub
.
Does it?
This was a local example. (just testing in my main.zig)
Let me check what happens if I put in something without the pub method from the outside…
src\movgen.zig:97:25: error: 'reset' is not marked 'pub'
self.storage.reset();
~~~~~~~~~~~~^~~~~~
src\main.zig:301:5: note: declared here
fn reset(self: *MoveCounter) void
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src\movgen.zig:412:25: error: 'store' is not marked 'pub'
self.storage.store(&m);
~~~~~~~~~~~~^~~~~~
src\main.zig:307:5: note: declared here
fn store(self: *MoveCounter, move: *const EngineMove) void
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src\movgen.zig:412:25: error: 'store' is not marked 'pub'
self.storage.store(&m);
~~~~~~~~~~~~^~~~~~
src\main.zig:307:5: note: declared here
fn store(self: *MoveCounter, move: *const EngineMove) void
When made pub
it works, otherwise not
1 Like
So… apart from the unreadability of it, it is very powerful.
I can just inject an “interface”
Sze
April 27, 2025, 9:49pm
8
Language Reference: import
Declarations which have the pub
keyword may be referenced from a different source file than the one they are declared in.
Within a single file everything is accessible.
Within a single container scope actually. The sample was crossing container boundaries, and as we saw, that you can’t do.
Well as far as I can see it works always if the used functions are public.
The weird thing is, when staring at the code which is using the ‘injected storage’, you have no clue what it is, where it is etc. You cannot see references, implementations etc. like in C#.
Sze
April 28, 2025, 4:07pm
11
This just works:
const std = @import("std");
const Storage = struct {
count: usize = 0,
fn store(self: *Storage) void {
self.count += 1;
std.debug.print("hello {}, ", .{self.count});
}
};
fn Gen(comptime S: type) type {
return struct {
const Self = @This();
storage: *S,
fn init(storage: *S) Self {
return Self{
.storage = storage,
};
}
fn store(self: *Self) void {
self.storage.store();
}
};
}
fn test_storage() void {
var storage = Storage{};
var mg = Gen(Storage).init(&storage);
mg.store();
mg.store();
mg.store();
}
pub fn main() !void {
test_storage();
}
The only pub
that is needed is for the main function, as soon as you separate pieces of the code across multiple files you need pub
.
2 Likes
Sze
April 28, 2025, 4:13pm
13
Within Gen
storage can be an arbitrary type, so Zls can’t tell you what methods/fields it has. But once you have an instance of Gen(Storage)
, Zls shows completion for that:
Yes but not outside that scope, where it is abstract.
Sze
April 28, 2025, 4:21pm
15
I don’t understand the context of your snippet, where it doesn’t work, can you provide a more full example and where the completion doesn’t work?
if
you put Storage in storage.zig (with pub functions)
and
Gen in gen.zig
then
in the gen.zig fn store() you get no code completion.
(edit: which seems logical to me because we have no ‘interface’)
1 Like
Sze
April 28, 2025, 4:39pm
17
Yes I think that is expected behavior, within Gen
S is only some type and we don’t know more.
mnemnion
Split this topic
April 28, 2025, 5:04pm
18
2 posts were split to a new topic: Pub, files, and container types