Is there an equivalent to optional chaining with arithmetic operators? - swift

I have two optional numbers that I add. Right now it looks like this:
if let a = optionalA {
if let b = optionalB {
return a + b
}
}
return nil
For methods, there's the more convenient optional chaining syntax, like optionalA.?method syntax. Is there an equivalent for arithmetic operators that would return nil if either side was nil?

It's possible to create an operator +? that does just this like this:
infix func +?(a: Int?, b: Int?) -> Int? {
if aa = a {
if bb = b {
return aa + bb
}
}
return nil
}
but I'm wondering if there's another, built-in way to do that.

I dont think there is built in way. But you can make your own operator function:
func +(lhs: Int?, rhs: Int?) -> Int? {
if let a = lhs {
if let b = rhs {
return a + b
}
}
return nil
}
var a: Int? = 1
var b: Int? = 2
var c = a + b

Here's the custom operator approach updated for Swift 3:
infix operator +?
func +?(a: Int?, b: Int?) -> Int? {
if let aa = a, let bb = b {
return aa + bb
}
return nil
}

Related

Synchronising combined Properties in ReactiveSwift

I'm considering converting a project using my own custom signal framework to use ReactiveSwift instead, but there is a fundamental issue I've never figured out how to resolve in ReactiveSwift:
As a simplified example, let's say you have two mutable properties:
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
Then, we derive a property that combines both to implement our logic:
let c = Property.combineLatest(a, b).map { a, b in
return a + b
}
Later, we receive some information that causes us to update the values of both a and b at the same time:
a.value = 3
b.value = 4
The problem now is that c will inform its listeners that it has the values 3 -> 5 -> 7. The 5 is entirely spurious and does not represent a valid state, as we never wanted a state where a was equal to 3 and b was equal to 2.
Is there a way around this? A way to suppress updates to a Property while updating all of its dependencies to new states, and only letting an update through once you are done?
combineLatest‘s fundamental purpose is to send a value when either of its upstream inputs send a new value, so I don’t think there’s a way to avoid this issue if you want to use that operator.
If it’s important that both values update truly simultaneously then consider using a MutableProperty<(Int, Int)> or putting the two values in a struct. If you give a little more context about what you’re actually trying to accomplish then maybe we could give a better answer.
Pausing Updates
So I really don't recommend doing something like this, but if you want a general purpose technique for "pausing" updates then you can do it with a global variable indicating whether updates are paused and the filter operator:
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
var pauseUpdates = false
let c = Property.combineLatest(a, b)
.filter(initial: (0, 0)) { _ in !pauseUpdates }
.map { a, b in
return a + b
}
func update(newA: Int, newB: Int) {
pauseUpdates = true
a.value = newA
pauseUpdates = false
b.value = newB
}
c.producer.startWithValues { c in print(c) }
update(newA: 3, newB: 4)
But there are probably better context-specific solutions for achieving whatever you are trying to achieve.
Using a sampler to manually trigger updates
An alternate solution is to use the sample operator to manually choose when to take a value:
class MyClass {
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
let c: Property<Int>
private let sampler: Signal<Void, Never>.Observer
init() {
let (signal, input) = Signal<Void, Never>.pipe()
sampler = input
let updates = Property.combineLatest(a, b)
.map { a, b in
return a + b
}
.producer
.sample(with: signal)
.map { $0.0 }
c = Property(initial: a.value + b.value, then: updates)
}
func update(a: Int, b: Int) {
self.a.value = a
self.b.value = b
sampler.send(value: ())
}
}
let x = MyClass()
x.c.producer.startWithValues { c in print(c) }
x.update(a: 3, b: 4)
Using zip
If a and b are always going to change together, you can use the zip operator which waits for both inputs to have new values:
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
let c = Property.zip(a, b).map(+)
c.producer.startWithValues { c in print(c) }
a.value = 3
b.value = 4
Use zip with methods for each type of update
class MyClass {
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
let c: Property<Int>
init() {
c = Property.zip(a, b).map(+)
}
func update(a: Int, b: Int) {
self.a.value = a
self.b.value = b
}
func update(a: Int) {
self.a.value = a
self.b.value = self.b.value
}
func update(b: Int) {
self.a.value = self.a.value
self.b.value = b
}
}
let x = MyClass()
x.c.producer.startWithValues { c in print(c) }
x.update(a: 5)
x.update(b: 7)
x.update(a: 8, b: 8)
Combining the values into one struct
I thought I would provide an example of this even though you said you didn't want to do it, because MutableProperty has a modify method that makes it less cumbersome than you might think to do atomic updates:
struct Values {
var a: Int
var b: Int
}
let ab = MutableProperty(Values(a: 1, b: 2))
let c = ab.map { $0.a + $0.b }
c.producer.startWithValues { c in print(c) }
ab.modify { values in
values.a = 3
values.b = 4
}
And you could even have convenience properties for directly accessing a and b even as the ab property is the source of truth:
let a = ab.map(\.a)
let b = ab.map(\.b)
Creating a new type of mutable property to wrap the composite property
You could create a new class conforming to MutablePropertyProtocol to make it more ergonomic to use a struct to hold your values:
class MutablePropertyWrapper<T, U>: MutablePropertyProtocol {
typealias Value = U
var value: U {
get { property.value[keyPath: keyPath] }
set {
property.modify { val in
var newVal = val
newVal[keyPath: self.keyPath] = newValue
val = newVal
}
}
}
var lifetime: Lifetime {
property.lifetime
}
var producer: SignalProducer<U, Never> {
property.map(keyPath).producer
}
var signal: Signal<U, Never> {
property.map(keyPath).signal
}
private let property: MutableProperty<T>
private let keyPath: WritableKeyPath<T, U>
init(_ property: MutableProperty<T>, keyPath: WritableKeyPath<T, U>) {
self.property = property
self.keyPath = keyPath
}
}
With this, you can create mutable versions of a and b that make it nice and easy to both get and set values:
struct Values {
var a: Int
var b: Int
}
let ab = MutableProperty(Values(a: 1, b: 2))
let a = MutablePropertyWrapper(ab, keyPath: \.a)
let b = MutablePropertyWrapper(ab, keyPath: \.b)
let c = ab.map { $0.a + $0.b }
c.producer.startWithValues { c in print(c) }
// Update the values individually, triggering two updates
a.value = 10
b.value = 20
// Update both values atomically, triggering a single update
ab.modify { values in
values.a = 30
values.b = 40
}
If you have the Xcode 11 Beta installed, you can even use the new key path based #dynamicMemberLookup feature to make this more ergonomic:
#dynamicMemberLookup
protocol MemberAccessingProperty: MutablePropertyProtocol {
subscript<U>(dynamicMember keyPath: WritableKeyPath<Value, U>) -> MutablePropertyWrapper<Value, U> { get }
}
extension MutableProperty: MemberAccessingProperty {
subscript<U>(dynamicMember keyPath: WritableKeyPath<Value, U>) -> MutablePropertyWrapper<Value, U> {
return MutablePropertyWrapper(self, keyPath: keyPath)
}
}
Now instead of:
let a = MutablePropertyWrapper(ab, keyPath: \.a)
let b = MutablePropertyWrapper(ab, keyPath: \.b)
You can write:
let a = ab.a
let b = ab.b
Or just set the values directly without creating separate variables:
ab.a.value = 10
ab.b.value = 20

Compare 2 structs/Objects implement the same Protocol?

let's say I have the following :
protocol P : Equatable {
var uniqueID : Int { get }
}
struct A : P {
var uniqueID = 1
}
struct B : P {
var uniqueID = 2
}
func ==<T : P>(lhs:T , rhs:T) -> Bool { return lhs.uniqueID == rhs.uniqueID }
Now when I write the following:
let a = A()
let b = B()
let c = a == b
I got error: binary operator '==' cannot be applied to operands of type 'A' and 'B'
is there any way to achieve this ?
you have to define the equality function with two generic types to allow different types to be compared, like this:
func ==<T: P, T2: P>(lhs: T , rhs: T2) -> Bool { return lhs.uniqueID == rhs.uniqueID }

How to use generic function to tear down swift's optional pyramid of doom

Instead of using multiple optional bindings, we can define a function to tear down optional pyramid of doom.
func if_let<T, U, V> (a: T?, _ b: U?, _ c: V?, fn:(T, U, V) -> () ){
if let a = a {
if let b = b {
if let c = c {
fn(a, b, c)
}
}
}
}
Then I can write like this:
var s1: String? = "s11"
var s2: String? = "s22"
var s3: String? = "s33"
if_let(s1, s2, s3) { s1, s2, s3 in
print(("\(s1) - \(s2) - \(s3)"))
}
However, the problem is how to make this if_let function more generic so that it can accept any number of arguments. My implementation is like this:
func if_let<T> (values: T?..., fn:(params: [T]) -> ()) {
for value in values {
guard value != nil else { return }
}
let unwrappedArray = values.map{ $0! }
fn(params: unwrappedArray)
}
I tried to map the array and get a new one with all elements unwrapped and then call the fn. But when I ran the test again, I got a compile error:
Cannot convert value of type String? to expected argument type '_?'
Can anyone explain and fix this error?
The problem is that your second implementation of if_let no longer takes as a final parameter a function of type (T,U,V)->(). It now needs a function of type ([T])->(). If you call it with one, it compiles:
if_let(s1, s2, s3) { args in // or: (args: [String])->() in
print("\(args[0]) - \(args[1]) - \(args[2])")
}
A relevant note, rather than an answer to the specific question: with Swift 2, you needn't enter the pyramid of doom no more
let a: String? = nil
let b: Int? = nil
let c: Double? = nil
// possible mutate...
if let a = a, b = b, c = c {
// do something with shadow vars
}

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?

Avoid consecutive "if let" declarations in Swift [duplicate]

This question already has answers here:
Using multiple let-as within a if-statement in Swift
(3 answers)
Closed 6 years ago.
In Swift I used if let declarations to check if my object is not nil
if let obj = optionalObj
{
}
But sometimes, I have to face with consecutive if let declarations
if let obj = optionalObj
{
if let a = obj.a
{
if let b = a.b
{
// do stuff
}
}
}
I'm looking for a way to avoid consecutive if let declarations.
I would try something like :
if let obj = optionalObj && if let a = obj.a && if let b = a.b
{
// do stuff
}
But the swift compiler do not allow this.
Any suggestion ?
Update
In swift 1.2 you can do
if let a = optA, let b = optB {
doStuff(a, b)
}
Original answer
In your specific case, you can use optional chaining:
if let b = optionaObj?.a?.b {
// do stuff
}
Now, if you instead need to do something like
if let a = optA {
if let b = optB {
doStuff(a, b)
}
}
you're out of luck, since you can't use optional chaining.
tl; dr
Would you prefer a cool one-liner instead?
doStuff <^> optA <*> optB
Keep reading. For how scaring it might look, this is really powerful and not so crazy to use as it seems.
Fortunately, this is a problem easily solved using a functional programming approach. You can use the Applicative abstraction and provide an apply method for composing multiple options together.
Here's an example, taken from http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values
First we need a function to apply a function to an optional value only only when it contains something
// this function is usually called fmap, and it's represented by a <$> operator
// in many functional languages, but <$> is not allowed by swift syntax, so we'll
// use <^> instead
infix operator <^> { associativity left }
func <^><A, B>(f: A -> B, a: A?) -> B? {
switch a {
case .Some(let x): return f(x)
case .None: return .None
}
}
Then we can compose multiple options together using apply, which we'll call <*> because we're cool (and we know some Haskell)
// <*> is the commonly-accepted symbol for apply
infix operator <*> { associativity left }
func <*><A, B>(f: (A -> B)?, a: A?) -> B? {
switch f {
case .Some(let value): return value <^> a
case .None: return .None
}
}
Now we can rewrite our example
doStuff <^> optA <*> optB
This will work, provided that doStuff is in curried form (see below), i.e.
func doStuff(a: A)(b: B) -> C { ... }
The result of the whole thing is an optional value, either nil or the result of doStuff
Here's a complete example that you can try in the playground
func sum(a: Int)(b: Int) -> Int { return a + b }
let optA: Int? = 1
let optB: Int? = nil
let optC: Int? = 2
sum <^> optA <*> optB // nil
sum <^> optA <*> optC // Some 3
As a final note, it's really straightforward to convert a function to its curried form. For instance if you have a function taking two parameters:
func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in f(a,b) } }
}
Now you can curry any two-parameter function, like + for example
curry(+) <^> optA <*> optC // Some 3
I wrote a little essay on the alternatives some time ago: https://gist.github.com/pyrtsa/77978129090f6114e9fb
One approach not yet mentioned in the other answers, which I kinda like, is to add a bunch of overloaded every functions:
func every<A, B>(a: A?, b: B?) -> (A, B)? {
switch (a, b) {
case let (.Some(a), .Some(b)): return .Some((a, b))
default: return .None
}
}
func every<A, B, C>(a: A?, b: B?, c: C?) -> (A, B, C)? {
switch (a, b, c) {
case let (.Some(a), .Some(b), .Some(c)): return .Some((a, b, c))
default: return .None
}
}
// and so on...
These can be used in if let statements, case expressions, as well as optional.map(...) chains:
// 1.
var foo: Foo?
if let (name, phone) = every(parsedName, parsedPhone) {
foo = ...
}
// 2.
switch every(parsedName, parsedPhone) {
case let (name, phone): foo = ...
default: foo = nil
}
// 3.
foo = every(parsedName, parsedPhone).map{name, phone in ...}
Having to add the overloads for every is boilerplate'y but only has to be done in a library once. Similarly, with the Applicative Functor approach (i.e. using the <^> and <*> operators), you'd need to create the curried functions somehow, which causes a bit of boilerplate somewhere too.
In some cases you can use optional chaining. For your simple example:
if let b = optionalObj?.a?.b {
// do stuff
}
To keep your nesting down and to give yourself the same variable assignments, you could also do this:
if optionalObj?.a?.b != nil {
let obj = optionalObj!
let a = obj.a!
let b = a.b!
}
After some lecture thanks to Martin R, I found an interesting workaround: https://stackoverflow.com/a/26012746/2754218
func unwrap<T, U>(a:T?, b:U?, handler:((T, U) -> ())?) -> Bool {
switch (a, b) {
case let (.Some(a), .Some(b)):
if handler != nil {
handler!(a, b)
}
return true
default:
return false
}
}
The solution is interesting, but it would be better if the method uses variadic parameters.
I naively started to create such a method:
extension Array
{
func find(includedElement: T -> Bool) -> Int?
{
for (idx, element) in enumerate(self)
{
if includedElement(element)
{
return idx
}
}
return nil
}
}
func unwrap<T>(handler:((T...) -> Void)?, a:T?...) -> Bool
{
let b : [T!] = a.map { $0 ?? nil}
if b.find({ $0 == nil }) == nil
{
handler(b)
}
}
But I've this error with the compiler: Cannot convert the expression's type '[T!]' to type '((T...) -> Void)?'
Any suggestion for a workaround ?