Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perform assignment only if right side is not nil

Tags:

swift

Is there a possibility to only perform an assignment (e.g. to a non-optional property) if the right hand side is not nil? I am looking for a one-line form for:

if let unwrapped = funcThatReturnsOptional() {
    object.nonOptionalProperty = unwrapped
}
like image 767
Ch1llb4y Avatar asked Jan 09 '16 20:01

Ch1llb4y


4 Answers

The answer from @Sajjon could be improved by using an if let to avoid reflection.

precedencegroup OptionalAssignment { associativity: right }

infix operator ?= : OptionalAssignment

public func ?= <T>(variable: inout T, value: T?) {
    if let value = value {
        variable = value
    }
}

like image 72
Fidel Morales Avatar answered Oct 13 '22 06:10

Fidel Morales


A single expression with the same effect as your code is

funcThatReturnsOptional().map { object.nonOptionalProperty = $0 }

but your code is definitely better readable.

Here the map() method of Optional is used and the closure is executed only if the function does not return nil.

like image 7
Martin R Avatar answered Nov 12 '22 17:11

Martin R


There are various ways that aren't too unwieldy

Using ?? :

object.nonOptionalProperty = funcThatReturnsOptional() ?? object.nonOptionalProperty 

Using a function :

func setNotNil<T>(inout variable:T, _ value:T?)
{ if value != nil { variable = value! } }

setNotNil(&object.nonOptionalProperty, funcThatReturnsOptional())

Using an operator :

infix operator <-?? { associativity right precedence 90 assignment }
func <-??<T>(inout variable:T, value:T?)
{ if value != nil { variable = value! } }

object.nonOptionalProperty <-?? funcThatReturnsOptional() 

Using an extension :

extension Equatable
{ mutating func setNotNil(value:Self?) { if value != nil { self = value! } } }

object.nonOptionalProperty.setNotNil(funcThatReturnsOptional())
like image 3
Alain T. Avatar answered Nov 12 '22 15:11

Alain T.


Okay, actually there is a way to achieve exactly this by introducing a new operator ?=:

infix operator ?= { associativity right precedence 90 }
func ?= <T: Any> (inout left: T, right: T?) {
    if let right = right {
        left = right
    }
}

By using ?= defined as above you can actually assign an optional to a non-optional if the optional has a value inside.

like image 2
Ch1llb4y Avatar answered Nov 12 '22 17:11

Ch1llb4y