Hello community!
While writing a Swift introduction tutorial for students, I’ve been stumbling
upon the rules for struct default and memberwise initializers.
I failed to find explanations in Apple’s language guide, but as far as I could
observe, I think the rules don’t fit interesting use-cases.
Here are the cases that I was able to identify (I hope you don’t mind
millennials and their obligatory Pokemon references):
First, as documented in Apple’s guide, structs that doesn’t define any
initializer and have no default values receive a memberwise initializer:
typealias Species = (number: Int, name: String)
struct Pokemon {
let species: Species
var level: Int
var nickname: String
}
let bulby = Pokemon(species: (001, "Bulbasaur"), level: 1, nickname: "bulby")
Structs that define a default value for all their properties receive a default
initializer:
struct Pokemon {
let species: Species = (001, "Bulbasaur")
var level: Int = 1
var nickname: String = "bulby"
}
let bulby = Pokemon()
Now digging a bit deeper, I noticed that they also seem to receive an
initializer for their non-constant properties:
let bulby = Pokemon(level: 1, nickname: "bulby")
If no value is provided for one (or several) of its variable properties, they
receives an initializer for all their variable properties:
struct Pokemon {
let species: Species = (001, "Bulbasaur")
var level: Int = 1
var nickname: String
}
let bulby = Pokemon(level: 1, nickname: "bulby")
Finally, if they're given a default value for their variable properties but not
for their constant properties, they receive the full memberwise initializer
only:
struct Pokemon {
let species: Species
var level: Int = 1
var nickname: String = "bulby"
}
let bulby = Pokemon(species: (001, "Bulbasaur"), level: 1, nickname: "bulby")
If the two extreme cases sounds perfectly valid to me (no default value vs all
default values), the mixed situations do not.
In particular, it seems strange that a struct without a default value for its
constant property, but one for all its variable properties receives the
memberwise initializer only. I guess that would be a common “mixed situation”
case, yet the provided initializer is actually useless.
Receiving the full memberwise initializer is fine, but I would also expect to
receive some kind of "partial memberwise” initializer for all properties
(constants or variables) that are not defined:
struct Pokemon {
let species: Species
var level: Int = 1
var nickname: String = "bulby"
}
let bulby = Pokemon(species: (001, "Bulbasaur”))
print(bulby)
// Prints "Pokemon(species: (1, "Bulbasaur"), level: 1, nickname: "bulby")"
Besides, that would avoid some tedious initializer definitions. Indeed, If I
want to get the desired result, I have to write this kind of initializer:
struct Pokemon {
let species: Species
var level: Int = 1
var nickname: String = "bulby"
init(species: Species, level: Int? = nil, nickname: String? = nil) {
self.species = species
if level != nil {
self.level = level!
}
if nickname != nil {
self.nickname = nickname!
}
}
}
In addition to be rather wordy, it arguably destroys the purpose of defining a
default value for variable properties in the first place, since imho this
approach is clearer (unless maybe for some more complicated structs with
multiple layers of initializer delegation):
struct Pokemon {
let species: Species
var level: Int
var nickname: String
init(species: Species, level: Int = 1, nickname: String = "bulby") {
self.species = species
self.level = level
self.nickname = nickname
}
}
Thanks.
Dimitri Racordon
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution