Search code examples
swiftswift-extensions

Struggling to understand the code - which tries to return the decimal digit 'n' places in from the right of the number


I'm new to Swift and is trying to learn the concept of extension. I saw this code in "the swift programming language", which tries to return the decimal digit 'n' places in from the right of the number. The code work fine, but I am struggling to understand how the code actually works.

Could someone explain it to me?

extension Int {
    subscript(var digitIndex: Int) -> Int {
        var decimalBase = 1
        while digitIndex > 0 {
            decimalBase *= 10
            --digitIndex
        }
        return (self / decimalBase) % 10
    }
}

746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
746381295[9]

Solution

  • Extensions work by adding capability to existing types, with the caveat that they cannot introduce their own storage. In the case in point:

    /*1*/ extension Int {
    /*2*/     subscript(var digitIndex: Int) -> Int {
    /*3*/         var decimalBase = 1
    /*4*/         while digitIndex > 0 {
    /*5*/             decimalBase *= 10
    /*6*/             --digitIndex
    /*7*/         }
    /*8*/         return (self / decimalBase) % 10
              }
          }
    

    Line 1 defines the extension as applying to all Int types.

    Line 2 is setting up a new subscript operator for an Int, which will allow you to have 12345[4] and produce 'something'. Lines 3-8 define that something.

    The while in lines 4-8 is multiplying decimalBase by 10 for 'digitIndex' times. A bit of a weird way of doing it, but never mind. The upshot is if digitIndex is 1, decimalBase is 10; if it's 2, decimal base is 100; 3 it's 1000; etc.

    The guts is in line 8. First it retrieves self. Since the extension applies to an Int, self will be that integer value. It then divides it by decimalBase, and because they're both integers, any fractional part will be lost. Therefore in the case of 746381295[2] decimalBase will be 100 so you get 7463812. Then it uses '%' to get the remainder of the division by 10. So 7463812 divided by 10 is 746381 with a remainder of 2. So the returned value is 2.

    Hope that explains it.

    Pre-empting your question, I might use for in this case, instead of the while:

    for _ in 0..<digitIndex {
        decimalBase *= 10
    }
    

    I haven't thought too much about how often the above loops, it might run once to often or once too few, but you get the idea.

    Even better would be to use the 'raising to the power' operator (not really sure what it's called).

    decimalBase = 10 ^^ digitIndex
    

    Then the whole definition could boil down to:

    return (self / (10 ^^ digitIndex)) % 10
    

    I will leave it to you to decide whether that's better or not.

    Either way, I wouldn't really create this extension, and I assume it was just done for the purpose of demonstration.