Cannot override initialiser in subclass of generic class - swift

I'd like to make a subclass of a generic class that is itself a subclass but I cannot override the initializer.
To clarify:
class BaseClass {
init(printMe: String) {
print(printMe)
}
}
class GenericClass<T>: BaseClass {
var object: T?
}
class NotGenericClass: GenericClass<NSNumber> {
override init(printMe: String) { // <- Error here
super.init(printMe: printMe)
// More setup
}
}
let a = NotGenericClass(printMe: "Print this")
a.object = NSNumber(int: 1)
The override init(printMe: String) line in NotGenericClass gives the following error:
Initializer does not override a designated initializer from its superclass
If GenericClass did not take a type parameter, this code would work. Is this a bug with Swift or am I misunderstanding how subclassing generic classes should work?

It seems that GenericClass doesn't automatically inherit the initializer in this case.
This makes it work:
class GenericClass<T>: BaseClass {
var object: T?
// Explicitly provide an initializer
override init(printMe: String) {
super.init(printMe: printMe)
}
}
This isn't clear from the Automatic Initializer Inheritance section of the docs, which claims that "If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers". You might want to file a bug.

Related

Swift initializer inheritance

Can you tell me why the superclass initializer gets called because I never call it from the initializer in subclass ?
Regarding the two step process of the initialization, I thought that the compiler would throw an error because I didn't call super.init() actually
class Superclass {
var a: Int
init() {
self.a = 1
}
}
class Subclass: Superclass {
var b: Int
override init() {
self.b = 2
}
}
var subclass = Subclass()
print(subclass.b)
// Print 2
print(subclass.a)
// Print 1 => How is it possible as I never call super.init() ?
The compiler can synthesise a call to super.init() in a designated initialiser if you don't make the call yourself. So in your case the compiler effectively transforms your code to:
class Superclass {
var a: Int
init() {
self.a = 1
}
}
class Subclass : Superclass {
var b: Int
override init() {
self.b = 2
super.init() // synthesised by the compiler
}
}
This also applies to cases where you're not overriding the superclass' init():
class Subclass : Superclass {
var b: Int
init(b: Int) {
self.b = b
super.init() // also synthesised by the compiler (try removing)
}
}
Note that this synthesis comes with some restrictions, it only applies when:
The superclass has one and only one designated initialiser
This designated initialiser doesn't have any parameters, i.e init()
In all other cases you need to call super.init yourself.

Swift 4 generic, referencing self

I'm considering the following structure using Swift 4:
class BaseClass {
// abstract function
func doSomething<T: BaseClass>(with object: T) {}
}
class SubClass: BaseClass {
var title: String = "hello world"
// implementation
override func doSomething<T: BaseClass>(with object: T) {
// do something with object
// can I access object.title here?
}
}
In the above snippet the object.title property is not accessible, because apparently type of object property is BaseClass, not SubClass.
I assume the function parameter type should be set as Self, such as:
func doSomething(with object: Self) {}
but the following error occurs while compilation.
'Self' is only available in a protocol or as the result of a method in a class; did you mean 'BaseClass'?
Is there a way to reference type of self while overriding functions from base class?
Edit
So my question is whether we can access SubClass's properties inside functions that overrides super class's functions (as object.title property is in SubClass implementation). I was considering a whole lot of classes that inherit base class, so I thought it might be useful to have functions that interacts with another instance with the same type when called.
You cannot create a function kike func doSomething(with object: Self) {} since it would mean different things in those classes (and thus, would not overwrite each other semantically)
Think about calling the subclass with a BaseClass object, that is not a Subclass, if you had a method with Self like you showed in your snippet, it would be implemented by the supperclass, but the subclass would not implement it anymore.
But, you can cast it like this in the subclass:
override func doSomething<T: BaseClass>(with object: T) {
guard let subClass = object as? SubClass else { return }
print("\(title): \(subClass.title)")
}

Swift: Implementing Protocol Initializer in a Class

I am trying to understand why Swift enforces a class that conforms to a protocol with an initializer to be marked as required. This essentially enforces any subclasses to also implement that initializer. Surely the designated superclass initializer would be inherited?
The quotes below are taken from the Swift Language Guide:
https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID272
You can implement a protocol initializer requirement on a conforming
class as either a designated initializer or a convenience initializer.
In both cases, you must mark the initializer implementation with the
required modifier:
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init(someParameter: Int) { // enforced to implement init again
// initializer implementation goes here
}
}
The use of the required modifier ensures that you provide an explicit
or inherited implementation of the initializer requirement on all
subclasses of the conforming class, such that they also conform to the
protocol.
EDIT:
I had not initially mentioned that I am currently limited to Swift 2.1. It appears to be a compiler issue in this release and does not occur in later versions.
Surely the designated superclass initializer would be inherited?
No, not always. If the subclass defines its own designated initialisers, then it won't automatically inherit the superclass' designated initialisers. Consider the following example:
class Foo {
init() {}
}
class Bar : Foo {
var str: String
init(str: String) {
self.str = str
}
}
let b = Bar() // illegal – what value would the 'str' property have?
As Bar defines its own init(str:) designated initialiser, it doesn't automatically inherit Foo's designated initialiser init(). This prevents unsafe initialisation in cases where the subclass declares its own stored properties.
Marking init() as required enforces Bar has an init(), be it through providing its own implementation:
class Foo {
required init() {}
}
class Bar : Foo {
var str: String
init(str: String) {
self.str = str
}
// implement required init(), as Bar defines its own designated initialiser.
required init() {
self.str = "foo" // now str is correctly initialised when calling init()
}
}
let b = Bar() // now legal
Or by inheriting Foo's implementation (when Bar doesn't define its own designated initialisers):
class Foo {
required init() {}
}
class Bar : Foo {
// inherits init() from Foo, as Bar doesn't define its own designed initialisers.
}
let b = Bar() // legal
You're not force to implement the initializer in the subclass. Consider this example, which compiles just fine:
protocol SomeProtocol {
init(someParameter: Int)
}
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
print(someParameter)
}
}
class SomeSubclass: SomeClass {
// Notice that no inits are implemented here
}
_ = SomeClass(someParameter: 123)
_ = SomeSubclass(someParameter: 456)

swift: How can I override a public method in superclass to be a private method in subclass

I have a super class
class Father {
public func doSomething() {
}
}
I want this child class to be
class Child: Father {
private override func doSomething() {
}
}
but Xcode says that
Overriding instance method must be as accessible as the declaration it
overrides
so, how can I override a public method in superclass be a private method in subclass
THANK YOU
You can't because that would violate the Liskov Substitution Principle.
Essentially, any code that can operate on an instance of a superclass must also be able to operate on an instance of your subclass.
So, if some other class has a method
class Unrelated {
func operateOnAThing(_ someThing:Father) {
someThing.doSomething()
}
}
then it still has to work when you do the following:
let aChild = Child()
unrelatedInstance.operateOnAThing(aChild)
If the doSomething method had more restrictive access in the Child class then you would get a runtime error. To prevent this, you cannot make access more restrictive in a subclass.
You can achieve that by marking the public method as unavailable using the #available attribute. Then, call the method using super in the private method.
Example:
class Father {
public func doSomething() {
print("doSomething privatly")
}
}
class Child: Father {
#available (*, unavailable)
override func doSomething() {
}
fileprivate func internal_doSomething() {
super.doSomething()
}
}
Child().internal_doSomething()
Child().doSomething() //'doSomething()' has been explicitly marked unavailable
(Tested using Swift 4.0!)

Swift: overriding typealias inside subclass

So I was thinking about a custom pattern in my project, but I can't get it to work. The main idea is to change the typealias on every subclass to get access to the subclass specific interface.
protocol InstanceInterface: class {
typealias Interface
var interface: Interface { get }
}
// Baseclass
protocol FirstClassInterface: class { /* nothing here for the example */ }
class FirstClass: InstanceInterface, FirstClassInterface {
typealias Interface = FirstClassInterface
var interface: Interface { return self }
}
// Subclass
protocol SecondClassInterface: FirstClassInterface {
func foo()
}
class SecondClass: FirstClass, SecondClassInterface {
typealias Interface = SecondClassInterface // <--- This does nothing :(
func foo() { print("hello world") } // Swift 2.0 here
}
// Lets say I want to call foo trough the interface
let test = SecondClass()
test.interface.foo() // 'Interface' does not have a member named 'foo'
Is there something I'm doing wrong or do I misunderstand some Swift concepts here?! I do need to subclass here to not to implement everything from super class' protocols over and over again. Is my little pattern even possible? I'd appreciate any help. :)
Would something like this work for your purposes?
class MyClass<T> {
}
class MySubclass1: MyClass<String> {
}
class MySubclass2: MyClass<Int> {
}
Unfortunately there is no good workaround for this problem.
The main idea to override the typealias would work in this case but consider the following:
protocol TakeAndGet {
typealias T
func take(value: T)
func get() -> T
}
class FirstClass: TakeAndGet {
typealias T = FirstClass
var property = 0
func take(value: T) {
value.property = 4
}
func get() -> T {
return FirstClass()
}
}
class SecondClass: FirstClass {
typealias T = SecondClass
var property2 = "hello"
}
If the typealias of the SecondClass overrides the other one the take method would work since it takes a subclass which can be treated as the superclass. But the get method cannot implicitly convert FirstClass to SecondClass. Therefore it is not possible to override a typealias.
Now if we want to override the get function with get() -> SecondClass it wouldn't work since it has not the same signature as the one in the superclass. In addition we inherit the get method which results in an ambiguous use:
SecondClass().get() // which type gets returned? SecondClass or FirstClass
So you have to try a different approach.