H. Reed
H. Reed

Reputation: 1

Is there a clean way to handle assignment expressions inside condiionals in Swift 3?

I am new to Swift and am in the process of porting the jay parser generator to output a Swift parser. In the parser skeleton file I've found constructs that use the result of an assignment expression inside a conditional. E.g. ...

if ((yyN = yySindex[yyStates[yyTop]]) != 0 && 
    (yyN += yyErrorCode) >= 0 && 
     yyN < yyTable.Length && 
     yyCheck[yyN] == yyErrorCode) { ... }

Note in particular the (yyN += yyErrorCode) >= 0 expression

Since Swift doesn't allow assignment expressions to return a value is there an efficient way to code this type of construct in Swift?

Upvotes: 0

Views: 206

Answers (2)

dfrib
dfrib

Reputation: 73176

Since Swift doesn't allow assignment expressions to return a value is there an efficient way to code this type of construct in Swift?

Yes: separate the assignments from the conditionals, and break it up into smaller components (see e.g. @tuple_cat:s answer).


(Don't do this)

For the fun of it, and for a brief look at some technical possibilities of Swift; Swift can be used to emulate heavily clustered conditional evaluations as the one above. To Swiftify your example (in a horribly non-clean way), you could use inline yyN-capturing and Bool-returning closures to spice up the non-readability even further:

if ({_ in yyN = yySindex[yyStates[yyTop]]; return yyN != 0}()) && 
   ({_ in yyN += yyErrorCode; return yyN != 0}()) && 
   yyN < yyTable.Length && 
   yyCheck[yyN] == yyErrorCode { 
   /* ... */ 
}

Swift also also allows defining custom operators, so we could construct assignment operators which simply calls their default versions (side effect), but returns the assigned value as a result from the assignment statement. E.g. in case yyN is of type Int:

// some C++ style assignment operators
infix operator ^=: AssignmentPrecedence
infix operator ^+=: AssignmentPrecedence
extension Int {
    static func ^= (lhs: inout Int, rhs: Int) -> Int {
        lhs = rhs
        return rhs
    }
    static func ^+= (lhs: inout Int, rhs: Int) -> Int {
        lhs += rhs
        return lhs
    }
}

if ((yyN ^= yySindex[yyStates[yyTop]]) != 0 &&
    (yyN ^+= yyErrorCode) >= 0 &&
    yyN < yyTable.Length &&
    yyCheck[yyN] == yyErrorCode) {
    /* ... */
}

Upvotes: 1

Emil Laine
Emil Laine

Reputation: 42828

Yes:

yyN = yySindex[yyStates[yyTop]]
if yyN != 0 {
    yyN += yyErrorCode
    if yyN >= 0 && yyN < yyTable.Length && yyCheck[yyN] == yyErrorCode {
        // …
    }
}

Upvotes: 0

Related Questions