Mixing optional binding and boolean expressions

There were few times already when I used this little-known feature of Swift in real code and it improved (in my opinion) readability a lot and much better described the intention of the code.

Here is the original code from the real app:

if let cutoffDate = menu?.cutoffDate where menu?.mealSwapEnabledForProduct == true {  
} else {

Very trivial piece of code. But it contains one problem - it communicate wrong intention. When optional binding comes first and is followed by where it may seem that we make decision based on the value in this optional and the boolean expression is secondary. But in fact decision here should be made based on the boolean expression.

We can make it much better because we don't have to have where always at the end of if statement:

if menu?.mealSwapEnabledForProduct == true,  
  let cutoffDate = menu?.cutoffDate  {
} else {

I think this way the code communicates our logic and intention much better.

In Swift we can combine optional binding with where and boolean expressions. But after we started optional binding block we can have only where at the end of it, or another optional binding block with its own where. So boolean expression can not appear after optional binding.

Here is the full grammar of if statement:

if-statement → if­ condition-clause ­code-block­ else-clause(opt­)  
else-clause → else­ code-block­  else­ if-statement­

condition-clause → expression­  
condition-clause → expression­,­ condition-list­  
condition-clause → condition-list­  
condition-clause → availability-condition­, ­expression­  
condition-list → condition­ | condition­,­ condition-list­  
condition → availability-condition­ | case-condition­ | optional-binding-condition­  
case-condition → case ­pattern­ initializer­ where-clause(­opt)­  
optional-binding-condition → optional-binding-head­ optional-binding-continuation-list­(opt) ­where-clause­opt­  
optional-binding-head → let­ pattern­ initializer­ | var ­pattern initializer­  
optional-binding-continuation-list → optional-binding-continuation­ |  optional-binding-continuation­, ­optional-binding-continuation-list­  
optional-binding-continuation → pattern ­initializer­ | optional-binding-head­  

So this grammar says that condition can start with expression (boolean) or availability condition, followed by condition list, which can contain another availability condition or case condition or optional binding. And as you can see condition list can contain several other condition lists.

For example this is a valid if statement:

  #available(watchOS 2, *), 
  booleanExpr1 && booleanExpr2, 
  #available(iOS 9, *), 
  let value11 = value1 where value11 > 0,
  case let .Some(value1) = value1 where value1 > 0,
  #available(OSX 10, *), 
  case let .Some(value2) = value2 where value2 < 0,
  let value22 = value2 where value22 < 0 {
comments powered by Disqus