I was experimenting with some things and run into a problem.
const log = @import("std").debug.print;
const Thing: type = struct {
data: u32,
fn init(d: u32) Thing {
return .{.data = d};
}
fn func(thing: *?Thing) void {
//log("d = {}\n", .{thing.?.data});
log("d = {}\n", .{thing.data});
}
};
pub fn main() void {
const t = Thing.init(11);
t.func();
}
Compiler says:
$ zig build-exe test.zig
test.zig:20:6: error: no field or member function named 'func' in 'test.Thing'
t.func();
~^~~~~
test.zig:4:21: note: struct declared here
const Thing: type = struct {
^~~~~~
test.zig:12:5: note: 'func' is not a member function
fn func(thing: *?Thing) void {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
I can not understand what is going on here.
Shouldn’t it be ?*Thing
No, I wanted pointer to optional, not an optional pointer.
The method syntactic sugar only works for This
, * This
and *const This
. Anything other than that, you have to do normal function call.
1 Like
If this worked, what would the method call do if the thing
argument points to null
?
something like this I suppose:
const log = @import("std").debug.print;
const Thing: type = struct {
data: u32,
fn init(d: u32) Thing {
return .{.data = d};
}
fn func(thing: *?Thing) void {
const t: Thing = thing.* orelse {
log("oops\n", .{});
return;
};
log("d = {}\n", .{t.data});
}
};
pub fn main() void {
var t: ?Thing = Thing.init(11);
Thing.func(&t);
t = null;
Thing.func(&t);
}
now it’s working but it’s not exactly what I wanted.
ok, nevermind.
Why do you need a pointer to optional anyways?
Good question.
I studied various ways of constructing interfaces with particular interest in method number 4 (old way, embed an interface struct into implementer struct and use @fieldParentPtr()
). Obviously this method does not allow a struct to implement several interfaces since methods are passed a pointer to a particular one. Then I thought that we can construct a set of interfaces.
Failed attempt to do this
const log = @import("std").debug.print;
const TraitA: type = struct {
impl: ?*const fn(*TraitSet) void = null,
fn doit(t: *?TraitA) void {
// if (*t and t.impl) |t, impl| {
if (t.impl) |impl| {
const ts: *TraitSet = @fieldParentPtr("a", t);
impl(ts);
} else {
log("A default implementation\n", .{});
}
}
};
const TraitB: type = struct {
impl: ?*const fn(*TraitSet) void = null,
fn doit(t: *?TraitB) void {
if (t.impl) |impl| {
const ts: *TraitSet = @fieldParentPtr("b", t);
impl(ts);
} else {
log("B default implementation\n", .{});
}
}
};
const TraitSet: type = struct {
a: ?TraitA = null,
b: ?TraitB = null,
};
/// implementations
const ThingOne: type = struct {
data: u32,
ts: TraitSet,
fn init(d: u32) ThingOne {
return .{
.data = d,
.ts = .{
.a = .{.impl = myAImpl},
},
};
}
fn myAImpl(ts: *TraitSet) void {
const me: *ThingOne = @fieldParentPtr("ts", ts);
log("I can do A with {}\n", .{me.data});
}
};
const ThingTwo: type = struct {
data: u32,
ts: TraitSet,
fn init(d: u32) ThingTwo {
return .{
.data = d,
.ts = .{
.b = .{.impl = myBImpl},
},
};
}
fn myBImpl(ts: *TraitSet) void {
const me: *ThingTwo = @fieldParentPtr("ts", ts);
log("I can do B with {}\n", .{me.data});
}
};
pub fn main() void {
const t1 = ThingOne.init(11);
var a = t1.ts.a; a.doit();
// const t2 = ThingTwo.init(22);
// t1.ts.a.doit();
// t1.ts.b.doit();
// t2.ts.a.doit();
// var m = t2.ts.b.?; m.doit();
}
const TraitSet: type = struct {
a: ?TraitA = null,
b: ?TraitB = null,
};
These have to be optional otherwise adding more interfaces to the set would break existing implementers.
1 Like
I don’t really see the problem. Sure you can’t have two interfaces that point at the same function, but apart from that you can you just do it like this:
const SeveralInterfaceImpl: type = struct {
data: u32,
a: TraitA,
b: TraitB,
fn init(d: u32) SeveralInterfaceImpl {
return .{
.data = d,
.a = .{.impl = &myAImpl},
.b = .{.impl = &myBImpl},
};
}
fn myAImpl(a: *TraitA) void {
const me: *SeveralInterfaceImpl = @fieldParentPtr("a", a);
...
}
fn myBImpl(b: *TraitB) void {
const me: *SeveralInterfaceImpl = @fieldParentPtr("b", b);
...
}
};
1 Like
I wanted all interfaces to be collected in a struct and pass it to implementing functions instead of a pointer to concrete interface.
Ok, it’s another topic already.
I will mark @LucasSantos91 answer as solution.
As to my affair with interfaces - if I will be able to do what I wanted I will create new topic.
2 Likes
Yep, that was some kind of glitch in my head, sorry.
Have no idea now what made me think in a so weird way.