Swift Generics & Upcasting - ios

I've got a quick question regarding generics in Swift. The problem is I'm trying to store a variable that takes a generic as a parameter, but am unable to cast it up to the type it is restricted by. It's best explained in a short example:
class Foo { }
class Thing<T: Foo> {
func produceBar() -> Bar {
return Bar(aThing: self as! Thing<Foo>)
}
}
class Bar {
var thing: Thing<Foo>
init(var aThing: Thing<Foo>) {
self.thing = aThing
}
}
The code above produces the error: "Cast from Thing<T> to unrelated type Thing<Foo> always fails"
Shouldn't it never fail, since T is restricted to being a subclass of Foo? I must be misunderstanding the way generics work in Swift, any guidance or help would be much appreciated!

Swift generics are not covariant. That is to say, exactly what the error says: you can't automatically say a Basket<Apple> is a kind of Basket<Fruit> even if Apple is a kind of Fruit. There is good reason for this.
Consider the following code:
class Fruit {}
class Apple: Fruit {}
class Orange: Fruit {}
class Basket<T: Fruit> {
private var items: [T]
func add(item: T) {
items.append(item)
}
init() {}
}
func addItem<T: Fruit>(var basket: Basket<T>, item: T) {
basket.add(item)
}
let basket:Basket<Apple> = Basket()
addItem(basket as Basket<Fruit>, Orange())
This would be legal code if Basket<Apple> were considered a Basket<Fruit>, and I'd be allowed to add an orange to a basket of apples.

Related

Initialiser Inheritance confusion

I am trying to build some mocking infrastructure, I want to be able to return a stubbed value and count the times the value was accessed. I have something simple like this:
class BasicMock<T> {
var callsCount = 0
private let backing: T
var result: T {
callsCount++
return backing
}
init(result: T) {
self.backing = result
}
}
class MockTimeDefinitionSerialiser: BasicMock<[String: [AnyObject]]>, TimeDefinitionSerialiserProtocol {
func serialiseTravelTime(travelTime: JSSTravelTime) -> [String: AnyObject] {
return result
}
}
However trying to build it:
let mockTimeDefinitionSerialiser = MockTimeDefinitionSerialiser(result: ["": ""])
Emits the error 'MockTimeDefinitionSerialiser' cannot be constructed because it has no accessible initialisers
My interpretation of the Swift docs is that I should automatically inherit the initialiser as I have set all stored properties.
What am I doing wrong?
Please remove any unnecessary code when asking a question. I was able to reduce your problem to this:
class Base<T> {
init(t: T) {}
}
class Sub: Base<Int> {}
Sub(t: 0) // error: 'Sub' cannot be constructed because it has no accessible initialisers
It seems like even though you specified the T in the subclass, the compiler cannot infer what the initialiser uses for T. I couldn't find a way to get the initialiser to be inherited, you'd have to use a workaround:
class Sub: Base<Int> {
override init(t: Int) {
super.init(t: t)
}
}

Cannot invoke 'handler' with argument list of type '([Post])'

I both do, and don't get why the last line of this playground throws a compiler error:
protocol Model { }
struct Post: Model {
var content = "Hello"
}
struct Posts: Model {
var allPosts: [Post] = [Post(), Post(), Post()]
}
func handler(items: [Model]) { }
var posts = Posts()
handler(posts.posts)
If you're reading between the lines, my goal is to be able to invoke a function with an argument that is an array of structs that conform to a protocol. The function should be able to deal with arrays of different types of structs. Would love to know what I'm missing, and if you have a suggestion for a better solution.
Thanks!
It seems to be Swift limitations. But you can do some workaround like this using Generics:
func handler<T: Model>(items: [T]) { }
or else make your protocol a #objc protocol which you can only apply to class type:
#objc protocol Model { }
class Post: Model {
var content = "Hello"
}

A static field inherited from the base class or protocol - how?

I want to be able to have the classes which have a static property (field) which is either inherited from the base class or "mixed" from a protocol. And every class should have it's own implementation of that property. Is it possible? Preferably, it to be immutable.
class C1 {
static let stProperty = "my prorepty1"
}
class C2 {
static let stProperty = "my prorepty2"
}
It's possible, but it's really hard to make this useful in Swift. How do you plan to refer to this property? Let's start with a super-simple implementation:
protocol SomeProtocol {
static var prop: String { get }
}
class C1: SomeProtocol {
static let prop = "This is One"
}
Great. So now I want a function that uses this:
func useProp(x: SomeProtocol) -> String {
return x.prop
// 'SomeProtocol' does not have a member named 'prop'
}
That doesn't work. x is an instance, but I want the type.
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
func useProp(x: SomeProtocol.Type) -> String {
return x.prop
}
This is probably how it will work some day given the word "unimplemented." But it doesn't work today.
func useProp(x: SomeProtocol) -> String {
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
return x.dynamicType.prop
}
Same thing.
Today, you really have to hang this on the object itself and not use static or class:
protocol SomeProtocol {
var prop: String { get }
}
class C1: SomeProtocol {
let prop = "This is One"
}
func useProp(x: SomeProtocol) -> String {
return x.prop
}
That's not so terrible in many cases, since the value for the class is probably also the value for any given instance of the class. And it's really all we can do today.
Of course your problem might be that you don't have an instance yet and you need this information to build an instance. That's really hard today and you should probably rethink your design. You'll generally have to use some other pattern like a Builder. See Generic Types Collection for more.
Now you also said:
or "mixed" from a protocol
I wouldn't say "mixed" here. If you really mean this like a Ruby "mixin", there is no such thing in Swift today. Swift folks often refer to this feature as "default implementation," and it's not currently possible (though I do expect it to come eventually). The only thing you can do in the protocol is say that the implementor has to provide this method somehow. You can't provide it for them.
Sure you can do that with a protocol:
protocol SomeProtocol {
static var foo: String { get }
}
class One: SomeProtocol {
class var foo: String {
get {
return "This is One"
}
}
}
Btw I agree with Rob Napier below that this is a bit off a oddball feature. I do think there are probably use-cases for it, but I also think those can be better implemented with other language features
protocol P {
class var stProperty: String { get }
}
class C1 {
class var stProperty: String {
return = "my property1"
}
}
class C2 {
class var stProperty: String {
return = "my property2"
}
}
Usage:
C2.prop //"my property2"
If you try:
C2.prop = "new value" //"cannot assign to the result of this expression"

Generic on class that is subclassed

In my application written in Swift, I have the following class structure. Class A has a static method which does some stuff, but in a very simple form it looks like the code below.
class A {
class func create<T: A>() -> T? {
println(NSStringFromClass(T));
return nil;
}
}
Class B is subclassed from class A.
class B : A {
}
Now, when I execute the following code, the println command outputs A instead of B.
var myVar:B? = B.create();
I am not sure what I am doing wrong here, but I would expect it to output B.
When debugging and putting a breakpoint in the create method, the value $swift.type.T is defined as a Builtin.RawPointer MyApp.A instead of B.
Your generic class method on A doesn't make sense to me. Instead I would actually use something like the code below. This way it creates an instance of Self, which is whatever class you call it on. No need for generics in this case.
class A {
required init() {}
class func create() -> Self {
return self()
}
func test() -> String {
return "A"
}
}
class B : A {
override func test() -> String {
return "B"
}
}
let b = B.create() // "{A}" according to the playground, but it is a "B" instance!
b.test() // "B"
Please note that A needs a required initializer because the use of Self. When doing it in playground, the created instance is shown as {A} on the right. This is an error in Xcode I believe, the actual type is correct.
Edit:
I believe the code above isn't what you were looking for exactly, now I do get what you're trying to do. I would suggest not doing that by depending on the actual class name, but using a generic class to create the instances for you:
protocol Entity {
init()
class func entityName() -> String
}
class EntityFactory<T : Entity> {
class func newEntity() -> T? {
var entity: T?
// ... create entity here using T.entityName()
return entity
}
}
class Person : Entity {
required init() {}
class func entityName() -> String {
return "Person"
}
}
let person = EntityFactory<Person>.newEntity()
Think this is a more elegant solution, which moves the responsibility of creating an entity to a separate generic class. This results in code that is maintainable and testable. You can even abstract it out further for i.e. unit testing purposes, but that seems a bit out of scope here.

Cannot convert the expression's type 'StaticString' to type 'StringLiteralConvertible' (Swift)

Generics in a programming language that runs on iOS? Shut up and take my money!
Here's my experimental code (this is running in a playground):
class Foo<GenericType1> {
var value:GenericType1?
init(value:GenericType1) {
self.value = value;
}
}
class Foo2<GenericType2> : Foo<GenericType2> {
override init(value:GenericType2) {
super.init(value:value);
}
}
extension Foo {
class func floop<T>(value: T) -> Foo2<T> {
return Foo2<T>(value:value)
}
}
Followed by:
var foo = Foo.floop("test")
The last part throws an error message:
Cannot convert the expression's type 'StaticString' to type 'StringLiteralConvertible'
I can't for the life of me figure out why. Any help would be much appreciated.
I found a similar problem and I could make it work by specifying the type at the moment of instantiating the class, i.e. you must tell what type the generic will have once the class is instantiated, in your case it could be something like this:
var foo = Foo<String>.floop("test") //or,
var foo = Foo<Int>.floop("test")
I tried it in your code and it worked in a playground.
Hope this helps!

Resources