How do you overload an operator in swift? - swift

Say you have a class C. It has two instance variables, number and vector. vector is just an array of either ints or doubles.
I would like to do the following:
c1 = C()
c1.number = 2
c1.vector = [1,2,3]
c2 = C()
c2.number = 3
c2.vector = [4,6,7]
println(c1.number + c2.number) \\print to screen 5
println(c1.vector + c2.vector) \\ print [5,8,10]
Basically, I'm looking to overload the "+" operator so that it knows which "version" of the "+" to use depending of the type.

The + operator is already defined for the type Array. It does an array merge and tacks the values of the rvalue onto the lvalue. To do a sum of values by index you can do something like this:
protocol Numeric { }
extension Double: Numeric {}
extension Int: Numeric {}
func +<T: Numeric>(left: [T], right: [T]) -> [T]? {
var numElements: Int = 0
if count(left) != count(right) {
return nil
} else {
numElements = count(left)
}
var result = [T]()
for var i = 0; i < numElements; ++i {
if let lvalue = left[i] as? Int, rvalue = right[i] as? Int {
result.append(lvalue + rvalue as! T)
} else if let lvalue = left[i] as? Double, rvalue = right[i] as? Double {
result.append(lvalue + rvalue as! T)
}
}
return result
}
But generally, I wouldn't advise overriding a predefined operator because of the high potential to cause confusion and chaos later on down the road.

Related

Sum and For loop together in Swift

I want to know how many common characters in the given sets.
Input: J = "aA", S = "aAAbbbb"
Output: 3
In the python solution for this as follows:
lookup = set(J)
return sum(s in lookup for s in S)
I have following solution in Swift it works, but it looks too wordy. I want to learn shorter way of it.
class Solution {
func checkInItems(_ J: String, _ S: String) -> Int {
let lookup = Set(J) ;
var sy = 0;
for c in S
{
if lookup.contains(c)
{
sy += 1;
}
}
return sy;
}
}
As a small variation of Sh_Khan's answer you can use reduce to
count the number of matching elements without creating an intermediate
array:
func checkInItems(_ J: String, _ S: String) -> Int {
let lookup = Set(J)
return S.reduce(0) { lookup.contains($1) ? $0 + 1 : $0 }
}
In Swift 5 there will be a count(where:) sequence method for this purpose,
see SE-0220 count(where:).
You can try
class Solution {
func checkInItems(_ J: String, _ S: String) -> Int {
let lookup = Set(J)
return S.filter { lookup.contains($0) }.count
}
}

Swift block syntax failure to infer type

Can anyone explain why this single line block with an implicit return compiles:
let r = withUnsafePointer(&msg) {
dn_expand(UnsafePointer($0), eomorig: UnsafePointer($0).advancedBy(msg.count), comp_dn: UnsafePointer($0).advancedBy(offset), exp_dn: &buf, length: buf.count)
}
but this version refactored where the only difference is to avoid the multiple calls to UnsafePointer($0) doesn't:
let s = withUnsafePointer(&msg) {
let p = UnsafePointer($0)
return dn_expand(p, eomorig: p.advancedBy(msg.count), comp_dn: p.advancedBy(offset), exp_dn: &buf, length: buf.count)
}
with error message:
Cannot convert value of type 'inout [UInt8]' (aka 'inout Array<UInt8>') to expected argument type 'inout _'
The dn_function being called is just a trivial wrapper around dn_expand from libresolv:
public static func dn_expand(msg: UnsafePointer<UInt8>, eomorig: UnsafePointer<UInt8>, comp_dn: UnsafePointer<UInt8>, exp_dn: UnsafeMutablePointer<CChar>, length: Int) -> Int {
return Int(res_9_dn_expand(msg, eomorig, comp_dn, exp_dn, Int32(length)))
}
As already said in the comments, withUnsafePointer() is not the
correct way to get a pointer to the element storage. It compiles, but
gives unexpected results, as the following example demonstrates:
var msg: [UInt8] = [1, 2, 3, 4]
func foo(x: UnsafePointer<UInt8>) {
print(x[0])
}
withUnsafePointer(&msg) {
foo(UnsafePointer($0))
}
This prints "random" numbers, but not the expected 1. The correct
way is to call the withUnsafeBufferPointer() method on the array:
msg.withUnsafeBufferPointer {
foo($0.baseAddress)
}
In your case that would be
let r = msg.withUnsafeBufferPointer {
dn_expand($0.baseAddress, eomorig: $0.baseAddress + $0.count, ...)
}
Here the return type of the closure is inferred automatically because
it is a "single-expression" closure. If the closure contains more
than one expression, you have to specify its type:
let r = msg.withUnsafeBufferPointer { bufPtr -> Int in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}
or let the compiler infer the return type from the context:
let r: Int = msg.withUnsafeBufferPointer { bufPtr in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}

Nicer syntax for ternary with a let?

Is there a nicer way to do the assignment to DEF in the following example? I want to convert type A to Type B, but still preserve the nil possibility whenever I can.
Can't seem to stumble into a better way of doing this, however. Suggestions?
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue != nil ? Int(someValue) : nil
}
}
Swift 1:
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue.map{Int($0)}
}
}
Swift 2:
class ABC {
var DEF: Int?
func X (someValue: Int8?) {
DEF = someValue.map(Int.init)
}
}
map() takes an optional, unwraps it, and applies a function to it. If the optional resolves to nil, map() returns nil.
You are describing optional map:
var i: Int? = 2
let j = i.map { $0 * 2 } // j = .Some(4)
i = nil
let k = i.map { $0 * 2 } // k = nil
Think of this map like array or other collection map, where optionals are collections that have either zero (nil) or one (non-nil) element.
Note, if the operation you want to perform itself returns an optional, you need flatMap to avoid getting a double-optional:
let s: String? = "2"
let i = s.map { Int($0) } // i will be an Int??
let j = s.flatMap { Int($0) } // flattens to Int?

Swift Cast Generics Type

I'm trying to cast a generic type to its super class.
class Foo : NSObject {
}
class Test<T> {
let value: T
init(_ value: T) {
self.value = value
}
}
let c = Test(Foo())
let v = c as Test<AnyObject>
But on the line
let v = c as Test<AnyObject>
I get 'Foo' is not identical to 'AnyObject'
While I can do that with built-in Arrays
let array1 = [Foo(), Foo()]
let array2 = array1 as [AnyObject]
Arrays are special-cased in Swift to be able to have this behaviour. You won't be able to replicate it with your own classes, unfortunately.
To get similar behaviour, you could give your type another init method:
class Test<T> {
let value: T
init(_ value: T) {
self.value = value
}
init<U>(other: Test<U>) {
// in Swift 1.2 you will need as! here
self.value = other.value as T
}
}
let c = Test(Foo())
let v = Test<AnyObject>(other: c) // this will work ok
Note though that this is unsafe (i.e. will assert at runtime) in cases where you want to convert to an incompatible type (and the alternative, a failable initializer, will also have complications)

Swift: adding optionals Ints

I declare the following:
var x:Int?
var y:Int?
and I'd like a third variable z that contains the sum of x and y. Presumably, as x & y are optionals, z must also be an optional:
var z:Int? = x + y
but this gives a complier error "value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'"
If I unwrap x & y:
var z:Int? = x! + y!
I get a run-time error as x & y are nil, so can't be unwrapped.
I can achieve the desired result as follows:
var z:Int?
if let x1 = x {
if let y1 = y {
z = x1+y1
}
}
but this seems a bit verbose for adding together 2 integers! Is there a better way of achieving this?
Here is my take, I think it's cleaner:
let none:Int? = nil
let some:Int? = 2
func + (left: Int?, right:Int?) -> Int? {
return left != nil ? right != nil ? left! + right! : left : right
}
println(none + none)
println(none + some)
println(some + none)
println(some + some)
println(2 + 2)
With results of:
nil
Optional(2)
Optional(2)
Optional(4)
4
The best I can think of is:
if x && y {
z = x! + y!;
}
Since they are all Optionals... there's really no way to avoid:
checking that they aren't nil
Unwrapping them before you add them.
Best solution IMO:
z = x.map { x in y.map { $0 + x } }
Did you know the map operator on Optional<T>? It is very nice.
Documentation says:
If self == nil, returns nil. Otherwise, returns f(self!).
It depends exactly what you're trying to achieve, but you could do it with an optional tuple:
var xy: (Int, Int)?
var z: Int
if let (x1, y1) = xy {
z = x1 + y1 // Not executed
}
xy = (3, 4)
if let (x1, y1) = xy {
z = x1 + y1 // 7
}
Update
As #Jack Wu points out, this changes the semantics. If you were willing to be a bit more verbose, you could however do it as follows:
func optIntAdd(x: Int?, y: Int?) -> Int? {
if let x1 = x {
if let y1 = y {
return x1 + y1
}
}
return nil
}
operator infix +! { }
#infix func +! (x: Int?, y: Int?) -> Int?{
return optIntAdd(x, y)
}
var x: Int?
var y: Int?
var z: Int?
z = x +! y // nil
x = 1
z = x +! y // nil
y = 2
z = x +! y // 3
Not sure "+!" is a useful choice of name for the operator, but it would't let me choose "+?".
Someday, we'll have variadic generics. Until then, you need a pair of overloads for all arities.
var z = Optional(x, y).map(+)
public extension Optional {
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optional0: Wrapped0?, _ optional1: Wrapped1?)
where Wrapped == (Wrapped0, Wrapped1) {
self = .init((optional0, optional1))
}
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
where Wrapped == (Wrapped0, Wrapped1) {
switch optionals {
case let (wrapped0?, wrapped1?):
self = (wrapped0, wrapped1)
default:
self = nil
}
}
}
z = (x ?? 0) + (y ?? 0)
* Worked on Xcode 9 *
Swift 5.5 Sum any optional values
infix operator +?: AdditionPrecedence
public func +? <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
if let lhs = lhs, let rhs = rhs {
return lhs + rhs
} else if let lhs = lhs {
return lhs
} else if let rhs = rhs {
return rhs
} else {
return .zero
}
}