Generic Sum for Numeric and String in Swift - ios

I have this function, which return sum of numbers
func sum<T: Numeric>(_ a: T, _ b: T) -> T {
return a + b
}
And I need to improve this function so that also return the concatenation of Strings by this function without overloading. I probe use RangeReplaceableCollection, but i can't use this protocol with Numeric protocol.
For example:
sum(2, 3) -> 5
sum(1.5, 2.4) -> 3.9
sum("abc", "def") -> "abcdef"

To have one generic function for such a case you would need to find a common behavior that could be used as a constraint for a generic Type. In your case, you can do (but you should NOT) this:
DON'T DO THIS
extension String: AdditiveArithmetic {
// some stupid placeholders, as there is no obvious behavior for that :D
public static func - (lhs: String, rhs: String) -> String {
lhs
}
public static var zero: String {
""
}
}
func sum<T: AdditiveArithmetic>(_ a: T, _ b: T) -> T {
a + b
}
print(sum("LOl", "KEK")) // LOLKEK
print(sum(1, 2)) // 3
I would RECOMMEND just to add a new func for that particular case
func sum(_ a: String, _ b: String) -> String {
a + b
}

protocol AddProtocol {
static func +(lhs: Self, rhs: Self) -> Self
}
func add<T: AddProtocol>(num1: T, _ num2: T) -> T {
return num1 + num2
}
extension Int: AddProtocol {
}
extension String: AddProtocol {}
print(add(num1: "Abc", "Xyz"))
print(add(num1: 12, 30))

Related

How to extend arithmetic operators to support optional values as well - Swift

In the below example,
let value1: Int? = 23
let value2: Int = 20
let answer = value1 + value2 // Compiler warning that + operator cannot be applied to Int? and Int
So I would have to change the code to
if let value1 = value1 {
let answer = value1 + value2
}
How to create an extension for + that supports Optional values as well? In that case it should give nil as output.
What if the operation has multiple operands?
let value1: Int? = 2
let answer = value1 + 3.0
You just have to find the right protocol type to constrain the generic types, really. After that the implementation is trivial:
// plus and minus is supported by AdditiveArithmetic
func +<T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x + y } }
/* the above is just a more "functional" way of writing
if let x = lhs, let y = rhs {
return x + y
} else {
return nil
}
*/
}
func -<T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x - y } }
}
// times is supported by Numeric
func *<T: Numeric>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x * y } }
}
// divide is not supported by a single protocol AFAIK
func /<T: BinaryInteger>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x / y } }
}
func /<T: FloatingPoint>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { x in rhs.map { y in x / y } }
}
To make value1 + 3.0 work, you'd have to do something like this:
func +<T: BinaryInteger, U: FloatingPoint>(lhs: T?, rhs: U?) -> U? {
return lhs.flatMap { x in rhs.map { y in U(x) + y } }
}
But it's usually not a good idea to go against the restrictions put in place. I don't recommend this.
Only pasting solution for addition, but other operators will work analogously (but mind subtract and division, since they are not commutative)
Three reasonable solutions
Global function(s)
Extend existential* (conforming to AdditiveArithmetic) to some new protocol e.g. AdditiveArithmeticOptional
Extend Optional
* Note: you can read about existentials here, e.g. protocol isn't an existential, but a concrete type, e.g. a struct is.
1 Global function(s)
See #Sweepers answer
Note: a global function is a function not implemented on a type (protocol or existential). Swift's zip function is an example
2 Extend existentials to new protocol
public protocol AdditiveArithmeticOptional: AdditiveArithmetic {
static func + (lhs: Self, rhs: Self?) -> Self
}
public extension AdditiveArithmeticOptional {
static func + (lhs: Self, rhs: Self?) -> Self {
guard let value = rhs else { return lhs }
return value + lhs
}
static func + (lhs: Self?, rhs: Self) -> Self {
rhs + lhs
}
}
extension Int8: AdditiveArithmeticOptional {}
extension Int16: AdditiveArithmeticOptional {}
extension Int32: AdditiveArithmeticOptional {}
extension Int64: AdditiveArithmeticOptional {}
extension Int: AdditiveArithmeticOptional {} // same as `Int64` on 64 bit system, same as `Int32` on 32 bit system
extension UInt8: AdditiveArithmeticOptional {}
extension UInt16: AdditiveArithmeticOptional {}
extension UInt32: AdditiveArithmeticOptional {}
extension UInt64: AdditiveArithmeticOptional {}
extension UInt: AdditiveArithmeticOptional {} // same as `UInt64` on 64 bit system, same as `UInt32` on 32 bit system
3 extend Optional
extension Optional where Wrapped: AdditiveArithmetic {
static func + <I>(optional: Self, increment: I) -> I where I: AdditiveArithmetic & ExpressibleByIntegerLiteral, I.IntegerLiteralType == Wrapped {
guard let value = optional else { return increment }
let base = I.init(integerLiteral: value)
return base + increment
}
static func + <I>(increment: I, optional: Self) -> I where I: AdditiveArithmetic & ExpressibleByIntegerLiteral, I.IntegerLiteralType == Wrapped {
optional + increment
}
}
You could create your own custom operator function if you have multiple scenarios where you require arithmetic operations between optionals as follows:
func + (lhs: Int?, rhs: Int?) -> Int {
(lhs ?? 0) + (rhs ?? 0)
}
func + (lhs: Int?, rhs: Int) -> Int {
(lhs ?? 0) + rhs
}
func + (lhs: Int, rhs: Int?) -> Int {
lhs + (rhs ?? 0)
}
Note: Add return keyword if you are using Swift 5 or below.
Update: Upon further investigation and inspiration from the answer of #sweeper following solution seemed more elegant.
func + <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
(lhs ?? .zero) + (rhs ?? .zero)
}
or if you need a nil when operation was not successful
func + <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T? {
lhs.flatMap { lhs in rhs.flatMap { lhs + $0 }}
}
Optionals don't make much sense to be added, a nil value usually represents something went wrong along the way and a value could not be retrieved. It's better to be explicit, and to write the if-let statements. This way you can handle the cases where you end up with nil values.
But if you want to ignore the nils, then you can use the nil coalescing operator:
let value1: Int? = 23
let value2: Int = 20
let answer = (value1 ?? 0) + value2
You are still explicit about the unwrap, but you also have a fallback route in case you want to ignore the nil value. And, maybe even more important, the code transmits its scope in a clear manner. If someone later on stumbles upon your code it will be clear to them what the code does and how it recovers from unexpected situations (nil is an unexpected value in regards to the addition)

Overload wrapped function with generic in Swift

First example
func foo<T>(_ t: T) -> String {
return bar(t)
}
func bar<T>(_ t: T) -> String {
return "Other"
}
func bar<T: StringProtocol>(_ t: T) -> String {
return "String"
}
foo("") // "Other" // Why not "String"?
bar("") // "String"
bar(1) // "Other"
Second example (more complex)
First example can be resolved by type checking, but in this example it is impossible.
func foo<T>(_ t: (T) -> String) -> String {
return bar(t)
}
func bar<T>(_ t: (T) -> String) -> String {
return "Other"
}
func bar<T: StringProtocol>(_ t: (T) -> String) -> String {
return "String"
}
foo { (string: String) -> String in return "" } // Other // Why not "String"?
bar { (string: String) -> String in return "" } // String
bar { (int: Int) -> String in return "" } // Other
Overloads are resolved statically. Since T inside foo() is unconstrained, it picks the overload of bar() with an unconstrained T. Is there any workaround?
As per current Swift implementation, the function which is more specialized, meaning it has constraints who are a superset of the constraints of the other overloaded function; overloading will pick the more specialized function.
So, I can't think of better alternative than making foo conform to StringProtocol.
Regarding why there is not a better hack around, I would like to quote from Swift documentation which talks about how nested or more specialized generic type should be resolved.:
This amounts to run-time overload resolution, which may be desirable,
but also has downsides, such as the potential for run-time failures
due to ambiguities and the cost of performing such an expensive
operation at these call sites. Of course, that cost could be mitigated
in hot generic functions via the specialization mentioned above.
Our current proposal for this is to decide statically which function
is called (based on similar partial-ordering rules as used in C++),
and avoid run-time overload resolution. If this proves onerous, we can
revisit the decision later.
Talking of work around.
You can do it as follows.
func foo<T>(_ t: T) -> String {
if let str = t as? String {
return bar(str)
}
return bar(t)
}
func bar<T>(_ t: T) -> String {
return "Other"
}
func bar<T: StringProtocol>(_ t: T) -> String {
return "String"
}
Again speaking of work around.
func foo<T>(_ t: #escaping (T) -> String) -> String {
if let clsr = t as? (String) -> String {
return bar(clsr)
}
return bar(t)
}
func bar<T>(_ t: (T) -> String) -> String {
return "Other"
}
func bar<T: StringProtocol>(_ t: (T) -> String) -> String {
return "String"
}

Class with generic type as a return value [duplicate]

I want to use generic protocol type as a function return type like this:
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> P<T> {
return C<T>()
}
}
But this code compile with errors complained:
Cannot specialize non-generic type 'P'
Generic parameter 'T' is not used in function signature
Is there any way to achieve similar function with Swift?
Swift 5.1 supports returning associated types using Opaque type. Using opaque type, your code builds successfully. Ref
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> some P {
return C<T>()
}
The problem is you cannot use the syntax P<T>. P is a protocol, meaning it can't be treated as a generic type (Cannot specialize non-generic type 'P'), even though it may have a given associatedtype.
In fact, because it has an associatedtype, you now can't even use the protocol type itself directly – you can only use it as a generic constraint.
One solution to your problem is to simply change your function signature to createC<T>() -> C<T>, as that's exactly what it returns.
class Factory {
func createC<T>() -> C<T> {
return C<T>()
}
}
I'm not entirely sure what you would gain from having the return type be a protocol here. Presumably your example is just a simplification of your actual code and you want to be able to return an arbitrary instance that conforms to P. In that case, you could use type erasure:
class AnyP<T> : P {
private let _get : () -> T?
private let _set : (T) -> ()
init<U:P where U.T == T>(_ base:U) {
_get = base.get
_set = base.set
}
func get() -> T? {return _get()}
func set(v: T) {_set(v)}
}
class Factory {
func createC<T>() -> AnyP<T> {
return AnyP(C<T>())
}
}

Using filter on Objects in an Array to find max? [swift]

I have a bunch of Objects stored in an Array.
They all have the property:
distanceInSeconds: Int
I was wondering if there's a way to find the max of this property between all objects in the array using filter or another array method?
For instance:
var distances: [Distance] = []
var maxDistance = distances.filter(find max)
This would be the Swifty way (by implementing Comparable):
class Route : Comparable {
let distance: Int
init(distance: Int) {
self.distance = distance
}
}
func ==(lhs: Route, rhs: Route) -> Bool {
return lhs.distance == rhs.distance
}
func <(lhs: Route, rhs: Route) -> Bool {
return lhs.distance < rhs.distance
}
let routes = [
Route(distance: 4),
Route(distance: 8),
Route(distance: 2),
Route(distance: 7)
]
print(routes.maxElement()?.distance)
output:
"8"
This works with Swift 2. If you're using Swift 1.2, maxElement(routes) should work
In Swift 2.0 minElement and maxElement now return optionals in case of empty sequences, and also now have versions that take isOrderedBefore closures.
let maxDistance = distances.maxElement { (a, b) -> Bool in
a.distanceInSeconds < b.distanceInSeconds
}
#1. The element type inside your sequence conforms to Comparable protocol
With Swift 4, if the element type inside your sequence conforms to Comparable protocol, you will be able to use the max() method that has the following declaration:
func max() -> Self.Element?
Returns the maximum element in the sequence.
Usage:
class Distance: Comparable, CustomStringConvertible {
let distanceInSeconds: Int
var description: String { return "Distance in Int: \(distanceInSeconds)" }
init(distanceInSeconds: Int) {
self.distanceInSeconds = distanceInSeconds
}
static func ==(lhs: Distance, rhs: Distance) -> Bool {
return lhs.distanceInSeconds == rhs.distanceInSeconds
}
static func <(lhs: Distance, rhs: Distance) -> Bool {
return lhs.distanceInSeconds < rhs.distanceInSeconds
}
}
let distances = [
Distance(distanceInSeconds: 20),
Distance(distanceInSeconds: 30),
Distance(distanceInSeconds: 10)
]
let maxDistance = distances.max()
print(String(describing: maxDistance)) // prints: Optional(Distance in Int: 30)
#2. The element type inside your sequence does not conform to Comparable protocol
With Swift 4, if the element type inside your sequence does not conform to Comparable protocol, you will have to use the max(by:) method that has the following declaration:
func max(by areInIncreasingOrder: ((offset: Int, element: Base.Element), (offset: Int, element: Base.Element)) throws -> Bool) rethrows -> (offset: Int, element: Base.Element)?
Returns the maximum element in the sequence, using the given predicate as the comparison between elements.
Usage:
class Distance: CustomStringConvertible {
let distanceInSeconds: Int
var description: String { return "Distance in Int: \(distanceInSeconds)" }
init(distanceInSeconds: Int) {
self.distanceInSeconds = distanceInSeconds
}
}
let distances = [
Distance(distanceInSeconds: 20),
Distance(distanceInSeconds: 30),
Distance(distanceInSeconds: 10)
]
let maxDistance = distances.max (by: { (a, b) -> Bool in
return a.distanceInSeconds < b.distanceInSeconds
})
print(String(describing: maxDistance)) // prints: Optional(Distance in Int: 30)
I think you want reduce:
Setup:
struct Distance {
var distanceInSeconds: Int
}
var distances: [Distance] = []
for _ in 1...10 {
distances += [Distance(distanceInSeconds: Int(arc4random_uniform(100)))]
}
Implementation:
let max = distances.reduce(distances.first) {
if let left = $0 where left.distanceInSeconds > $1.distanceInSeconds {
return $0
} else {
return $1
}
}

How to make a closure optional with a default value

I have a bunch of functions that I would like to be able to specify a default closure if one is not provided. I can't seem to figure out how to do it without some ugly code.
So for example, I would like the perform function to accept an optional parameter called closure that is executed when provided. Otherwise it will default to executing myClosure. How can I make this better so I don't have to repeat the function calls?
class MyClas {
typealias closureType = ((number: Int) -> Int)?
func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = nil) -> Int {
if closure == nil {
return myClosure(number)
} else {
return closure!(number: number)
}
}
}
Ideally, I could do this!
class MyClass {
typealias closureType = ((number: Int) -> Int)?
func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = myClosure) -> Int {
return closure(number: number)
}
}
Your problem is that you've made made myClosure a method (or member function), which means it doesn't have the signature you want (it's instead a curried function, of type MyClass->Int->Int).
Either pull it out of the class, or make it a static (or rather "class" in the case of a class) method:
class MyClass {
typealias closureType = (number: Int) -> Int
class func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = MyClass.myClosure) -> Int {
return closure(number: number)
}
}
P.S. once you do this, it doesn't need to be optional any more
Just to show it compiling as a non-static method:
class MyClass {
typealias closureType = MyClass -> (number: Int) -> Int
func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = myClosure) -> Int {
return closure(self)(number: number)
}
}
let c = MyClass()
println(c.perform(5)) // prints 10
Closure is first-class citizen in Swift. So you can provide default value for it.
class MyClass {
func perform(number: Int, closure: Int -> Int = { $0 * 2 }) -> Int {
return closure(number)
}
}

Resources