Search code examples
swiftpassword-generator

Binary operator '+' cannot be applied to operands of type 'String' and 'String?'


new to programming and not quite grasping how this is wrong, any advice is appreciated.

func exercise() {
    let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]

    var char0 = alphabet.randomElement()
    var char1 = alphabet.randomElement()
    var char2 = alphabet.randomElement()
    var char3 = alphabet.randomElement()
    var char4 = alphabet.randomElement()
    var char5 = alphabet.randomElement()

    print(char0 + char1 + char2 + char3 + char4 + char5)
}

Solution

  • Others have explained why your code gives an error. (String.randomElement() returns an Optional<String>, which is not the same thing as a String, and you can't use + to concatenate Optionals.)

    Another point: Your code is verbose and repetitive. There is a principle, "DRY", in computer science. It stands for "Don't Repeat Yourself". Any time where you have the same code over and over (maybe with slight variations) it is "code smell", and an opportunity to improve.

    You could rewrite your code without repetition like this:

    func exercise() {
        let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
    
       var result = ""
       for _ in 1...6 {
         result.append(alphabet.randomElement() ?? "")
       }
       print(result)
    }
    

    In that version, the expression alphabet.randomElement() only appears once. You don't repeat yourself. It also uses the ?? "nil coalescing operator" to convert possibly nil results to blank strings.


    Another way to handle it would be to define an override of the += operator that lets you append String optionals to a string:

    public func +=(left: inout String, right: Optional<String>) {
        left = left + (right ?? "")
    }
    

    Then your function becomes:

    func exercise() {
        let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
       var result = ""
       for _ in 1...6 {
        result += alphabet.randomElement()
       }
       print(result)
    }
    

    Yet another way would be to shuffle your source array, fetch the first 6 elements, and then join them back together into a String:

    func exercise() {
        let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
        
        let result = alphabet
            .shuffled()[1...6]
            .joined()
        print(result)
    }