Like Jarod, I’m concerned about how this generalizes to situations where one wants additional parameters, or all members except one, or….
It’s a sticky problem that may have no good solution, but I would be interested in exploring a design direction where:
- There is some sort of “splatting” syntax that can unpack tuples into individual arguments at call sites.
- There is also a type splatting syntax for unpacking tuple types in method signatures.
- There are compiler-generated static types that are aliases for tuple types in the shape of
- a particular type’s stored properties and
- a particular function’s signature.
- There are ways of extracting as tuple values of
- a struct’s properties and
- a function’s arguments.
So for example, ignoring questions of precise naming and syntax, I imagine something of this general spirit:
struct S {
var x: Int
var y: String
}
let z: S.Properties // equivalent to `let z: (x: Int, y: String)`
let zIntoS = S(★z) // equivalent to `let zIntoS = S(x: z.x, y: z.y)`
// (★ is the hypothetical splat syntax;
// means “expand tuple into multiple values”)
extension S {
init(
✪stuff: S.Properties, // ✪ causes separate args at call site to be packed into tuple
// In general, ✪ is hypothetical “pack into tuple” syntax
bonusValue: String
) {
self.✪properties = stuff // ✪properties is placeholder for magic syntax;
// means “all properties as tuple, can be an L-value”
doBonusStuff(bonusValue)
}
}
S(x: 3, y: "hello", bonusValue: "frongle") // works
And similarly for function params:
func f(a: Foo, b: Bar, c: Bazzle) {
let stuff = ✪parameters // equivalent to `let stuff = (a: a, b: b, c: c)`
}
func g(a: Foo, b: Bar) {
f(✶✪parameters, c: defaultBazzle) // works
}
let gargs: g.ParameterTypes // equivalent to `let gargs: (a: Foo, b: Bar)`
And maybe even:
func passThrough<Params,Return>(
_ otherFunc: (✶Params) -> Return
✪ params: Params
) -> Return {
otherFunc(✶params)
}
passThrough(f, a: foo, b: bar) // works
Thus the OP’s use case becomes the slightly more complicated but far more generalizable:
struct MyStruct <T> {
private var foo: String
private var bar: Bool?
private var baz: Array<T>
public init(✪ properties: Properties) {
self.✪properties = properties
}
}
This line of thinking gets messy fast:
- What about properties with different access modifiers? Are there multiple syntaxes to select for them?
- What about “all properties except x and y?” Are we heading for something even more esoteric than Typescript’s mapped types?
- Handling labels gets messy, probably
- Type checking semantics and performance will be headaches, probably
- Syntax will definitely be a headache
Still, it’s a direction I’d be curious to explore.