Eliminate "if" statement

Sort of kidding. :slight_smile:

I have come to prefer using switch instead of if / else (if). (If there's only one branch then if is fine.)

I just wrote the following as an extension of String:

 func fixLength(_ length: Int) -> String {                                 
    if self.count < length {                                               
        return self + String(repeating: " ", count: length - self.count)   
    }                                                                      
    else if self.count > length {                                          
        return String(self.dropLast(self.count - length))                  
    }                                                                      
    return self                                                            
}                                                                          

While I realize its a very common idiom, I don't care for it aesthetically. I've tried two alternatives using switch, and while both (seem to) work, it still seems to me there should be a better alternative.

    switch true {                                                          
    case self.count == length:                                             
        return self                                                        
    case self.count < length:                                              
        return self + String(repeating: " ", count: length - self.count)   
    case self.count > length:                                              
        return String(self.dropLast(self.count - length))                  
    }                                                                      

The above option is quite readable, and almost the same as the if/else/if. Does the fact that it has to first do the compare in the case and then apply the result with the ~= operator to true make it less efficient? Or perhaps the compiler is able to optimize that away?

Then there is this one:

    switch self.count {                                                  
    case length:      //  self.count = length                            
        return self                                                      
    case ..< length:   //  self.count < length                            
        return self + String(repeating: " ", count: length - self.count) 
    default:          //  self.count > length                            
        return String(self.dropLast(self.count - length))                
    }                                                                    

Took me a bit to adjust to this. I guess it's OK.
Seems like a >.. postfix operator would be nice in this case, in place of the "default", i.e.:

    case length >..:          //  self.count > length                            
        return String(self.dropLast(self.count - length))                

That doesn't seem to exist, and I've not yet attempted to create it.

What I'd truly find ideal is the following:

    switch self.count {                                                  
    case length:      //  self.count = length                            
        return self                                                      
    case < length:    //  self.count < length                            
        return self + String(repeating: " ", count: length - self.count) 
    case > length:    //  self.count > length                            
        return String(self.dropLast(self.count - length))                
    }                                                                    

No idea if something like that is possible.

As a matter of precedence, the COBOL (yes COBOL) 2014 standard supports a similar idiom, called "partial expressions":

    evaluate cnt
    when length
        [...]
    when < length
        [...]
    when > length
        [...]
    end-evaluate

The partial expression 'selection object' of each 'when' branch is applied to the right side of the the 'selection subject' and evaluated.

Reasonable? Petty and asking for too much sugar?

Postfix >.. would be pretty simple to define. If you only wanted to handle integers you don't even need to declare a new type, just use the same technique we use to convert closed ranges to half-open ones. Exceeeept... >.. violates the rules for operators. :crying_cat_face:

postfix operator >••

extension Strideable {
    public static postfix func >•• (minimum: Self) -> PartialRangeFrom<Self> {
        return (minimum.advanced(by: 1))...
    }
}

That said, right now you'd still have to write a default: clause, because the compiler doesn't know enough about ranges to know your switch is exhaustive. But you can always fatalError it.

This is where ComparisonResult really shines, and I think it's too bad that it's in Foundation and not in the standard library. If you implement a compared(to:) method on Comparable (or even introduce a <=> operator), you can write

 func fixLength(_ length: Int) -> String {                                 
switch self.count.compared(to: length) {                                                          
    case .orderedSame:                                             
        return self                                                        
    case .orderedAscending:                                              
        return self + String(repeating: " ", count: length - self.count)   
    case .orderedDescending:                                              
        return String(self.dropLast(self.count - length))                  
    }                                                            
}    
1 Like