Function Overloading

Kotlin supports function overloading, which is a form of polymorphism where the compiler deduces which function should get called based on the type and position of the arguments. When we overload functions, we create functions that have the same name, but different return types or arguments. This allows us to write code that is customized based on the type of the parameters based on the function. Let’s begin with an example.

class Bob(val name : String = "Bob")

/**
 * Here are five functions with the same name. Each function is resolved
 * based on the type of parameters that are supplied.
 */
fun foo(name : String) {
    println("Inside foo(String)")
    println(name)
}

fun foo(num : Int){
    println("Inside foo(Int)")
    println(num)
}

fun foo(bob : Bob){
    println("Inside of foo(Bob)")
    println(bob.name)
}

fun foo(any : Any){
    println("Inside of foo(Any)")
    println(any)
}

fun foo(name : String, any : Any){
    println("Inside of foo(name, any)")
    println("$name, $any")
}

Here are five functions named foo. The compiler can figure out which function to use because all five of our foo functions take a different type as an argument. So when we call foo(“Hello World”) the version of foo that takes a String parameter is used because “Hello World” is a String. Likewise, when we call foo(12), the compiler will choose the foo(Int) version because 12 is an int. The final version of foo takes two parameters, String and Any. It will get called when we supply a String and another object so foo(“Hello”, “Bob Belcher”) matches to foo(String, Any) as well as foo(“Bob is #”, 1).

Optional Arguments

The designers of Kotlin realized that while function overloading is useful, it can also turn into verbose code. Kotlin supports optional arguments and named arguments to help address the problem.

fun foo(num : Long = 0,
        name : String = "",
        bob : Bob = Bob(),
        any : Any = object{
    override fun toString() = "Object"
}){
    println("Inside of default argument function")
    println(num)
    println(name)
    println(bob)
    println(any)
}

When this code compiles, the compiler will basically overload the foo function for us, but we can avoid writing a bunch of overloaded function when we use optional arguments correctly. This version of foo can be called by writing foo(), which uses all of the defaults, foo(num = 12L), which uses the defaults except for the num parameter which is set to 12. We can also write foo(any = Bob()), and so on.

Putting it Together

Here is a sample driver program that shows off function overloading and optional arguments.

package ch1.overloading

class Bob(val name : String = "Bob")

/**
 * Here are five functions with the same name. Each function is resolved
 * based on the type of parameters that are supplied.
 */
fun foo(name : String) {
    println("Inside foo(String)")
    println(name)
}

fun foo(num : Int){
    println("Inside foo(Int)")
    println(num)
}

fun foo(bob : Bob){
    println("Inside of foo(Bob)")
    println(bob.name)
}

fun foo(any : Any){
    println("Inside of foo(Any)")
    println(any)
}

fun foo(name : String, any : Any){
    println("Inside of foo(name, any)")
    println("$name, $any")
}

//Note that we can also use default arguments in Kotlin
//which lets us reduce function overloading
fun foo(num : Long = 0,
        name : String = "",
        bob : Bob = Bob(),
        any : Any = object{
    override fun toString() = "Object"
}){
    println("Inside of default argument function")
    println(num)
    println(name)
    println(bob)
    println(any)
}

fun main (args : Array<String>){
    //Resolves to foo(String) because "Hello World" is a String
    foo("Hello World")

    //Resolves to foo(Int) because 1 is an int
    foo(1)

    //Resolve to foo(Bob) because Bob is Bob
    foo(Bob())

    //Resolves to foo(Any) because the object expression matches
    //to Any, which is the base type of all objects in Kotlin
    foo(object { override fun toString() = "Object"})
    
    //Matches to foo(String, Any)
    foo("Hello ", Bob())

    foo() //Called with optional arguments.

    foo(num = 2L) //Called with only using one of the optional arguments
}

When run, we get this output

Inside foo(String)
Hello World
Inside foo(Int)
1
Inside of foo(Bob)
Bob
Inside of foo(Any)
Object
Inside of foo(name, any)
Hello , ch1.overloading.Bob@3caeaf62
Inside of default argument function
0

ch1.overloading.Bob@6a38e57f
Object
Inside of default argument function
2

ch1.overloading.Bob@5577140b
Object
Advertisements

Python Line Scanner

This post borrows from a code example found in Programming Python: Powerful Object-Oriented Programming that demonstrates collecting command line arguments, opening a file, reading the file, and passing a function as a callback to another function.

Code

Here is the entire script that accepts a file as a command line argument and prints the contents of the file to the console.


def scanner(name, func):

    # Open the file (with statement ensures closure even if there is an exception)
    with open(name, 'r') as f:
        # Iterate through the file
        for line in f:
            # Call our callback function
            func(line)

if __name__ == '__main__':
    import sys
    name = sys.argv[1]

    # This is a function we are passing to scanner
    # Python has first class functions which can be
    # get passed as arguments to other functions
    def print_line(str):
        print(str, end='')

    # Call the scanner function, which in turn
    # calls the print_line function for each line
    # in the file
    scanner(name, print_line)

Command Line Arguments

The first concept covered in this script is processing command line arguments. Python requires us to import the sys module (line 12) which maintains an argv property. The argv property is a list-like object that contains all of the command line arguments used to hold all of the command line parameters. The first index [0] is the name of the script, followed by all of the other arguments supplied to the program.

On line 13, we grab the target file (stored in argv[1]) and keep it in a name variable. At this point, our program knows which file to the open later on when we use the scanner function.

First Class Functions

Python treats functions as objects. As such, we can define any function in a Python program and store it in a variable just like anything else. Lines 18-19 define a print_line function that accepts a String parameter. On line 24, print_line is the second argument to the scanner function.

Once inside of the scanner function, the print_line function is referenced by the variable func. On line 9, we call print_line with the func(line) rather than print_line(line). This works because func and print_line both refer to the same function object in memory. Passing functions in this fashion is incredibly powerful because it allows the scanner function to accept different behaviors for each line it processes.

For example, we could define a function the writes each line processed by scanner to a file rather than printing it to the console. Later on, we may choose to write another function that sends each line over the network via network sockets. The beauty of the scanner function as defined is that it works the same regardless of the callback function passed to the func argument. This programming technique is sometimes known as programming to a behavior.

Opening and Reading Files

The final topic covered is opening and reading a file. Line 5 in the script uses the with statement combined with the open function to actually open the file in read mode. The as f assigns the result of the open function to the variable f. The f variable holds a Python file object.

Since Python file objects support the iterator protocol, they can be used in for loops. On line 7, we read through each line in the file with the statement for line in f:. On each execution of the loop, the line variable is updated with the next line in the file.

When the loop is complete, the with statement calls the file’s close() method automatically, even if there is an exception. Of course, Python’s garabage collection will also ensure a file is closed, but this pattern provides an extra level of safety, especially since there are a variety of Python interpretors that may act differently than the CPython.

Conclusion

The most powerful take away from this example if the first class functions. Python treats functions like any other data type. This allows functions to be stored as passed around the program as required. Using first class functions keeps code loosely coupled and highly maintanable!

Sources

Lutz, Mark. Programming Python. Beijing, OReilly, 2013.

Kotlin Koans—Part 23

This portion of the Kotlin Koans tutorial appeared to be a review of the concepts I had been working on throughout the collection section. I had to solve three different problems using the collections API. While doing this, I got to revist the Elivis operator (?:), map, maxBy, sumBy, filter, count, and toSet.

Get Customers Who Ordered Product

This problem focused on filtering.

fun Shop.getCustomersWhoOrderedProduct(product: Product): Set {
    // Return the set of customers who ordered the specified product
    return customers.filter { it.orderedProducts.contains(product) }.toSet()
}

The filter method takes a predicate that returns true or false. In this case, I just used the contains method on orderedProducts. If the product is found in orderedProducts, we get a true, otherwise false. Then there is a toSet() operation to transform the collection to a set.

Get Most Expensive Delived Products

This problem was a little more challenging. I had to go back and review how to use the Elivis operator (TODO: Link).

fun Customer.getMostExpensiveDeliveredProduct(): Product? {
    // Return the most expensive product among all delivered products
    // (use the Order.isDelivered flag)
    return orders.filter { it.isDelivered }.map { it.products.maxBy { it.price } }.maxBy { it?.price ?: 0.0}
}

I started with a filter operation to check if an order was delivered or not since the problem statement required me to find the most expensive delivered product. Then I had to use a map operation which allowed me to traverse all delivered orders. At this point, I could use a maxBy operation and check it.price. This builds up a collection of products that contains the most expensive product on each order.

The next part of the operation is to find the most expensive product of all orders. At this point, I have a collection of products so I just needed another maxBy operation. However it was a little more trickey this time. In this case, there was a possibily that the variable it could be null. It’s nice that Kotlin has compiler checks for this sort of thing because I truthfully didn’t realize that I could be working with null objects here. Thus, I had to use the Elvis operator in this final lambda operation.

Get Number Of Times Product Was Ordered

I had to solve this problem by chaining transformations together again.

fun Shop.getNumberOfTimesProductWasOrdered(product: Product): Int {
    // Return the number of times the given product was ordered.
    // Note: a customer may order the same product for several times.
    return customers.sumBy { it.orders.sumBy { it.products.count { it == product } } }
}

A customer has a one to many relationship with orders, and orders have a one to many relationship with products. I needed two sumBy operations to solve this problem. I began with a sumBy on customers. Inside of the lambda, I did another sumBy operation on orders. Once I was traversing orders, I could do a count operation on products and get a total of how many products matched my predicate.

The it.products.count returns a number that gets fed into it.orders.sumBy. The it.orders.sumBy returns a number that gets fed into customers.sumBy. Once customers.sumBy returns, we have a count of the total number of times the specified product was ordered.

You can click here to see Part 22

Kotlin Koans—Part 22

More functional programming on the horizon. This portion of Kotlin Koans demonstrated folding. I personally had never tackled a challenge like this so it took me more time to figure it out than the other problems. My job was to go through all customers and the products they ordered and reduce them down to a single set of objects. Here is the Kotlin code.

fun Shop.getSetOfProductsOrderedByEveryCustomer(): Set {
    // Return the set of products ordered by every customer
    return customers.fold(allOrderedProducts, {
        orderedByAll, customer ->
            orderedByAll.intersect(customer.orderedProducts)
    })
}

As usual, I tried to do the same problem in Java for comparison purposes, but I wasn’t able to figure it out! (If you know the solution, please leave it in the comments section!). I’ll have to admit that I am weak in some of the functional programming areas.

You can click here to see Part 21.

Kotlin Koans—Part 21

The Kotlin Koans tutorial continues with more demonstrations about the extensions on collection classes. This portion of the tutorial was a partitioning problem where I had to return the customers that have not had their orders delivered. Here is the code.

fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set {
    // Return customers who have more undelivered orders than delivered
    return customers.partition { it.orders.all { it.isDelivered } }.second.toSet()
}

Kotlin adds a partition method to it’s collection classes. The partition method takes a lambda expression that returns a boolean. Inside of this lambda, I used the all (#TODO Link to All) method on the orders collection. Once again, I am returning a boolean value.

Now for the coolest part. Kotlin has a pair class that has a first and second method. Since I need the orders that are not delievered, I use the second property on the Pair class. At this point, second is holding a collection of Customers whose orders are not delivered. Finally, I can use the toSet (#TODO Link) method to transform the collection into a set.

Like the last few portions of this tutorial, I decided to compare the Kotlin code to the Java 8 code. Here is what I came up with.

public static Set getCustomersWithMoreUndeliveredOrdersThanDelivered(Shop shop){
    return new HashSet(shop.getCustomers()
            .stream()
            .collect(Collectors.partitioningBy((Customer c) -> c.getOrders().stream().allMatch(Order::isDelivered)))
            .get(false));
}

You can click here to see Part 20.

Kotlin Koans—Part 20

Grouping objects by a property and storing them into a map is a challenge that all developers have faced at some point in time. For example, you may have a collection of Customers and you wish to find out which Customers live in each city. Basically, you want a map where City is the key and a Collection of Customers associated with that City is the value.

This was exactly the problem that Kotlin Koans tutorial had me do.

fun Shop.groupCustomersByCity(): Map {
    // Return a map of the customers living in each city
    return customers.groupBy { it.city }
}

I was able to arrange all of the Customers by city with just one line of Kotlin code. The related Java code wasn’t that difficult either, but I did have to search for the solution since it wasn’t quite as clear as the Kotlin approach.

public static Map groupCustomersByCity(Shop shop){
    return shop.getCustomers().stream().collect(Collectors.groupingBy(Customer::getCity));
}

What helped me with the Kotlin approach was that since the groupBy method was direclty on the Collection object, my IDE was able to supply me with the groupBy method. That’s not the case with the Java approach since it’s using a static method on the Collectors class. It also didn’t occur to me to use the collect method on the Stream object either. I was looking for something that said group in it.

You can click here to see Part 19.

Kotlin Koans—Part 19

This section of the Kotlin Koans tutorial continued onward with Kotlin’s collection API enhancement. The challenge in this section use to total the price of all products a customer purchased. Here is the code

fun Customer.getTotalOrderPrice(): Double {
    // Return the sum of prices of all products that a customer has ordered.
    // Note: a customer may order the same product for several times.
    return orders.sumByDouble { it.products.sumByDouble { it.price } }
}

The collection API in Kotlin has a sumByDouble method, which takes a lambda expression. The lambda let’s developers chain function calls. In this case, each Customer had a collection of Products in each Order. To get the price of all Products ordered, I needed the sum of the price of all products in a order. This was easy enough to do because I just made a nested call to sumByDouble on it.products and then told it to sum on it.price.

Here is Java code that solves the same problem.

public static double getTotalOrderPrice(Customer customer){
    return customer
            .getOrders()
            .stream()
            .mapToDouble(
                    order -> order.getProducts()
                                    .stream()
                                    .mapToDouble(Product::getPrice)
                            .sum())
            .sum();
}

You can click here to see Part 18