I think a function like AutoPtr below can be used instead, as a compromise between versatility and being concise. (But it may make sense to lock-down/harden the function more to only accept pointers that can be method receivers)
How is the distinction meaningless?
When constness has real consequences on what methods you can call on the result to ownerS?
And why can I write this then?
zig 0.15.1:
const std = @import("std");
const S = struct {
t: T,
pub fn format(self: *const S, writer: anytype) error{WriteFailed}!void {
try writer.print("t: {}\n", .{self.t});
}
pub fn toggle(self: *S) void {
self.t.x = !self.t.x;
}
};
const T = struct {
x: bool,
fn ownerS(self: anytype) AutoPtr(@TypeOf(self), S) {
return @alignCast(@fieldParentPtr("t", self));
}
};
pub fn AutoPtr(input: type, Output: type) type {
return switch (@typeInfo(input)) {
.pointer => |p| if (p.is_const) *const Output else *Output,
else => @compileError("not supported"),
};
}
pub fn main() !void {
var s = S{ .t = .{ .x = true } };
const cs = s;
const t: *T = &s.t;
const ct: *const T = &cs.t;
std.debug.print("{}\n", .{@TypeOf(t.ownerS())});
std.debug.print("{}\n", .{@TypeOf(ct.ownerS())});
std.debug.print("{f}\n", .{t.ownerS()});
std.debug.print("{f}\n", .{ct.ownerS()});
t.ownerS().toggle();
// ct.ownerS().toggle(); // not allowed on const pointer
std.debug.print("{f}\n", .{t.ownerS()});
std.debug.print("{f}\n", .{ct.ownerS()});
}
It seems to me that the language reference is wrong describing the signature with:
@fieldParentPtr(comptime field_name: []const u8, field_ptr: *T) anytype
When the function empirically accepts either *T or *const T (or any kind of pointer?).
So is the documentation wrong or the language implementation?
Considering there is no existing notation for an arbitrary pointer (or field pointer), I think using *anytype (which does not exist) to describe it, would possibly confuse readers into thinking that it is a valid variation of anytype. (And just using anytype wouldn’t communicate that it needs to be a pointer)
I think as long as the pointer is actually a pointer to a field of the corresponding @fieldParentPtr result type, it should work; and the properties of the field_ptr should not matter if it is a valid field pointer.
There is actually another error about the documentation:
Given a pointer to a struct field, returns a pointer to the struct containing that field.
You also can use @fieldParentPtr to convert a pointer to a union-field-value, to a pointer to the union value.
The documentation only mentions structs and implies it only works with structs.