Weird ambiguity for class func() in inherited classes [Swift] - swift

I have a simple class hierarchy like this in Swift.
class Parent {
var name:String = "Unnamed"
class func all() -> [Parent] {
return Dad.all() + Mom.all()
}
}
class Dad:Parent {
static var AllDads:[Dad] = []
class func all() -> [Dad] {
return AllDads
}
}
class Mom:Parent {
static var AllMoms:[Mom] = []
class func all() -> [Mom] {
return AllMoms
}
}
Mom.all().forEach { mom in
print(mom.name)
}
If I put this in a workspace, everything is good until I hit the run button. At which point it tells me that the last expression Mom.all() is ambiguous. Why is this? Is there not a way to have a class func which refines in the subclass for the subtype, and keep them unambiguous?

The reason is that the all on Parent and the all on Mom have different signatures. Thus, the all on Mom cannot be an override for that on Parent (also shown by the fact that the compiler does not require the override keyword). What this means is that two class functions named all exist on the Mom type. Furthermore, the closure you are passing to forEach does not specify a parameter type, so it is impossible to be sure of which of the two functions is being referenced. Assigning a type to the mom parameter in the forEach will solve this problem.

Until you instantiate a Mom, and call it on that instance of Mom, it will be ambiguous.

Related

How to implement custom implementation of method?

I'm drawing a blank for some reason.. If I want to make a bunch of objects from a class, but I want each instance to have its own unique implementation of a certain method, how would I do this?
For example:
class MyClass {
var name: String
func doSomething() {
// Each object would have custom implementation of this method, here.
}
}
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method? I'm trying to figure out the correct or "Swiftly" way to do this. I'm also thinking along the lines of something with protocols, but I can't seem to figure out how to go about this.
I think there're many ways to do it.
In case of Base class + some sub-classes (e.g. Animal, subclassed by Dog, Cat, etc), you can do this:
First of all it's a good idea to define a protocol:
protocol MyProtocol {
func doSomething()
}
Also provide a default implementation, which throws a fatal error if a class doesn't override that method:
extension MyProtocol {
func doSomething() {
fatalError("You must override me")
}
}
Now your base class confirms the protocol thanks to default implementation. But it will throw a fatal error at runtime:
class MyClass: MyProtocol {
// conformant
}
Child class, however, will run correctly as long as it overrides this function:
class MyOtherClass: MyClass {
func doSomething() {
print("Doing it!")
}
}
You could also move fatal error into base class, and not do any extension implementation.
In case of many instances of the same Class, that solution makes no sense. You can use a very simple callback design:
typealias MyDelegate = () -> Void
class MyClass {
var delegate: MyDelegate?
func doSomething() {
delegate?()
}
}
let x = MyClass()
x.delegate = {
print("do it!")
}
x.doSomething()
// Or you can use a defined function
func doIt() {
print("also doing it")
}
x.delegate = doIt
x.doSomething()
It can also be that you re looking for Strategy pattern, or Template pattern. Depends on your usage details.
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method
Yes. That is extremely common and eminently Swifty. Incredibly miminalistic example:
struct S {
let f:()->()
func doYourThing() { f() }
}
let s = S { print("hello") }
let s2 = S { print("goodbye" )}
s.doYourThing() // hello
s2.doYourThing() // goodbye
Giving an object a settable method instance property is very, very easy and common. It doesn't have to be provided during initialization — you might set this property later on, and a lot of built-in objects work that way too.
That, after all, is all you're doing when you create a data task with dataTask(with:completionHandler:). You are creating a data task and handing it a function which it stores, and which it will call when it has performed the actual networking.

How to get class type statically in swift

As the question may seem duplicated, I point out first that this is not asking for how to get a class type from an instance ( answer is using type(of:) ).
protocol Owner {
static func name() -> String
}
extension Owner {
static func name() -> String {
return "\(self)"
}
}
class Foo {
var ownerName: String
init(with owner: Owner.Type) {
ownerName = owner.name()
}
}
class Bar: Owner {
var foo = Foo(with: Bar.self)
}
The code above simply works, but imagine that I want to rename the class Bar to BarBar then I need to change the initialization of foo to Foo(with: BarBar.self) manually. Is there any keyword that can be used instead of ClassName.self (e.g. Bar.self BarBar.self) to get the class type? Something like Self or Class (they don't compile actually)
My guess is that your whole question is a red herring and that type(of:self) is exactly what you want to say. In that case, the problem is merely that var foo is declared as an instance property. There are special rules for when you are allowed to say self while initializing an instance property (rightly, because self is exactly what does not yet exist during initialization). However, there are ways around that, as I have explained elsewhere; you can make this a computed instance property, or a lazy instance property, which is initialized by a function to be executed later, and then you are allowed to say type(of:self).

Calling a method from a struct within the same class

I'd like to logically organize class properties to signify that they are one logical unit and to distinguish them from other class properties that are less tightly related.
I thought of doing this using a struct within my class. However, it seems that I can't call class methods from the struct property setters. I get what seems to be an inappropriate compile error: "missing argument for parameter #1 in call"
This seems to be different from calling method from struct in swift
where the function is within the struct. In my case, the methods are generic and don't just apply to my struct but to all class properties. Therefore, I don't want to move them within the struct.
Do you have ideas on how to organize properties into tight(er) logical units within classes?
class MyClass {
struct MyStruct {
static var aVarInMyStruct: String? {
didSet {
anotherVarInMyStruct = foo() // This gives compile error "missing argument for parameter #1 in call"
}
}
static var anotherVarInMyStruct: String?
}
func foo() {
println("I am foo()")
}
}
The inner type MyStruct knows nothing about its outer type MyClass. So there is no foo function to call from MyStruct. To better organize your code I suggest you to use // MARK: - whatever this section is comments. Types are not here to organize codes. Types are here to create right abstractions for the program.
I fix your bug:
class MyClass {
struct MyStruct {
static var aVarInMyStruct: String? {
didSet {
anotherVarInMyStruct = MyClass.foo() // This gives compile error "missing argument for parameter #1 in call"
}
}
static var anotherVarInMyStruct: String?
}
static func foo()->String {
println("I am foo()")
return "it is ok"
}
}

Instantiate class from protocol type

I am writing method which takes a type which conforms to a protocol and instantiates an instance of this class. When I build it, the compiler crashes with a segfault. I appreciate that this points to a compiler bug 99% of the time, but I am interested to see if what I'm trying to do is logically correct or am I just throwing absolute nonsense at the compiler and I shouldn't be surprised to see it crash.
Here is my code
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
class ClassCreator {
class func createClass(classType: CreatableClass.Type) -> CreatableClass {
return classType()
}
}
ClassCreator.createClass(ExampleClass.self)
I also tried to rule out passing a Type as a method parameter as being the root of the problem and the following code also crashes the compiler:
protocol CreatableClass {
init()
}
class ExampleClass : CreatableClass {
required init() {
}
}
let classType: CreatableClass.Type = CreatableClass.self
let instance = classType()
So - is this just a straightforward compiler bug and does what I am trying to do seem reasonable, or is there something in my implementation that is wrong?
Edit:
This can be achieved using generics as shown #Antonio below but unfortunately i believe that isn't useful for my application.
The actual non-dumbed down use-case for doing this is something like
protocol CreatableClass {}
protocol AnotherProtocol: class {}
class ClassCreator {
let dictionary: [String : CreatableClass]
func addHandlerForType(type: AnotherProtocol.Type, handler: CreatableClass.Type) {
let className: String = aMethodThatGetsClassNameAsAString(type)
dictionary[className] = handler()
}
required init() {}
}
I usually do that by defining a generic method. Try this:
class func createClass<T: CreatableClass>(classType: T.Type) -> CreatableClass {
return classType()
}
Update
A possible workaround is to pass a closure creating a class instance, rather than passing its type:
class ClassCreator {
class func createClass(instantiator: () -> CreatableClass) -> (CreatableClass, CreatableClass.Type) {
let instance = instantiator()
let classType = instance.dynamicType
return (instance, classType)
}
}
let ret = ClassCreator.createClass { ExampleClass() }
The advantage in this case is that you can store the closure in a dictionary for example, and create more instances on demand by just knowing the key (which is something in 1:1 relationship with the class name).
I used that method in a tiny dependency injection framework I developed months ago, which I realized it works only for #objc-compatible classes only though, making it not usable for my needs...

Generic Types Collection

Building on previous question which got resolved, but it led to another problem. If protocol/class types are stored in a collection, retrieving and instantiating them back throws an error. a hypothetical example is below. The paradigm is based on "Program to Interface not an implementation" What does it mean to "program to an interface"?
instantiate from protocol.Type reference dynamically at runtime
public protocol ISpeakable {
init()
func speak()
}
class Cat : ISpeakable {
required init() {}
func speak() {
println("Meow");
}
}
class Dog : ISpeakable {
required init() {}
func speak() {
println("Woof");
}
}
//Test class is not aware of the specific implementations of ISpeakable at compile time
class Test {
func instantiateAndCallSpeak<T: ISpeakable>(Animal:T.Type) {
let animal = Animal()
animal.speak()
}
}
// Users of the Test class are aware of the specific implementations at compile/runtime
//works
let t = Test()
t.instantiateAndCallSpeak(Cat.self)
t.instantiateAndCallSpeak(Dog.self)
//doesn't work if types are retrieved from a collection
//Uncomment to show Error - IAnimal.Type is not convertible to T.Type
var animals: [ISpeakable.Type] = [Cat.self, Dog.self, Cat.self]
for animal in animals {
//t.instantiateAndCallSpeak(animal) //throws error
}
for (index:Int, value:ISpeakable.Type) in enumerate(animals) {
//t.instantiateAndCallSpeak(value) //throws error
}
Edit - My current workaround to iterate through collection but of course it's limiting as the api has to know all sorts of implementations. The other limitation is subclasses of these types (for instance PersianCat, GermanShepherd) will not have their overridden functions called or I go to Objective-C for rescue (NSClassFromString etc.) or wait for SWIFT to support this feature.
Note (background): these types are pushed into array by users of the utility and for loop is executed on notification
var animals: [ISpeakable.Type] = [Cat.self, Dog.self, Cat.self]
for Animal in animals {
if Animal is Cat.Type {
if let AnimalClass = Animal as? Cat.Type {
var instance = AnimalClass()
instance.speak()
}
} else if Animal is Dog.Type {
if let AnimalClass = Animal as? Dog.Type {
var instance = AnimalClass()
instance.speak()
}
}
}
Basically the answer is: correct, you can't do that. Swift needs to determine the concrete types of type parameters at compile time, not at runtime. This comes up in a lot of little corner cases. For instance, you can't construct a generic closure and store it in a variable without type-specifying it.
This can be a little clearer if we boil it down to a minimal test case
protocol Creatable { init() }
struct Object : Creatable { init() {} }
func instantiate<T: Creatable>(Thing: T.Type) -> T {
return Thing()
}
// works. object is of type "Object"
let object = instantiate(Object.self) // (1)
// 'Creatable.Type' is not convertible to 'T.Type'
let type: Creatable.Type = Object.self
let thing = instantiate(type) // (2)
At line 1, the compiler has a question: what type should T be in this instance of instantiate? And that's easy, it should be Object. That's a concrete type, so everything is fine.
At line 2, there's no concrete type that Swift can make T. All it has is Creatable, which is an abstract type (we know by code inspection the actual value of type, but Swift doesn't consider the value, just the type). It's ok to take and return protocols, but it's not ok to make them into type parameters. It's just not legal Swift today.
This is hinted at in the Swift Programming Language: Generic Parameters and Arguments:
When you declare a generic type, function, or initializer, you specify the type parameters that the generic type, function, or initializer can work with. These type parameters act as placeholders that are replaced by actual concrete type arguments when an instance of a generic type is created or a generic function or initializer is called. (emphasis mine)
You'll need to do whatever you're trying to do another way in Swift.
As a fun bonus, try explicitly asking for the impossible:
let thing = instantiate(Creatable.self)
And... swift crashes.
From your further comments, I think closures do exactly what you're looking for. You've made your protocol require trivial construction (init()), but that's an unnecessary restriction. You just need the caller to tell the function how to construct the object. That's easy with a closure, and there is no need for type parameterization at all this way. This isn't a work-around; I believe this is the better way to implement that pattern you're describing. Consider the following (some minor changes to make the example more Swift-like):
// Removed init(). There's no need for it to be trivially creatable.
// Cocoa protocols that indicate a method generally end in "ing"
// (NSCopying, NSCoding, NSLocking). They do not include "I"
public protocol Speaking {
func speak()
}
// Converted these to structs since that's all that's required for
// this example, but it works as well for classes.
struct Cat : Speaking {
func speak() {
println("Meow");
}
}
struct Dog : Speaking {
func speak() {
println("Woof");
}
}
// Demonstrating a more complex object that is easy with closures,
// but hard with your original protocol
struct Person: Speaking {
let name: String
func speak() {
println("My name is \(name)")
}
}
// Removed Test class. There was no need for it in the example,
// but it works fine if you add it.
// You pass a closure that returns a Speaking. We don't care *how* it does
// that. It doesn't have to be by construction. It could return an existing one.
func instantiateAndCallSpeak(builder: () -> Speaking) {
let animal = builder()
animal.speak()
}
// Can call with an immediate form.
// Note that Cat and Dog are not created here. They are not created until builder()
// is called above. #autoclosure would avoid the braces, but I typically avoid it.
instantiateAndCallSpeak { Cat() }
instantiateAndCallSpeak { Dog() }
// Can put them in an array, though we do have to specify the type here. You could
// create a "typealias SpeakingBuilder = () -> Speaking" if that came up a lot.
// Again note that no Speaking objects are created here. These are closures that
// will generate objects when applied.
// Notice how easy it is to pass parameters here? These don't all have to have the
// same initializers.
let animalBuilders: [() -> Speaking] = [{ Cat() } , { Dog() }, { Person(name: "Rob") }]
for animal in animalBuilders {
instantiateAndCallSpeak(animal)
}