Proposal: =? operator

I would like to have a built in =? operator which only assigns if the rhs is non-nil. If the rhs is nil, then it would do nothing.


I can make it myself (and have for my own projects), but I make a lot of frameworks and custom controls, and I don't want to unexpectedly make custom operators in other people's code base.


I use this fairly often, and one of the main areas where it comes in handy is in NSCoding.


With the =? operator

required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
     
        color =? aDecoder.decodeObjectForKey("color") as? UIColor
        borderWidth =? aDecoder.decodeObjectForKey("borderWidth") as? CGFloat
        borderColor =? aDecoder.decodeObjectForKey("borderColor") as? UIColor
     
        commonSetup()
}


As you can see, if a coded object has been stored (as the expected type), then it updates the default value. If it has not been stored, then it leaves it at the current/default value.


Without the =? operator, I have to recreate the defaults (which can get out-of-sync)

required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
     
        color = aDecoder.decodeObjectForKey("color") as? UIColor ?? UIColor.blackColor()
        borderWidth = aDecoder.decodeObjectForKey("borderWidth") as? CGFloat ?? 1.0
        borderColor = aDecoder.decodeObjectForKey("borderColor") as? UIColor ?? UIColor.blackColor()
     
        commonSetup()
}

Replies

Is there a case where using

color = aDecoder.decodeObjectForKey("color") as? UIColor ?? color

would fail?

Hmm... the compiler was giving me guff about that earlier, but I just tried it again and it seems to be working. Thanks for that :-)


That said, if assignment is expensive, or the property has a 'didSet' with an expensive calculation, it is nice to avoid assignment in those cases. For example, I have several properties which flag that a layout pass is needed, or that other cached values need to be recalculated.


Of course you can just do:

if let value = rhs {
     property = value
}


but =? is a nice shorthand

As a mild example from the code I posted above, borderColor is actually a calculated getter/setter which gets/sets the borderColor from a layer in the view. Setting the value to itself requires creating a UIColor from the layer's CGColor, then taking that UIColor and transforming it back to a CGColor to set on the layer (which then also updates the CA presentation tree). Quite a bit of work being done to keep the status quo.


Not too bad, but I have a couple hundred of these views, so it adds up... and doing no work is preferable to doing work which doesn't actually accomplish anything...

You can avoid this recalculation by checking against oldValue in the didSet, which you should probably do for any expensive calculation and is unrelated to the optional assignment.