protocol EmptyInitializable {
init()
}
@propertyWrapper
struct PropertyWrapper: EmptyInitializable {
let wrappedValue: Int
init(_ wrappedValue: Int = 0) {
self.wrappedValue = wrappedValue
}
}
// This one lools redundent
extension PropertyWrapper {
public init() {
wrappedValue = 0
}
}
Por que precisamos dessa extensão na parte inferior? Por que o compilador não consegue simplesmente descobrir que struct PropertyWrapper
já está em conformidade com os requisitos para protocol EmptyInitializable
? Parece tão feio...
PS: Acredito que isso realmente funcionasse em situações semelhantes antes.
O compilador não diminui
para
Porque senão o número de sobrecargas que o compilador deve gerar cresce exponencialmente para cada parâmetro opcional, entre outros motivos. Para um método com 5 parâmetros opcionais, o compilador precisaria gerar 32 assinaturas diferentes.
Com isso dito,
PropertyWrapper
claramente não está em conformidade comEmptyInitializable
.O que realmente acontece é que existe apenas uma sobrecarga, mas para cada parâmetro opcional é gerado um thunk para calcular o valor daquele parâmetro.
Há também alguns metadados que informam ao compilador para gerar chamadas para essa conversão, quando o chamador não tiver fornecido todos os argumentos. A chamada
PropertyWrapper()
é reduzida paraPropertyWrapper(defaultValueForArgument0OfInit())
. Você pode ver o código compilado em godbolt.org .Se você estiver chamando
init
através de um protocolo, a chamada será despachada dinamicamente, então o compilador nem sabe qual implementação será chamada , muito menos se precisa passar os valores padrão dos parâmetros opcionais .É claro que o compilador poderia ser projetado de outras maneiras que tornam isso possível, mas perguntar por que ele não foi projetado dessa maneira não é realmente responsável, a menos que você esteja sendo muito específico.
Nota lateral: como você criou um protocolo apenas para os tipos que podem ser inicializados sem parâmetros, recomendo a leitura Protocols are more than Bags of Syntax .