cannot invoke 'append' with an argument list of type '(T)' - arrays

Just got this strange error when trying to write a stack with generic type in latest playground.
I really don't understand what's wrong here, can someone explain to me why I got this error?
class MyStack<T> {
var stack1 = [T]()
func push<T>(value: T) {
stack1.append(value) // Error: cannot invoke 'append' with an argument list of type '(T)'
}
}

The class is already generic, no need to make push generic too
class MyStack<T> {
var stack1 = [T]()
func push(value: T) {
stack1.append(value)
}
}
When push is declared as push<T>, the generic parameter overrides the one defined on the class. So, if we were to rename the generic parameters, we'd get
class MyStack<T1> {
var stack1 = [T1]()
func push<T2>(value: T2) {
stack1.append(value) // Error: cannot invoke 'append' with an argument list of type '(T2)'
}
}
presented like this, it makes sense that we cannot push a T2 in [T1].

Related

SWIFT iterating through structures - issue

Im trying to iterate thorough and array of structures using generics and I keep getting this error. Value of type [T] has no member 'printMessage'
My 2nd questions is - What message would print? The statement in the Foo protocol extension or the statement in the struct instance?
Not sure what the issue is.. and its driving me insane!
protocol Foo {
func printMessage()
}
extension Foo {
func printMessage() {
print("Hello")
}
}
struct test: Foo {
func printMessage() {
print("Goodbye")
}
}
func MessagePrinter<T: Foo>(for message: [T]) {
for message in [message] {
message.printMessage()
}
For more clarity name the array in plural form and and the element in singular form.
And the square brackets in the for loop are wrong, the parameter is already an array
func messagePrinter<T: Foo>(for messages: [T]) {
for message in messages {
message.printMessage()
}
}
And please name functions always with starting lowercase letter.
The method in the protocol extension is called unless the method is implemented.
But consider that T is a single concrete type at runtime, you cannot call the method on a heterogenous Foo array like this
let messages : [Foo] = [Test()]
messagePrinter(for: messages)
You will get the error
Protocol 'Foo' as a type cannot conform to the protocol itself
To be able to call the method on an heterogenous array whose elements conform to Foo you have to declare
func messagePrinter(for messages: [Foo]) { ...
You are wrapping an array in another array here:
func MessagePrinter<T: Foo>(for messages: [T]) {
for message in [messages] {
message.printMessage()
}
}
(I've renamed your function argument from message to messages to make it clearer.)
When you write [messages] you end up with an array containing another array containing T, so the type is [[T]]. The single element message thus has type [T], and an array has no method printMessage.
What you want is this:
func MessagePrinter<T: Foo>(for messages: [T]) {
for message in messages {
message.printMessage()
}
}
As for what's printed when you execute it: that depends on what elements you feed it. If the elements implement printMessage those methods are called (e.g. "Goodbye"). Otherwise the default implementation you have provided for the protocol is called ("Hello").

Array of generic classes and subclassing

I'm having trouble wrapping my head around generics. What I want is to have an array of generic classes, each with it's own associated type, and call a function accordingly. It would look something like this:
class SomeGenericClass<U> {
func addCallback(callback: (U)->() ) { ... }
}
var array: [SomeGenericClass] // compile error
The last line yields an error, so I found that I needed to have a superclass. I tried something like this:
class SuperClass {
func addCallback<V>(callback: (V)->() ) { ... }
}
class SomeGenericClass<U> {
func addCallback<V: U>(callback: (V)->() ) { ... } // compile error
}
var array: [SuperClass] // no compile error
This yields the error Type 'V' constrained to non-protocol, non-class type 'U'.
Basically I want to be able to do:
array.append(SomeGenericClass<UIImage>()) // array[0]
array.append(SomeGenericClass<Int>()) // array[1]
// Since array[0] is effectively of type SomeGenericClass<UIImage>, the compiler should understand that the close added if of type (UIImage)->(), and therefore that value is of type UIImage
array[0].addCallback { value in
someImageView.image = value
}
Is using a superclass the right approach in this case? How should it be implemented?
I worked around this problem by storing my array members in their own variable. That is, instead of defining my array like:
lazy var array: [SuperClass] = [
SomeGenericClass<UIImage>(),
SomeGenericClass<Int>(),
//etc...
]
I defined it this way:
lazy var genericFirst: SomeGenericClass<UIImage> = SomeGenericClass<UIImage>()
lazy var genericSecond: SomeGenericClass<Int> = SomeGenericClass<Int>()
// etc...
lazy var array: [SuperClass] = [
genericFirst,
genericSecond,
//etc...
]
This way, I can access the generics I want like this:
genericFirst.addCallback { value in
// value is indeed of type UIImage
someImageView.image = value
}

Typescript: extending IterableIterator for array type but return a simple type

I am trying to extend the IterableIterator with a method similar to Array.flat(). Writing the method itself is no problem, extending the interface for IterableIterator is also easy. So the javascript part is under control. Unfortunately I can't get the typescript compiler to understand what I want.
How should I declare Flatten in IterableIterator for item to be understood by typescript as a number and not as a number[] like it is now?
NOTE: if I wrap total+=item with if(item instanceof number) {} the method works. Just for completion the method looks currently like this:
function* iterable_flatten<T>(this: Iterable<T[]>): Generator<T> {
for (let item of this) {
for (let itemitem of item)
yield itemitem;
}
}
After reading this article I found out that the solution is to create a type which infers the base type of the array :
type BaseTypeOfArray<T> = T extends Array<infer I> ? I : "never";
And then use it to get the base type in the declaration:
flatten(this: Iterable<T>): Generator<BaseTypeOfArray<T>>;

Generic Parameter T could not be inferred with optional generic array

I have a method in my Model class that has signature below:
func parse<T: Codable>(data: Data) throws -> Array<T>?
When I call the method in another class, Facade, I get the
Generic Parameter T could not be inferred
Calling function as below
if let data = data {
do{
let parsedArray = try self.model.parse(data: data);
}
catch{
print(error)
}
gives me the compiler warning on the line where I call the parse function.
You need to explicitly declare the type of the variable you are setting or add another parameter to the parse method and pass the desired type:
let parsedArray: [YourType] = try model.parse(data: data)

Address of Array & Remove(at :) IOS

I'm passing an array of a specific model by reference between ViewControllers.
If I change any value of a specific element in the array it reflects well in all ViewControllers but when I remove an element from that array it doesn't reflect to the other controllers.
Does the remove(at: ) function create new array and refer to another address?
And if so how to delete an element without changing the address of array so it can reflect this change on the other view controllers?
Swift Arrays are value types (specifically, an array is a struct), not reference types, so you are mistaken when you say that you are "passing an array of a specific model by reference between view controllers". You can only ever pass a Swift array as a value.
Arrays, like other structs, have copy-on-modify semantics. As soon as you change the array itself a copy is made and the change is made to the copy.
Now, in your case the array contains references to model objects; When you update the model object you change the object itself, not the reference held in the array, so you see the change reflected in all of your view controllers.
An analogy might be the difference between adding a house to a street (which changes the street itself) versus changing the occupants of an existing house on the street.
I would suggest you implement a model object that provides abstraction from the underlying array so that you have better code and avoid the issue with array references.
One approach could be something like:
struct MyModel {
let name: String
let size: Int
}
class MyData {
private var _models = [MyModel]()
var models: [MyModel] {
return _models
}
func insert(model: MyModel) {
self._models.append(model)
}
func removeModel(at: Int) {
guard at >= 0 && at < _models.count else {
return
}
self._models.remove(at: at)
}
}
Although this isn't ideal as it still requires model consumers to know indices in the underlying array. I would prefer something like this:
struct MyModel: Hashable {
let name: String
let size: Int
}
class MyData {
private var _models = [MyModel]()
var models: [MyModel] {
return _models
}
func insert(model: MyModel) {
self._models.append(model)
}
func remove(model: MyModel) -> Bool {
if let index = self._models.index(of: model) {
_models.remove(at: index)
return true
} else {
return false
}
}
}
Now I don't need to know what internal collection MyData uses to store the models.
If you need to pass an array (or any other value type) by reference, you could go through an intermediate structure that manages the indirection for you.
[EDIT] changed to use KeyPaths available in Swift 4.
// Generic class to hold a "weak" reference to a property from an object
// including properties that are valued types such as arrays, structs, etc.
// This is merely an encapsulation of Swift's native KeyPath feature
// to make the code a bit more readable and simpler to use
//
class ReferenceTo<ValueType> { var value:ValueType! { get { return nil} set {} } }
class Reference<OwnerType:AnyObject,ValueType>:ReferenceTo<ValueType>
{
internal weak var owner:OwnerType!
internal var property:ReferenceWritableKeyPath<OwnerType,ValueType>! = nil
internal var valueRef:KeyPath<OwnerType,ValueType>! = nil
init(_ owner:OwnerType, _ property:ReferenceWritableKeyPath<OwnerType,ValueType>)
{ (self.owner,self.property) = (owner,property) }
init(_ owner:OwnerType, get valueRef:KeyPath<OwnerType,ValueType>)
{ (self.owner,self.valueRef) = (owner,valueRef) }
override var value:ValueType!
{
get { return valueRef != nil ? owner?[keyPath:valueRef] : owner?[keyPath:property] }
set { owner?[keyPath:property] = newValue }
}
}
With this generic class you can create references to valued type properties of object instances and manipulate them anywhere in your code as if the valued type property was a reference type.
// Example class with a read/write and a read-only property:
class MyObject
{
var myArray = [1,2,3,4]
var total:Int { return myArray.reduce(0,+) }
}
var instance:MyObject! = MyObject()
// create a reference to the array (valued type)
// that can be used anywhere and passed around as a parameter
let arrayRef = Reference(instance, \.myArray)
// the value is accessed and manipulated using the
// "value" property of the reference
arrayRef.value.remove(at:2)
arrayRef.value.append(5)
print(instance.myArray) // [1,2,4,5]
// Read-only properties can also be manipulated as
// references
let valueRef = Reference(instance, get:\.total)
print(valueRef.value) // 12
The Reference class allows passing the value as a reference to function parameters
// a function that expects a reference to an array
// would be declared as follows
func changeArray(_ array:ReferenceTo<[Int]>)
{ array.value.insert(9, at: 1) }
// the reference can also be used as an inout parameter
func shift(_ array:inout [Int])
{ array = Array(array.dropFirst()) + Array(array.prefix(1)) }
changeArray(arrayRef)
shift(&arrayRef.value!)
print(instance.myArray) // [9,2,4,5,1]
...
// the reference uses a weak link to the owner
// of the referenced property or value
// so there will be no strong reference cycle issues even
// if the reference is used in an object held strongly
// by the owner itself
instance = nil
print(arrayRef.value) // none ... no more value after the owner is gone

Resources