Pointer to optional self in struct method

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. :frowning:

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.

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.

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);
        ...
    }
};

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.

Yep, that was some kind of glitch in my head, sorry.
Have no idea now what made me think in a so weird way.