Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.

Tuesday, March 13, 2012

Fizz 18 - Getting the Monkey Off of Your Patch

When talking about functions and methods there really isn't much difference between the two at first.  The real meaning and value doesn't start to show up until other esoteric features like  class inheritance, subtyping, polymorphism, late binding, multiple dispatch, meta-object protocols, category theory, and on and on and on.  That is the territory where PhDs are minted.  Without all that messy class theory the main difference between a method and a function are access to protected fields and an implicit this parameter.  Methods are also typically also declared inside the structure declaring the class.  And methods for a particular class are almost always declared by the original implementer of the class.  If you need a new method in a class, you nearly always had to sub-class the class.  Nearly.

fun Int.isFizz() : Boolean {
    return this % 3 == 0
}

fun Int.isBuzz() : Boolean {
    return this % 5 == 0
}

fun main(args : Array<String>) {
    for (i:Int in 1..100) {
        when {
            i.isFizz() && i.isBuzz() -> println("FizzBuzz")
            i.isFizz() -> println("Fizz")
            i.isBuzz() -> println("Buzz")
            else -> println (i)
        }
    }
}

Kotlin let you, after a fashion, declare methods that look like they belong in a class.

On line 10 we declare the looping variable i to be of type Int. This is a class provided by Kotlin and is one that is not open to extension. Remember, all classes are closed by default in Kotlin. But look at lines 12, 13, and 14. We are calling an isFizz and isBuzz method in the Int class. Surely they are not just juicing up the standard library to look good in a standard demo, are they?

It's not the Kotlin team that is juicing things up. It is the program itself. Lines 1-7 are declaring extension functions on the Int class. This is how we are adding what look like methods onto the already closed class Int. Really, these are not all that different from Python methods except for some syntactic sugar low-carb coding where the explicit self parameter becomes an implicit this parameter, whose type is explicitly determined by convention of the function name: <class name>.<method name>.

This addition, however, does not literally add a method to the class it is extending.  The method is not subject to any late binding or multiple dispatch.  The particular method is entirely determined at compile time.  It also must either be present in the package at compile time, or explicitly imported in the file in which it is used. So a developer can write an awesome set of String extension functions, like String.invertEveryThirdWord() and not have to involuntarily subject the world to their awesomeness by declaring them in the org.example.of.category.theory package, and only let the 1337 few who are worthy of it's power bask in it's glory.

No comments:

Post a Comment