"Generic parameter 'T' could not be inferred" error in Swift - swift

I am trying to practice "class with generic". I encountered 2 errors:
Generic parameter 'T' could not be inferred
Reference to generic type 'GenericObject' requires arguments in <...>
The 2 errors in GenericManager class. Please reference the following code. How do I solve this issue?
class User {
var name: String
init(name: String) {
self.name = name
}
}
class Employee {
var name: String
var position: String
init(name: String, position: String) {
self.name = name
self.position = position
}
}
class GenericObject<T> {
var items = [T]()
init(forType: T.Type) {}
func addObject(_ obj: T) {
self.items.append(obj)
}
}
class GenericManager {
//issue: Generic parameter 'T' could not be inferred
var objects = [GenericObject]()
//issue: Reference to generic type 'GenericObject' requires arguments in <...>
func addObject(_ obj: GenericObject) {
self.objects.append(obj)
}
}
let u = User(name: "User")
let uo = GenericObject(forType: User.self)
uo.addObject(u)
let e = Employee(name: "Employee", position: "session manager")
let eo = GenericObject(forType: Employee.self)
eo.addObject(e)
let manager = GenericManager()
manager.addObject(uo)
manager.addObject(eo)

The compiler needs to know the type of T, and in this case you haven't supplied it.
You can do it like this:
var objects = [GenericObject<YourTypeHere>]()
For example, if GenericObject will hold an array of Int, it would look like this:
var objects = [GenericObject<Int>]()
I noticed you updated your question. It would be helpful to know what you're trying to achieve, but I'll try to help you anyway.
When you have a generic object, you need to tell the compiler the type of the generic at compile time, that's why it's complaining that the type can't be inferred, it needs to know.
Since you want to be able to add objects to the GenericManager array, you need the generic in those two cases to be the same, so you can modify your class like this:
class GenericManager<T> {
var objects = [GenericObject<T>]()
func addObject(_ obj: GenericObject<T>) {
self.objects.append(obj)
}
}
However, since the objects have to be of the same generic, you can't add a GenericObject<User> and GenericObject<Employee> to the same manager, what you can do is to implement those as GenericObject<Any>, and do the same with the GenericManager, then it will look like this:
let u = User(name: "User")
let uo = GenericObject(forType: Any.self)
uo.addObject(u)
let e = Employee(name: "Employee", position: "session manager")
let eo = GenericObject(forType: Any.self)
eo.addObject(e)
let manager = GenericManager<Any>()
manager.addObject(uo)
manager.addObject(eo)
Keep in mind that this will lose you any advantage that generics would do, what you could do is to create a protocol or common superclass and use that instead of Any, but that depends on what you're trying to achieve.
If you have any further questions, please add a comment instead of silently updating your question.

The problem you are having is that you are trying to use generics, but want to ignore that in GenericManager and store references to objects of different types.
Consider this - when you call manager.objects[0] what would you expect to be returned?
You can solve this by type-erasure using Any as EmilioPelaez suggested. However this is often a codesmell which leads to casting hacks throughout your code.
One alternative would be to use an enum to specify the different types of data you want to represent:
enum GenericObject {
case users([User])
case employees([Employee])
}
...
let uo = GenericObject.users([ u ])
...
let eo = GenericObject.employees([ e ])
Now when you access the properties inside GenericManager you would be required to switch over the different supported types, and when you add a new type you would be required to implement code whenever you use a GenericObject

Related

Cast SomeType<Protocol> to SomeType<ProtocolImpl> in Swift

I'm currently experimenting with Generics in Swift and came to some problem with casting some types around such as SomeType<Protocol> to SomeType<ProtocolImpl>. So basically I have some type that takes a generic parameter which is handled as a Protocol and which at a later point is casted to a more concrete type. My question is if that isn't possible to do?
/// 'dict' is of type [String: SomeType<Protocol>]
if let element = dict["str"], // 'element' here is of type SomeType<Protocol>
let castedElement = element as? SomeType<ProtocolImpl> { // This is always false
return castedElement // Here I want to return castedElement with type SomeType<ProtocolImpl>
}
Is there any way to make this cast work? I'm already working on another solution for my problem, but I'm still interested if there's a way to make this work somehow.
Edit: Because #jtbandes wanted a example he can paste somewhere, here:
class SomeType<T> {
let value: T
init(value: T) {
self.value = value
}
}
protocol Protocol {}
class ProtocolImpl: Protocol {}
var dict: [String: SomeType<Protocol>] = ["str": SomeType(value: ProtocolImpl())]
if let element = dict["str"],
let castedElement = element as? SomeType<ProtocolImpl> {
print(castedElement.value) // I want to get here
}
Long story short, generics in Swift are not covariant, which means that SomeType< ProtocolImpl> is not convertible SomeType<Protocol>, even if ProtocolImpl conforms to Protocol. Thus the direct answer to your question is: this is not currently possible in Swift.
However you might ask yourself is why do you need the downcast in the first place. As you're storing the instances in a container, polymorphic behaviour might be better suited. You could declare the functionality you need to access as part of the protocol, and access is though the protocol interface. This way you don't need to know which is the concrete implementation under the hood, which is one of the main reason of using a protocol.
It's hard for me to tell what you're trying to achieve from the question. Still, maybe the below will help you.
class SomeType<T>: Protocol { // Maybe SomeType IS your ProtoImpl?
let value: T
init(value: T) {
self.value = value
}
}
protocol Protocol {}
//class ProtocolImpl: Protocol {}
//var dict: [String: SomeType<Protocol>] = ["str": SomeType(value: ProtocolImpl())]
var dict: [String: Protocol] = ["str1": SomeType<String>(value: "Some Type"),
"str2": SomeType<Int>(value: 1)
]
if let castedElement = dict["str1"] as? SomeType<String> {
print(castedElement.value) // --> "Some Type"
}
if let castedElement = dict["str2"] as? SomeType<Int> {
print(castedElement.value) // --> "1"
}

Swift Conversion using a variable

Is there anyway to use conversion using a variable? I am using object stacking using type of "AnyObject" and I've been able to take the class type and populate a variable. Now I need to populate an array using conversion.
var myString = "Hello World"
var objectStack = [AnyObject]()
objectStack.append(myString)
let currentObject = String(describing: objectStack.last!)
var objectType = String()
let range: Range<String.Index> = currentObject.range(of: ":")!
objectType = currentObject.substring(to: range.lowerBound)
let range2: Range<String.Index> = objectType.range(of: ".")!
objectType = objectType.substring(from: range2.upperBound)
The code above will evaluate the class and set the value of "objectType" to "String". Now I'm trying to go the other way. Something like this:
for obj in objectStack{
obj = newObject as! objectType //this doesn't work
}
Is something like this possible?
There is a simpler, safer way to get the type:
let type = type(of: objectStack.last!) // String.Type
let typeString = String(describing: type) // "String"
The other way around is not possible because the type of the object is not known at compile time. Do you have a number of known types you want to try to cast to? In that case, use optional binding to check if the cast is successful:
let object = objectStack.last!
if let string = object as? String {
// do String stuff
}
else if let i = object as? Int {
// do Int stuff
}
// and so on
If you have a large number of possible types that share some common functionality: Use Protocols. See Swift Documentation for a nice introduction.
You define a protocol for some common functionality that different types can implement:
protocol Stackable {
func doStuff()
// (more methods or properties if necessary)
}
The protocol provides a contract that all types conforming to this protocol have to fulfill by providing implementations for all declared methods and properties. Let's create a struct that conforms to Stackable:
struct Foo: Stackable {
func doStuff() {
print("Foo is doing stuff.")
}
}
You can also extend existing types to make them conform to a protocol. Let's make String Stackable:
extension String: Stackable {
func doStuff() {
print("'\(self)' is pretending to do stuff.")
}
}
Let's try it out:
let stack: [Stackable] = [Foo(), "Cat"]
for item in stack {
item.doStuff()
}
/*
prints the following:
Foo is doing stuff.
'Cat' is pretending to do stuff.
*/
This worked for me:
var instance: AnyObject! = nil
let classInst = NSClassFromString(objectType) as! NSObject.Type
instance = classInst.init()

How to get all class initializers using reflection in Swift

I'm trying to get all signature of initializer from the class in Swift. Initializer can mirror, I can find the signatures like below code.
enum MessageType {
case say
case shout
case wisper
}
class Message {
var text = ""
var type : MessageType = .say
init(text: String, type: MessageType) {
self.type = type
self.text = text
}
init(text: String) {
self.text = text
}
}
let firstInit = Message.init(text:)
let secondInit = Message.init(text:type:)
let firstMirror = Mirror(reflecting: firstInit)
let secondMirror = Mirror(reflecting: secondInit)
print(firstMirror.subjectType)
// (String) -> Message
print(secondMirror.subjectType)
// ((String, MessageType)) -> Message
However, this code requires to specify init which I want to look it up. What I expected is something like below:
let mirror = Mirror(reflecting: Message)
let inits = mirror.initializers
// something like [Message.init(text:), Message.init(text:type:)] as [Any]
for method in inits {
let mirror = Mirror(reflecting: method)
print(method.subjectType)
}
How can I get all init initializers from class using Mirror?
The Mirror struct in Swift offers some runtime introspection features, but for the default case, these focus on the instance being reflected upon rather than the type of that instance. From the language reference for Mirror:
Mirror
Representation of the sub-structure and optional “display style” of any arbitrary subject instance.
Overview
Describes the parts—such as stored properties, collection elements, tuple elements, or the active enumeration case—that make up
a particular instance. May also supply a “display style” property that
suggests how this structure might be rendered.
You can implement a custom mirror for you Message type by conforming to the CustomReflectable protocol. Implementing a custom mirror with the single purpose of listing available initializers, however, would still require manually supplying the initializer's information to the implementation of the custom mirror.
E.g.:
extension Message: CustomReflectable {
var customMirror: Mirror {
let children = DictionaryLiteral<String, Any>(dictionaryLiteral:
("init(text:)", type(of: Message.init(text:))),
("init(text:type:)", type(of: Message.init(text:type:))))
return Mirror.init(Message.self, children: children,
displayStyle: .class)
}
}
// using your custom mirror
let myMessage = Message(text: "foo")
for case (let label?, let value) in Mirror(reflecting: myMessage).children {
print("\(label), \(value)")
} /* init(text:), (String) -> Message
init(text:type:), ((String, MessageType)) -> Message */
This manual implementation requirement possibly defeats the very purpose of the exercise though. Note also that reflection must still be performed upon an instance rather than the type itself (so possibly it's easier to simply implement a dictionary describing the initializers directly as a static type property; but the manual form of this implementation defeats much of its value).

Cast class type retrieved from string

I'm trying to read a class from a String and pass its type to a generic function. But it seems like there's no way to achieve this:
protocol Person { ... }
class Student: Person { ... }
class Teacher: Person { ... }
func foo<SomePerson: Person>(param: String, type: SomePerson.Type) { ... }
// Get class from string and pass class type to foo()
let someClass = NSClassFromString("MyApp.Teacher")
foo("someParam", type: someClass.dynamicType)
Trying this I'm getting an error:
Cannot invoke 'foo' with an argument list of type '(String, type: AnyClass.Type)
Is it actually possible to obtain the 'real' type 'Teacher' instead of the generic type 'AnyClass' and pass it to foo()? The classes are read on runtime from a file - so using hard class names when calling foo() is not possible.
Thanks for any advice!
If Person is a class as the original question was written:
Since you are making the life for the compiler considerably harder that it needs to be you have to help him a bit. You have to make sure the type is correct before calling the function:
if let actualType = someClass as? Person.Type {
foo("someParam", type: actualType)
} else {
// error handling here
}
Which yields the desired working code:
If Person is a protocol:
You are going to have a bad day. The above solution will not work. As far as I can remember your only option is to check for every possible subclass:
if let actualType = someClass as? Student.Type {
foo("someParam", type: actualType)
} else if let actualType = someClass as? Teacher.Type {
foo("someParam", type: actualType)
}
// etc.

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)
}