I am trying to write a class base on class clusters like NSArray:
class C {
init() { }
mutating init(use1: Bool) { // 'mutating' may only be used on 'func' declarations
self = use1 ? C1() : C2() // Cannot assign to value: 'self' is immutable
or
return use1 ? C1() : C2() // 'nil' is the only return value permitted in an initializer
}
}
class C1: C { }
class C2: C { }
is there any problems to achieve init with subclass in swift? I mean it could use static func to return subclass, but that is too weird that you can't use the init() right?
You wouldn't even need to subclass to get into a weird situation, because if what you asked for would be allowed, then the initializer would also be available on C1, C2 and any other subclass of C, letting you write eg:
let myC2: C2 = C2(use1: true)
print(myC2 is C1) // true ... I guess.
which seems a bit nonsensical (since C1 is not a subclass of C2).
Actually the question is: I want to use something behave like init() to return subclass
We can do this now:
class C {
init() { }
static func `init`(use1: Bool) -> C { // Keyword 'init' cannot be used as an identifier here If this name is unavoidable, use backticks to escape it
return use1 ? C1() : C2()
}
}
class C1: C { }
class C2: C { }
then
let c = C.`init`(use1: <#T##Bool#>)
But we can't:
let c = C(use1: )
If I want to use C(use1: ), there is a actually way is callAsFunction, even It can't be use in static function and It will look very very confused because it's not named init():
class C {
init() { }
static func callAsFunction(use1: Bool) -> C {
return use1 ? C1() : C2()
}
}
class C1: C { }
class C2: C { }
let c = C(use1: true) // It is impossible now
So there is my simple solution, add a new attribute like @callAsFunction or other name (actually, I think callAsFunction should be done by using attribute from the beginning and make this feature be supported in Type, now just making all function named callAsFunction confusing everyone)
then:
class C {
init() { }
@callAsFunction static func `init`(use1: Bool) -> C {
return use1 ? C1() : C2()
}
}
class C1: C { }
class C2: C { }
let c = C(use1: true)
or
let c = C.`init`(use1: true) // is not good enough but at least it‘s clear
class C {
init() { }
}
extension C {
private class C1: C { }
private class C2: C { }
@callAsFunction static func `init`(use1: Bool) -> C where Self == C { // I think Self == C should be infered successed in Swift 5.3
return use1 ? C1() : C2()
}
}
But having C1 and C2 be private C.C1 and C.C2 makes them inaccessible/unusable outside C, ie if you try to use them outside the scope of C, you'd get this error: 'C1' is inaccessible due to 'private' protection level
which I guess is not what you'd want.
there is a exmaple Generic type not equal in extension
because swift does't support generic type not equal in extension, so I think if I could use a subclass to distinguish when I don't need the userInfo
and I am sorry I make a mistake, init(use1: Bool) -> R where Self == C, R: C is never work, because swift can't infer R, even you use some C
You can get close to what you want by adding a global function with the same name as your class and use that instead of an initializer. No need for language changes.
struct Foo {}
func Foo(bar: Int) {}
> Foo() // creates an instance of Foo
> Foo(bar: 42) // calls the function Foo
Or alternatively just add a static instantiation method to your class: