-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Problem Case
It is a common occurrence that one might want to serialize a struct into a tuple.
At the moment this is usually done via a helper method:
const Deformation = struct {
xx: f32 = 1, xy: f32 = 0, xz: f32 = 0,
yx: f32 = 0, yy: f32 = 1, yz: f32 = 0,
zx: f32 = 0, zy: f32 = 0, zz: f32 = 1,
pub fn serialize(m: Deformation) [9]f32 {
return .{
m.xx, m.xy, m.xz,
m.yx, m.yy, m.yz,
m.zx, m.zy, m.zz,
};
}
};This isn't too bad if you have only one serialization format, or that all possible variations are known at the time of creating your data type so that you can just write them into your type methods.
However, when interfacing with libraries, of which you have no control over their predefined Types, it becomes an NxM problem to map all combinations from one to another.
Often you'd also need to modify the fields before passing them into the converted types.
All this means that you must explicitly write out the mapping at the call site, since writing utility functions for all the arbitrary mappings and variations is simply not feasible nor worthwhile when there are many one-off variations.
More often than not, these conversions usually comes only from one source variable rather than mixing them from multiple ones of the same type; in this case, assignment via explicit reference to <identifier name>.<field of identifier> means repeating the <identifier name> for as many times as you're referencing it, which becomes error-prone and cumbersome especially within an expression that references them multiplie times.
Potential Proposal
Currently, there are no syntactic occurrences of .{ <assignments> } being preceded by a variable name -- it must always be freestanding within the expression context.
Consider also that with .{ .field = <value> }, only left-handed expressions can contain .field which unambiguously references the currently-constructed tuple as parent scope, so there is currently no semantic occurrence of .field in a right-handed expression.
Therefore, I think it would be a unambiguous drop-in syntax to have varDst = varSrc.{ .fieldDst = .fieldSrc } define the field-identifier context of right-handed expression to be the source variable.
So for example, the following homogeneous tuple declaration:
const arrayed_tuple = .{
my_deformation.xx, my_deformation.xy, my_deformation.xz,
my_deformation.yx, my_deformation.yy, my_deformation.yz,
my_deformation.zx, my_deformation.zy, my_deformation.zz,
};would be sugared into:
const arrayed_tuple = my_deformation.{
.xx, .xy, .xz,
.yx, .yy, .yz,
.zx, .zy, .zz,
};And the following heterogeneous tuple declaration:
const fielded_tuple = .{
.r = my_vector.x,
.g = my_vector.y,
.b = my_vector.z,
.a = ( my_vector.x + my_vector.y + my_vector.z ) / 3,
};would be sugared into:
const fielded_tuple = my_vector.{
.r = .x ,
.g = .y ,
.b = .z ,
.a = (.x + .y + .z) / 3 ,
};Obviously the field types need not be homogeneous since they are tuples:
const Person = struct {
surname: []const u8,
birthyear: isize,
age: isize,
}
const Wine = struct {
name: []const u8,
price: usize,
year: isize,
}
fn makeWine(comptime maker: Person) Wine {
return maker.{
.name = "Chateau " ++ .surname,
.price = .surname.len,
.year = .birthyear + .age,
};
}This can be thought of as a generalized of the use case described in #17875 , where instead of just homogeneous entries in @Vector types this applies to any types that has dot-accessible members.