Swift generics and extensions need to workout [duplicate] - swift

This question already has answers here:
Array extension to remove object by value
(15 answers)
Closed 7 years ago.
Im learning swift currently. While learning I'm stuck with generics. Im solving one simple problem that -> return index of specified element in an array
import UIKit
extension Array
{
func indexOfLetter<T:Equatable>(item:T) -> Int
{
var i = 0
for (index, value) in enumerate(self)
{
if value == item
{
return i
}
i++
}
return -1;
}
}
var arrayOfItems = ["A","B"]
arrayOfItems.indexOfLetter("A")
in this code I'm getting error that we
Can not compare two operands using == operator which are of type T.

The answer to your problem becomes more clear if we use a letter other than T for our generic identifier.
Change the method signature to use the letter U. And now we get this error message:
Binary operator '==' cannot be applied to operands of type 'T' and 'U'
This is the same error, but it's made more clear by using a different letter. The Array type is already a generic whose generic identifier is T for its type.
When we use U it unmasks the real problem.
The Equatable protocol only requires that our type defines == for comparisons to itself. We could compare two U's as long as U's type is Equatable. But the Equatable protocol does not ensure that we can compare a U to a T using ==.
This Stack Overflow answer can provide some insight on the difficulties of using the Equatable protocol with generics.

Related

Sequence extension that works on Arrays, Sets and Dictionaries in Swift

I'm learning Swift with Paul Hudson's 100 days of Swift. In one of his extension lessons, I have found a notion that more advanced developers could write a Sequence extension that would service Arrays, Sets and Dictionaries:
https://www.hackingwithswift.com/quick-start/understanding-swift/when-are-protocol-extensions-useful-in-swift
I have given this a shot but:
I don't know how to create a variable that could change its type (wonder if that's even possible at all)
I don't know how to create a sequence that would service dictionaries too, since their syntax for allSatisfy is a bit different
Would you be so kind and give me a hand here? :)
The code:
extension Sequence {
var isAllEven:Bool {
numbers.allSatisfy { $0.isMultiple(of:2)}
}
}
let numbers = Set([4, 8, 15, 16])
print(numbers.isAllEven)
I can change numbers to be both Array and Set but as soon as I understood what Paul said, there is a possibility to create an extension that could service all 3 in one passage of code without having to change the variables content.
As isMultiple(of:) belongs to all integer types a generic version must be constrained to BinaryInteger
extension Sequence where Element : BinaryInteger {
var isAllEven : Bool {
allSatisfy {$0.isMultiple(of: 2)}
}
}
But this cannot cover Dictionary, because although Dictionary conforms to Sequence the Element type is different.
You could write a second extension of Sequence which matches the Dictionary tuple type
extension Sequence where Element == (key:String, value:Int) {
var isAllEven : Bool {
allSatisfy {$0.value.isMultiple(of:2)}
}
}
but this considers only String keys and Int values
A more generic way is to extend Dictionary directly
extension Dictionary where Value : BinaryInteger {
var isAllEven : Bool {
allSatisfy {$0.value.isMultiple(of: 2)}
}
}

Swift. Check if Any is value type or reference type [duplicate]

This question already has answers here:
Check if `Any` value is object
(2 answers)
Closed 3 years ago.
Is it possible to check if an object (not as in OOP) is of reference type or value type?
let something : Any = getSomething() // func getSomething() -> Any
let isReferenceType : Bool = // how to check?
EDIT:
As pointed out this is practically a duplicate of Check if `Any` value is object
This is not so easy as it seems, see
let isReferenceType: Bool = type(of: something) is AnyClass
See How to test whether generic variable is of type AnyObject
However, if you need such things, then usually you have some big problem with your architecture that you should address instead. Using Any type should be the last resort for exceptional situations.

What is difference between create object with init and () in Swift [duplicate]

This question already has answers here:
In Swift, what's the difference between calling UINavigationController() vs UINavigationController.init()?
(3 answers)
Closed 5 years ago.
class A {
private var value: Int
init(value: Int) {
self.value = value
}
}
We have class A and what is the difference between I create this object by using A.init(value: 5) and A(value: 5)? Thanks
There is no functional difference between the two. Both styles will call the same initializer and produce the same value.
Most style guides that I've seen prefer to leave out the explicit .init-part in favor of the shorter A(value:) syntax — that also resembles the constructor syntax in many other languages.
That said, there are some scenarios where it's useful to be able to explicitly reference the initializer. For example:
when the type can be inferred and the act of initialization is more important than the type being initialized. Being able to call return .init(/* ... */) rather than return SomeComplicatedType(/* ... */) or let array: [SomeComplicatedType] = [.init(/* ... */), .init(/* ... */)]
when passing the initializer to a higher order function, being able to pass "something".map(String.init) rather than "something".map({ String($0) })
Again, it's a matter of style.

Swift - Binary Operator == cannot be applied to two [[Double]] operands [duplicate]

This question already has answers here:
Swift equality operator on nested arrays
(2 answers)
Closed 5 years ago.
I wrote a litle swift function like this:
func compareTest(values: [[Double]]) {
if(values == [[1.0,2.0]]) {
// some code
}
}
But when I try to compile, I get an error at the comparision:
Binary operator == cannot be applied to two [[Double]] operands.
I searched in Questions around here. Most answers are that the error message is misleading and people are using the wrong type (Example Question).
Can someone help me there I wrote the types incorrect?
In this case there is nothing misleading.
Normally the == operator is defined for Equatable items. That allows two Double values to be compared to each other, e.g. 1.0 == 1.0.
Then we have a specific == operator defined on Arrays of Equatable items:
public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool
That means that you can compare any arrays with equatable items. However, the arrays themselves are not Equatable.
There is no such operator defined for nested arrays.
You would have to define:
public func ==<Element : Equatable>(lhs: [[Element]], rhs: [[Element]]) -> Bool {
...
}
I'm not familiar with Swift but as a general rule in any language, double values should not be compared using equality operator. Instead two double values should be considered equal if their absolute arithmetic difference is small than an epsilon
var epsilon = 0.00000001;
if(fabs(v1-v2)< epsilon){ // values are considered equal
}

Swift error: binary operator '>' cannot be applied to two T operands

I am writing a mutaitin function for Array. I can't compare the array components like below:
extension Array {
mutating func mutFunc() {
while self[1]>self[2]{
}
}
}
The Array must is Int type array. I can't even use this way to compare.
while Int(self[1])>Int(self[2]){
}
What is wrong in my code?
You can't do it in Swift 1.2 or before. This is exactly the problem that extension where clauses in Swift 2.0 solves. That way, you can extend Array only and exactly insofar as its element type adopts Comparable (or even Int), thus guaranteeing that > is defined.
extension Array where Element : Comparable {
// ... your function involving > goes here
}