Today, casting between struct types is not supported. This is a proposal for supporting implicit casting from one struct type to another with the same number and types of fields. I'm not yet convinced that it's actually a good idea, but it seems worth discussing. I'm interested in hearing what other use cases and challenges people can think of.
This doesn't cover any explicit casting, e.g. something like @structCast(T, s)
.
Related: #685
pub fn main() void {
const S = struct {
a: i32,
b: f32,
};
const T = struct {
a: i32,
b: f32,
};
const s1: S = S{ .a = 4, .b = 2.0 }; // ok
const s2: S = T{ .a = 4, .b = 2.0 }; // error: expected type 'S', found 'T'
const s3: S = struct {
a: i32 = 4,
b: f32 = 2.0,
}{}; // error: expected type 'S', found 's3'
}
S
, T
, and the anonymous struct type all have the same field types. In this simple example, it seems reasonable that implicit casting would occur.
Once anonymous struct literals are supported, supplying int and float literal values to them would be somewhat problematic.
const S = struct {
a: i32,
b: f32,
};
fn f(s: S) void {}
pub fn main() void {
f(.{.a = 6, .b = 6.6});
}
The effective type of the anonymous struct literal passed to f
above is:
struct {
a: comptime_int,
b: comptime_float,
}
The layout of normal structs is not defined. If struct types S
and T
have identical definitions but the compiler ordered or padded the fields differently, would this make casting between them infeasible?
Furthermore, should extern
or packed
structs support casting in any circumstance?
Let's re-imagine our example. Is it possible to cast the following types to each other?
const S = struct {
a: i32,
b: f32,
};
const T = struct {
a: i32,
b: f32,
pub fn incr(self: *@This()) void {
self.a += 1;
}
};
const U = struct {
a: i32,
b: f32,
pub const rank = "despot";
};
Structs can contain structs, which can contain structs, ad nauseam. Supporting casting between S
and T
here might reveal some complexity, either semantically or in the compiler implementation.
const S = struct {
a: i32,
sub: G,
};
const T = struct {
a: i32,
sub: H,
};
const G = struct {
ok: bool,
};
const H = struct {
ok: bool,
};
- Do field names need to be equal?
- Besides comptime_X types, will this work for enum literal values in fields?
- Pointers: Given equivalent struct types
S
andT
, can one cast*S
to*T
?
A workaround for the comptime_int issue described above is to use explicit casting on the fields. This is fairly painless now, but would be less so after #1757 . Comparing all three:
pub fn main() void {
f(.{.a = 6, .b = 6.6});
f(.{.a = i32(6), .b = f32(6.6)});
f(.{.a = @cast(i32, 6), .b = @cast(f32, 6.6)});
}