Kotlin Koans—Part 2

After doing the first tutorial on Kotlin, I was impressed, but let’s face it, anyone can do a simple “hello world” style program. Nevertheless, I decided to continue with the Kotlin tutorial found at kotlinlang.org. When I moved onto part two of the tutorial, I was really impressed.

It wasn’t that I was super impressed with the language itself. It was IntelliJ’s support of Kotlin that blew me away. When you copy and paste Java code into the IDE, it will offer to translate it to Kotlin for you.

You can see in the video that IntelliJ just did the work of taking the Java code that I copied and pasted into my Kotlin class. I thought this was incredibly slick because it gave me the change to see the differences between Java and Kotlin.

Of course, I wanted to do the exercise myself so that I can get the hang of writing Kotlin code. The problem in this portion of the tutorial was to take this Java code and rewrite as Kotlin code.

public class JavaCode1 extends JavaCode {
    public String task1(Collection collection) {
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Integer element = iterator.next();
            sb.append(element);
            if (iterator.hasNext()) {
                sb.append(", ");
            }
        }
        sb.append("}");
        return sb.toString();
    }
}

It’s not too painful of code. Here is what I ended with when I wrote the code as Kotlin code on my own.

fun todoTask1(collection: Collection): Nothing = TODO(
    """
        Task 1.
        Rewrite JavaCode1.task1 in Kotlin.
        In IntelliJ IDEA, you can just copy-paste the code and agree to automatically convert it to Kotlin,
        but only for this task!
    """,
    references = { JavaCode1().task1(collection) })


fun task1(collection: Collection): String {
    val sb = StringBuilder()
    sb.append("{")
    val iterator = collection.iterator()
    while (iterator.hasNext()){
        val element = iterator.next()
        sb.append(element)
        if (iterator.hasNext()){
            sb.append(", ")
        }
    }
    sb.append("}")
    return sb.toString()
}

There was one thing I noticed about the Kotlin code that I liked. It looks as if we are allowed to have free standing functions in Kotlin outside of a class definition. While I appreciate OOP, there are frankly times where I’m not sure if OOP is the best approach to a problem. This was one of things I really like about Python is that I can break out of OOP when I want.

Now I know that it’s perfectly true that we can use static imports in Java, but I have always felt that was a clumsy approach. Static functions and static imports always seemed more like an after thought to the language that got tacked on after enough people complained. Of course, that’s just a matter of opinion, but anyway, I do like having a choice in Kotlin about when to use classes or just when to use function. Kotlin seems to have included this choice as part of the design of the language right from the get go.

You can click here to see Part 1 and here to see Part 3.

Functions—Python

All computer programming languages allow developers to seperate code into reuseable pieces of code called functions. Functions are critical because they allow us to generalize pieces of work into a block of code and reuse that code as many times as needed. When designed well, functions improve code readability by cutting down on the length of the code. We can also debug our code easier because we only have to look in on place for a bug rather than several places.

Demonstration

Let’s begin with a function demonstration.

# A function
def nested_func():
    print('Inside of nested_func()')
    return 'value'


# A function
def func():
    print('Inside of func()')

    val = nested_func()
    print('Back in func(). nest_func() returned {}'.format(val))


# Not a function
if __name__ == '__main__':
    print('Outside of all functions. Calling func()')
    func()
    print('Back from our functions')

This is a block of code that creates two functions. When we run the code, we get this output.

Outside of all functions. Calling func()
Inside of func()
Inside of nested_func()
Back in func(). nest_func() returned value
Back from our functions

Computer programs normally run from top to bottom one line at a time. In the case of this program, the program doesn’t start until we reach if __name__ == '__main__':. This is because Python runtime isn’t going to execute the code inside of nest_func() or func() until the functions are called.

When the code reaches 17, it executes the print statement. The next line, 18, is our first call to a function. We named our function func() in this case. Calling func() causes the program’s execution to jump up to line 9. Once we are at line 9, Python executes the print statement and then moves onto the next line in the function, line 11.

Line 11 creates a variable called val and then calls our next function, nested_func(). The nested_func() function is a function that returns a value. Program execution moves to line 3. Line 3 executes the print statement, and then line 4 returns a String value. The program execution returns back to line 11.

At this point, the variable val has a value stored in it. The program’s execution goes to line 12 and the print statement is executed. Now the program exits the func() function and control returns to line 19. The program executes the final print statement found on line 19 and then exits.

Defining a function

You create functions in Python by using the def keyword followed by the name of the function. After the name of the function, you have an opening parentheses ( followed by a closing parenthese ). You can place any number of variables inside of the parentheses. Here is an example

# Function with arguments
def func(val, val2):
    print(val)
    print(val2)

# Calling the function
func('Hello', 'World')

The name of this function is func. It has two arguments, val and val2. After the colon, you can include any number of statements you would like inside of the function. The function is now a seperate unit of code at this point. This function get’s called by func('Hello', 'World'). Anytime the Python interpreter something like this, it will execute all of the statements inside of func. We do not have to use ‘Hello’ or ‘World’ as the argument either. It’s perfectly ok to do something like func(47, 'Thunderbiscuit').

Optional Arguments

We can specify default values to our functions.

def some_func(arg1='Mickey'):
    print(arg1)

# Prints 'Mouse'
some_func('Mouse')

# Prints 'Mickey'
some_func()

Since this function has optional arguments, we can either pass it our own argument, or we can just use the default. The first call passes ‘Mouse’ to some_func, in which case arg1 = ‘Mouse’. The second call does not specify a value, so arg1 gets the default ‘Mickey’ value.

Lists—Python

Lists are a sequence type object that Python provides to us for grouping data together into a single variable. Let’s consider a common application of a list before we go into details.

names = ['Bob Belcher',
         'Linda Belcher',
         'Tina Belcher',
         'Gene Belcher',
         'Louise Belcher']
for name in names:
    print (name)

This code creates a list called names and populates it with five names. Then it prints the names to the console. We could accomplish the same output by using this code.

bob = 'Bob Belcher'
linda = 'Linda Belcher'
tina = 'Tina Belcher'
gene = 'Gene Belcher'
louise = 'Louise Belcher'

print(bob)
print(linda)
print(tina)
print(gene)
print(louise)

A quick comparison shows that the first example is not only much easier to read, but it is also more maintainable. If we want to print additional names, we only need to add them to the names list in the first example. However, in the second example, we need to add new name variable and another print statement. This may not seem like a big deal with six names, but obviously 6,000 is a much different case.

It’s for this reason that almost every programming language provides some sort of a collection object. List is one such data type that Python provides out of the box. Let’s look at common list operations.

Check if item is in the list

We may want to check if a list has a certain item.

names = ['Bob Belcher',
         'Linda Belcher',
         'Tina Belcher',
         'Gene Belcher',
         'Louise Belcher']
if 'Bob Belcher' in names:
    print('Found Bob')

This code prints ‘Found Bob’ because 'Bob Belcher' in names returns True.

Check if item is not in list

We can also check if a list does not have an item.

names = ['Bob Belcher',
         'Linda Belcher',
         'Tina Belcher',
         'Gene Belcher',
         'Louise Belcher']
if 'Teddy' not in names:
    print('No Teddy here!')

This code would print ‘No Teddy here!’ because 'Teddy' not in names is True. Our names list does not have ‘Teddy’

Combine lists

We can add two lists together (called concatenation) using the + operator.

belchers = ['Bob Belcher',
            'Linda Belcher',
            'Tina Belcher',
            'Gene Belcher',
            'Louise Belcher']

pestos = ['Jimmy Pesto',
          'Jimmy Pesto Jr.',
          'Andy Pesto',
          'Ollie Pesto']

family_frackus = belchers + pestos
print(family_frackus)

This code will print all of the names to standard out when run.

Accessing items

Lists use the index operator access items

belchers = ['Bob Belcher',
            'Linda Belcher',
            'Tina Belcher',
            'Gene Belcher',
            'Louise Belcher']
print(belchers[0])
print(belchers[3])

Keep in mind that lists are 0 based, so belchers[0] is ‘Bob Belcher’ while belchers[3] is ‘Gene Belcher’

Add item to list

We can add an item to a list using the append() method.

belchers = ['Bob Belcher',
            'Linda Belcher',
            'Tina Belcher',
            'Gene Belcher',
            'Louise Belcher']
belchers.append('Teddy')
print(belchers[5])

Remove item from a list

We use the del operator to remove an item from a list

belchers = ['Bob Belcher',
            'Linda Belcher',
            'Tina Belcher',
            'Gene Belcher',
            'Louise Belcher']
del belchers[0]

Using del belchers[0] removes ‘Bob Belcher’ from the list.

Replace item in a list

We can replace an item in a list by specifying the index and assigning a new value to it.

belchers = ['Bob Belcher',
            'Linda Belcher',
            'Tina Belcher',
            'Gene Belcher',
            'Louise Belcher']
belchers[0] = 'Mort'

The code belchers[0] = 'Mort' replaces ‘Bob Belcher’ with ‘Mort’

Length of the list

We get the length of the list using len.

belchers = ['Bob Belcher',
            'Linda Belcher',
            'Tina Belcher',
            'Gene Belcher',
            'Louise Belcher']
print(str(len(belchers))) 

The print(str(len(belchers))) prints 5 to the console.

Conclusion

We can do a lot more with lists than what was discussed in this post. Make sure you check out the Python documentation for a complete list of features!

Strings—Python

Python has native support for Strings (which is basically text). Many computer programs need to process text data and Python’s string type has powerful features to make the lives of developers easy!

String Literals

Here are a few examples of how to create strings in Python using literals.

sq = 'String made with Single Quotes'
dq = "String made with double quotes"
tq = """String with triple quotes"""

Double quote strings let you embed an apostrope character without escaping it. So you can write “I’m a cat” as a string literal in Python. Triple quote strings allow white space and line breaks in the string.

Individual Characters

Python strings support the index operator, so you can access characters in a string using [n] where n is the position of the character you wish to access. Here are a few ways to process strings by individual characters.

kitties = 'I like kitties'

# Access by index
for i in range(0, len(kitties)):
    print(kitties[i])

# Access with iteration
for c in kitties:
    print (c)

Useful Methods

The Python string class has many useful methods. You can view them all at Python documentation. Here are some of the ones I use the most.

islower()

This checks if a string is all lower case characters.

kitties = 'i like kitties'
if kitties.islower():
    print(kitties, ' is lower case')
else:
    print(kitties, ' is not lower case')

lower()

Python Strings are immutable, but you can use lower to convert a string to all lower case.

kitties = 'I like kitties'

if not kitties.islower():
    kittens = kitties.lower()
    print(kittens) 

isupper()

This method tests if a string is all upper case.

kitties = 'I LIKE KITTIES'

if kitties.isupper():
    print(kitties, ' is upper case')
else:
    print(kitties, ' is not upper case')

upper()

This method converts the string to upper case.

kitties = 'i like kitties'

if not kitties.isupper():
    cat = kitties.upper()
    print(cat)

isnumeric()

Checks if the strings is a numbers. This is useful if you want to convert a string to an int.

number_str = '3'

if number_str.isnumeric():
    number = int(number_str)

format()

This is useful for using a generic string that allows you to replace {} with values.

fm = 'I have {} kitties'
print(fm.format(3')
# Prints: I have 3 kitties

Numbers—Python

Computer programs need to track numberic data every single day. You may want to track balances in bank accounts, scientific numbers, or just counters. Python gives us a wide variety of numeric processing types. Here are some of the more common ones:

  • Integers
  • Floats
  • Boolean
  • Decimals
  • Fractions

Integers

Integers are whole numbers that are either positive or negatives. Unlike langues such as Java or C++ (or Python 2.x) Python does not distinguish between regular and long integers. Here are some examples of declaring integers

positiveNumber = 123456
negativeNumber = -111

Floating Point Numbers

Floating point numbers are numbers that have decimal points or numbers in scientific notations. They can be positive or negative.

dollar = 3.15
pi = 3.14159
sci = 8.2e10

Octal, hex, binary

Here are examples of numbers in octal, hexadecimal, and binary numbers.

oct = 0o237
hex = Ox9F
binary = Ob10011111

Decimals and Fractions

Python provides us with Decimal and Fraction data types which maintainer percision with decimal points. A loss of percision may not get noticed in trival programs, but when working with big datasets, the loss of percision can introduce major bugs in the program.

d = Decimal('1.59')
f = Fraction(1, 3) # Numerator / denominator

Boolean

Booleans hold true and false values.

b = True
f = False

For more information

You can learn more by visiting the python documentation.

Enumerations—Python

Enumerations are a way to group constants together and improve code readibility and type checking. Here is an example of an enumeration in Python.

from enum import Enum
from random import randint


class Color(Enum):
    RED = 1
    BLUE = 2
    GREEN = 3


def pick_color():
    pick = randint(1, 3)
    if pick == Color.RED.value:
        return Color.RED
    elif pick == Color.BLUE.value:
        return Color.BLUE
    elif pick == Color.GREEN.value:
        return Color.GREEN


def print_color(color):
    if color == Color.RED:
        print('Red')
    elif color == Color.GREEN:
        print('Green')
    elif color == Color.BLUE:
        print('Blue')


if __name__ == '__main__':
    color = pick_color()
    print_color(color)

Python enumeration extend the enum class. After inheriting from enum, we just list out the values in our enumeration and assign them constants.

The pick_color() function returns a randomly picked enumeration. We then pass that value to print_color().

You’ll notice that print_color accepts a color object and does comparisons against the values of the Color enumeration. You can see that the code is much more readible (and also more robust) than using literals such as 1, 2, or 3 in our code. The other nice aspect of using an enumeration is that we can change the values of our constants without breaking code and we can add more constants if needed.

Kotlin Koans—Part 1

I read that Android is going to officially support Kotlin now. Last year, I bought the IntelliJ IDE and one of the first things I noticed was that the IDE offered to make Kotlin classes. I had never done anything with Kotlin but I often wondered about it. It looked interesting to me, but now that Google has thrown in with Kotlin, I decided to give it try for myself.

This is the first in a series of posts where I’m going to work through the tutorials provided on kotlinlang.org. This first post was on the very first tutorial, which is the classical ‘Hello World’ style problem.

I started by cloning the github project that they give you. Here is what I got presented with.

package i_introduction._0_Hello_World

import util.TODO
import util.doc0

fun todoTask0(): Nothing = TODO(
    """
        Introduction.

        Kotlin Koans project consists of 42 small tasks for you to solve.
        Typically you'll have to replace the function invocation 'todoTaskN()', which throws an exception,
        with the correct code according to the problem.

        Using 'documentation =' below the task description you can open the related part of the online documentation.
            Press 'Ctrl+Q'(Windows) or 'F1'(Mac OS) on 'doc0()' to call the "Quick Documentation" action;
            "See also" section gives you a link.
            You can see the shortcut for the "Quick Documentation" action used in your IntelliJ IDEA
            by choosing "Help -> Find Action..." (in the top menu), and typing the action name ("Quick Documentation").
            The shortcut in use will be written next to the action name.

        Using 'references =' you can navigate to the code mentioned in the task description.

        Let's start! Make the function 'task0' return "OK".
    """,
    documentation = doc0(),
    references = { task0(); "OK" }
)

fun task0(): String {
    return todoTask0()
}

My job was to make the function task0 was to make it return “OK”. It wasn’t too painful. I just had to update task0

fun task0(): String {
    return "OK"
}

Once I did this, I ran the unit test that they give you to check if you did the task properly. This was easy to do in IntelliJ. The IDE provides you with a button to click on to run the test.
run_test
After I ran the test, I got the output the test was expecting.

Recursion Example — Walking a file tree

Many developers use Python as a platform independent scripting language to perform file system operations. Sometimes it’s necessary to walk through a file system. Here is one way to navigate a file system recusively. (Of course, Python has libaries that do this!)

import os

def walk_fs(start_dir):
    # Get a list of everything in start_dir
    contents = os.listdir(start_dir)

    # This stores the output
    output = []

    # Loop through every item in contents
    for f in contents:
        # Use os.path.join to reassmble the path
        f_path = os.path.join(start_dir, f)

    # check if f_path is directory (or folder)
    if os.path.isdir(f_path):
        # Make recusive call to walk_fs
        output = output + walk_fs(f_path)
    else:
        # Add the file to output
        output.append(f_path)

    # Return a list of files in the directory
    return output

if __name__ == '__main__':
    try:
        result = walk_fs(input('Enter starting folder => '))
        for r in result:
            print(r)
    except FileNotFoundError:
    print('Not a valid folder! Try again!')

The key to this is to begin by using os.listdir, which returns a list of every item in a directory. Then we can loop through each item in contents. As we loop through contents, we need to reassemble the full path because f is only the name of the file or directory. We use os.path.join because it will insert either / (unix-like systems) or \ (windows) between each part of the path.

The next statement checks if f_path is a file or directory. The os.path.isdir function is True if the item is a directory, false otherwise. If f_path is a folder, we can make a recursive call to walk_fs starting with f_path. It will return a list of files that we can concat to output.

If f_path is a file, we just add it to output. When we have finished iterating through contents, we can return output. The output file will hold all of the files in start_dir and it’s subdirectorys.

Tuples—Python

Tuples are another one of Python’s built-in collection objects. Since tuples implement the immutable sequence type, they boast much of the same functionality as lists, with the main difference being that tuples are immutable.

Using Tuples

You can declare tuples like so

# literals
belchers = ('Bob Belcher', 'Linda Belcher')

# constructor
pestos = tuple('Jimmy Pesto', 'Andy Pesto')

You can also convert a list to a tuple using this code

# Make a list
belcher_list = ['Bob Belcher', 'Linda Belcher']

# Turn list to a tuple
belcher_tuple = tuple(belcher_list)

# Back to a list now
new_belcher_list = list(belcher_tuple)

Tuples generally have the same methods as lists, but you are prohibited from doing anything that modifies the tuple

  • No reassignments
  • No adding elements
  • No removing elements
  • No sorting or shuffling

However, you are free to modify objects stored in a tuple and you are free to use any of the read methods on a tuple. So for example, you can still access items in a tuple by using the [] operator, and tuples support iteration allowing the to be used in a for loop.

Need for Tuples

Immutable is a fancy programming word that means an object is read-only. Unlike a list, tuples forbid operations that modify the tuple. That means you are not free to add, remove, or sort tuples (note that you can modify the objects stored in a tuple just not the tuple itself). Tuples are useful in programming because they provide a safe guard against inadvertant modification of a sequence.

For exampe, let’s suppose that we have a database table that looks like the one below.

  • ID (PK)
  • First Name
  • Last Name
  • Job Title
  • Salary

When we run database queries against this table, we most likely aren’t going to want to change the order of the result set’s columns. However, a list would allow use to do that exact sort of thing. We could certainly program defensively to make sure our code doesn’t modify the order the columns, but even so, it’s easy to write code like the below example.

def nested_func(result_set):
# Modify the result_set
# in a nested function
result_set.reverse()

def func(result_set):
# Do some sort of work
nested_func(result_set)

if __name__ == '__main__':
# Store DB row in result_set
# We don't want the order to change
result_set = [1, 'Bob',
'Belcher', 'Owner']

print(result_set)
func(result_set)

# Did our order change?
print(result_set)

Remember that our intention was to maintain the order of result_set. We call func() which in turns calls nested_func. Here is the result of this program when executed.

[1, 'Bob', 'Belcher', 'Owner']
['Owner', 'Belcher', 'Bob', 1]

This is a simple enough of a programming error to make on it’s own, but when a developer works with larger programs with multiple modules, it becomes an even easier error to make and worse, an even harder program to debug.

However, if we change result_set to a tuple rather than a list, the Python runtime will help us out and catch the error for us!

def nested_func(result_set):
# Modify the result_set
# in a nested function
result_set.reverse()

def func(result_set):
# Do some sort of work
nested_func(result_set)

if __name__ == '__main__':
# Store DB row in result_set
# Notice that it's a tuple now!!!
result_set = (1, 'Bob',
'Belcher', 'Owner')

print(result_set)
func(result_set)

# Did our order change?
print(result_set)

When executed, the program displays this output to the console instead…

AttributeError: 'tuple' object has no attribute 'reverse'

In this version of the program, nested_func attempts to call reverse() on a tuple object. Tuples do not have a reverse method, so the program crashes with an AttributeError along with the output of the stack so that we can track down where the error occurred in the program. In this way, the tuple protected us from a difficult to find bug that we would have had we used a list object.

Recursive Binary Search—Python

It’s possible to implement a binary search using recursion. Just like the loop version, we slice our sorted collection into halfs and check one half of the collection and discard the other half.

Here is the code

def binary_search(search_list, data, low, high):
    # This is the base case that
    # terminates the recursion
    if low <= high:
        # Find the mid point
        mid = int(low + (high - low) / 2)

        if search_list[mid] == data:
            # We found our item. Return the index
            return mid
        elif search_list[mid] < data:
            # Search the top half of search_list
            return binary_search(search_list, data, mid + 1, high)
        else:
            # Search the bottom half of the search_list
            return binary_search(search_list, data, low, mid - 1)
    return None


if __name__ == '__main__':
    names = ['Bob Belcher',
             'Linda Belcher',
             'Tina Belcher',
             'Gene Belcher',
             'Louise Belcher']

    print('Sorting names...')
    names.sort()

    linda_index = binary_search(names, 'Linda Belcher', 0, len(names) - 1)
    if linda_index:
        print('Linda Belcher found at ', str(linda_index))
    else:
        print('Linda Belcher was not found')

    teddy_index = binary_search(names, 'Teddy', 0, len(names) - 1)
    if teddy_index:
        print('Teddy was found at ', str(teddy_index))
    else:
        print('Teddy was not found')

When run, we get the following output

Sorting names...
Linda Belcher found at  2
Teddy was not found
%d bloggers like this: