This is my code:
class Person {
init<T: RawRepresentable>(raw: T = Child.johnDoe) {}
}
enum Child: String {
case johnDoe
}
It doesn't compile. The error is:
Default argument value of type 'Child' cannot be converted to type 'T'
Why can't it be converted? According to the docs, Child.someEnum
is RawRepresentable
:
Enumerations with Raw Values For any enumeration with a string, integer, or floating-point raw type, the Swift compiler automatically adds RawRepresentable conformance. When defining your own custom enumeration, you give it a raw type by specifying the raw type as the first item in the enumeration’s type inheritance list.
This also compiles:
class Person {
static func accept<T: RawRepresentable>(raw: T) where T.RawValue == String {}
}
enum Child: String {
case johnDoe
}
Person.accept(raw: Child.johnDoe)
Why doesn't it work as a default parameter?
Use case: I want to accept any RawPresentable
value, so I can extract the rawValue
from it. I want to provide a default value (always "") (I just create a struct with rawValue = ""
). I do not want to create multiple initializers, since I got some subclasses and that would get a mess. The best for me is just to provide a default RawRepresentable
object.
When I add a cast: init(ty: T = (Child.johnDoe as! T)) where T.RawValue == String {
}
Or make it nillable:
(ty: T? = nil)
It compiles. But now I can not call:
let x = Person()
It gives the error:
Generic parameter 'T' could not be inferred
This is certainly possible. However, you have to use your own protocol and add the default value to that protocol:
protocol MyRawRepresentable: RawRepresentable {
static var defaultValue: Self { get }
}
class Person {
init<T: MyRawRepresentable>(raw: T = T.defaultValue) {}
}
enum Child: String, MyRawRepresentable {
case johnDoe
static let defaultValue: Child = .johnDoe
}
There is another issue though. How will you specify the generic type if you use the default parameter value and all you will have will be just Person.init()
?
The only solution I see is to also specify a default generic type which means you actually want:
class Person {
init<T: RawRepresentable>(raw: T) {
}
convenience init() {
self.init(raw: Child.johnDoe)
}
}
Unless you actually want to make Person
itself a generic class because then you could just use
Person<Child>.init()