Description
Currently in Rust, there is no way to guarantee to the compiler that something for sure has a certain field. For example, if you are using an enum that has multiple fields, and all of those fields have the exact same name, type and purpose. I want a "semi-struct" of sorts (or maybe just a struct) that can guarantee that all variants inside of an enum have a certain field. Maybe this could also see extended use in traits or functions, to guarantee that XYZ field exists.
I have no idea how the syntax should (ideally) be structured, but here is a proposal that I have in Rust pseudocode.
The drawbacks that I see for this are in the pseudocode's comments.
// 'strict' will be important later
strict field FooField {
x: usize,
y: usize
}
field BarField {
x: usize,
y: usize
}
// The 'strict' specifier now comes into play here. Now you can automatically implement a new
// function for types that don't implement it and also have the FooField field.
trait FooTrait {
// I think the dyn keyword should be required
// for non-strict fields like BarField.
// You also shouldn't be able to initiate a type
// from Output unless it used a "strict" field.
type Output: FooField;
// anonymous fields with the exact names and properties may be
// used instead of FooField, however ALREADY DEFINED fields
// with the exact same properties should be disallowed
fn new(x: usize, y: usize) -> Output {
// Here, in theory, you should be able to
// create a new instance since this is a strict field
Output {
x,
y
}
}
}
// Implementing MULTIPLE fields on a tuple would also be problematic
// because it uses numbers to access values, as opposed to their names.
field BarTuple(x: usize, y: usize);
// Using anonymous parameters for the declaration above is probably
// just a bad idea because it makes the purpose of these values
// less clear.
// =============
fn main() {
// Anonymous fields.
let my_thing = field {
x: 3u8,
y: 4u8
};
other_fn(my_thing);
}
fn other_fn(thing: field {x: u8, y: u8} ) {
}
// Above, the syntax is a bit clunky.
// I think the real advantage would be being able to
// create objects without the need for an enum or
// an entirely new struct, not for usage in functions.
// Should there be a field! macro to allow for this?
// =============
// Here, defining FooStruct is optional since we are not adding additional properties.
struct FooStruct with FooField;
// Here, it is not. The goal here is to make it more difficult to mis-interpret the code while skimming through it.
struct BarStruct with FooField {
x, y,
z: usize
}
// Fields that are not strict can optionally be converted into strict
// fields for certain use-cases.
struct BarStruct with strict BarField;
enum FooEnum with FooField {
// FooVariant does not compile!
FooVariant {
// Shorthand, so you don't need to specify types.
// Also makes it clearer which types come from the FooField, and which from the enum variant.
x,
y,
// This throws a compiler error because 'strict' was specified. That means
// that the enum cannot contain any additional fields.
s: usize
}
// Fails, no X or Y fields
BarVariant,
NoIdeaVariant {
// Success!
x,
y
}
}
// All variants must have at least BarField's components,
// but can also add their own fields. Variants of BarEnum
// cannot be constructed in a trait function though, as they might require
// additional fields which won't be included
enum BarEnum with BarField {
// Valid
Pos3D {
x,
y,
z: usize
}
// Valid
Pos2D {
x, y
}
// Invalid, does not contain field y.
Pos1D {
x
}
// Invalid, no implicit fields here!
Pos0D
}
// Uses all of BarField's fields, but this time,
// it strictly requires that it conforms to BarField
enum xyzEnum with strict BarField {
// Variants here.
}
The reason I do not wish to add new functionality to structs is because I want field
s to be used like traits, while struct
s are strict types.
I would greatly appreciate criticism.