teaching machines

SENG 440: Lecture 1 – Mobility and Kotlin

Dear students,

Welcome to SENG 440! I’m visiting the University of Canterbury thanks to Erskine Fellowship Program. When I’m not in Christchurch, I live and work in the north central part of the United States in a state called Wisconsin. I’m glad to be here and to be teaching this course in particular. I’ve taught versions of it four times, but it’s been a few years, and I’ve missed it.

We have two big goals for today: to talk about the course a bit and to flex some coding muscle in the language we will be using this semester.

Probably I will be using some words that have different meaning than they do here in New Zealand. When I say course, I am referring to what New Zealanders sometimes call a paper. On restaurant menus back home, we start with appetizers and then move on to the entrees. Here you start with the entrees and move on to main dish. I say oh-RAY-gah-noh, while you say oh-ray-GAH-noh. If I unknowingly say something that has an offensive or awkward meaning in this country, please let me know so I can avoid future embarrassment.

I usually start my notes to you off with a list of things that I ask you to complete before the next time we meet. Here’s your first TODO list:

  • Read the syllabus.
  • Read the description of project 1.
  • Install Android Studio.
  • Read Basic Syntax and Basic Types.
  • Write a main function that declares some variables, executes some computation of your choice, and prints the results with a string template. Keep it short, and write it on a quarter sheet of paper (roughly A6) to be turned in at the beginning of the next lecture. Test your code in the Kotlin Playground at play.kotlinlang.org or in the Kotlin REPL in Android Studio.

Enough meta. Let’s start talking about mobile computing.

Mobile-First

In some sense, phones and tablets are just computers, and many of our desktop software development practices apply equally well to mobile app development. The ideas that you’ve learned in other courses are not going away; they are just as relevant when you are writing apps. But mobile computing has several qualities that make it a topic deserving of its own course. Some of these qualities emerge from the technical and physical specifications of our devices, like these four:

  • Ubiquitous. Our mobile devices are small and battery-powered, reaching geographic locations that are typically inaccessible to other types of computers. The number and variety of contexts in which we use mobile devices is much higher than for desktops and notebooks.
  • Situated. Our mobile devices can sense their local context. They can determine their geographic location, orientation, and properties of their environment, and they can hear and see what’s going on around them. Additionally, unlike landline phones and many desktop computers, mobile devices tend to be associated with individuals.
  • Connected. Our mobile devices can access a number of communication networks, including our cell carrier’s network, WiFi, and Bluetooth.
  • Finite. Our mobile devices have fewer and less reliable resources than other types of computers. Signals are easily lost, batteries die, and storage fills up faster.

These qualities are characteristic of all mobile platforms. Marc Andreesen, venture capitalist and author of Mosaic, the first web browser, defines platform in this way:

A “platform” is a system that can be programmed and therefore customized by outside developers—users—and in that way, adapted to countless needs and niches that the platform’s original developers could not have possibly contemplated, much less had time to accommodate.

Andreesen’s definition makes it clear that a platform is not strictly a technical product put out by a company. Platforms gain their identity from the kinds of software they enable and the developer and consumer culture they foster. What identity or cultural trends do we see in the software written for mobile platforms? I can think of a few:

  • Apps are casual. The operator of a mobile device is likely going to be using it in a regular but intermittent manner while going about their day. While waiting for the bus or an appointment, they will play interruptible games and seek out lightweight entertainment like music, video, and newsfeeds.
  • Apps are paranoid. Interruptions to service and power are expected and even a normal part of an app’s lifecycle, and devices containing precious data are easily lost or damaged. We expect our apps to transparently use caching and limited local storage to ride out lost services and use the cloud for persistent storage.
  • Apps are personal. Mobile devices have been trained to become an extension of ourselves. They are carried in our pockets or bags and are integrated into our daily tasks. They know our friends, our destinations, and our favorites. We use them to conduct commercial transactions, and they serve as one possible factor in multifactor authentication.
  • Apps are social. We post about life events as they happen on social media, we share messages and files, and we play multifriend games. We use our devices to become citizen scientists and journalists. Our shared media goes viral and garners likes, which triggers dopamine rushes and more posting.

Mobile development packages together several distinct subdisciplines of computer science: systems, human-computer interaction, and software engineering. In my opinion, this course should be a post-requisite, helping you contextualize and cement the ideas you have been introduced to in previous courses.

Choosing a Platform

There are at least three ways a course on mobile development could be structured. A course might focus on one particular mobile platform. Or it might cover several of the platforms. Or it might focus on a cross-platform approach that uses an intermediate language that can produce executables for different targets. I have tried to do all of these, and I was most satisfied with the learning and apps that students made when we focused on a single ecosystem. I decree therefore that this course will concentrate on a single platform.

These days Android and iOS are the only significant platforms left on the market. There are several platforms in the software graveyard, including Windows Mobile (from Microsoft), Windows Phone (from Microsoft), Blackberry (from Research in Motion), and Symbian (from Symbian Ltd. until acquired by Nokia). There are a few small players too, but Android and iOS together comprise over 95% of the mobile platform market.

How do you suppose this 95% is split? StatCounter offers a breakdown based on billions of website accesses.

To choose between iOS and Android, we must consider and weigh several factors:

  • market share
  • profitability
  • ease of development
  • the future

Android clearly wins the market share battle. But if you are in the business of selling your apps, you generally care more about revenue potential than the user base. iOS users tend to spend more money in the App Store than Android users spend in the Play Store. In 2018, Sensor Tower reports that App Store revenue was nearly double that of Google Play. iOS wins this round, but it should be noted that Play Store revenue grew twice as fast as the App Store revenue. We must keep an eye on the future.

While the previous three factors are important, they are more important in an industrial setting. We are in a learning environment, and ease of development is more important to us. We need access to the tooling.

Android development tools run in Windows, macOS, and Linux. We can freely install our apps on our personal devices and distribute them on the web. If we don’t have a device, we can run apps on an emulator. We can publish them via the Google Play store for a small one-time fee.

iOS development tools run on macOS. Apple is a hardware company, and macOS only legally runs on Macintosh hardware. Running it on a virtual machine violates the macOS license. There are third party tools that can be used to build iOS apps, but there’s not much we can do with them beyond that point without Macintosh hardware. With that hardware, we can freely install an app on a personal device, but it will expire after seven days. If we don’t have a device, we can run apps on a simulator. To permanently install apps and distribute them on the App Store, we must pay annually a fee that is four times that of Android’s one-time fee.

As an instructor of human beings from all socioeconomic and technical backgrounds, I favor tools that my students can freely use. Therefore, we will use Android in this course.

Please recognize that choosing between iOS and Android presents a false dichotomy. If you intend to make a profession of building mobile apps, you want to choose both. When your company asks what equipment you need at your first job, the only correct answer is that you need both Android and iOS devices, plus whatever else might be out there.

Kotlin

In previous incarnations of this course, we used the Java programming language to build our apps. This semester will be different.

In 2011, JetBrains released Kotlin, a language that was intended to marry ideas from functional and object-oriented languages and run on top of the Java Virtual Machine. We already had a few such languages, but JetBrains developer Dmitry Jemerov had this to say:

We’ve looked at all of the existing JVM languages, and none of them meet our needs. Scala has the right features, but its most obvious deficiency is very slow compilation. Other languages don’t meet some of our requirements in terms of the feature set.

While this is a reasonable justification, I think thing it ignores the psychological pull of developerism, the insatiable urge to create our own technology rather than use someone else’s.

In 2017, Google officially declared Kotlin as an official language for building Android apps. Enough people have switched from Java to Kotlin, and we will too in this course for two primary reasons:

  • Kotlin mostly imposes less syntactical burden than Java. We will write a lot of code together in class, and Java’s verbosity tends to be overwhelming in these live coding sessions.
  • Kotlin promotes a more functional style of programming, providing immutability, higher-order functions, and type inference. These are important ideas that you can transfer to other contexts.

Because this language is probably new to you, we will spend this first week looking at Kotlin apart from Android.

Main

Main functions in Kotlin look like this:

fun main(args: Array<String>) {
  println("Goodbye, Pluto!")
}

This is similar to the ones we write in Java, with one notable difference. They are defined at the top-level of our source code and not within a class.

Suppose we wrote this code in main.kt. We compile and run the executable at the command line with these instructions:

kotlinc main.kt
kotlin MainKt

I find that Kt suffix on MainKt annoying. When we’re executing something, we don’t really care if the source is Kotlin or Java. Why then the suffix? Though Kotlin allows top-level function definitions, the JVM does not. The Kotlin compiler automatically packages up main inside a bytecode class, and its name is derived from the source file and suffixed with Kt. We can influence the generated name with an annotation:

@file:JvmName("Main")

fun main(args: Array<String>) {
  println("Goodbye, Pluto!")
}

Variables

Variables are declared with a reversed structure compared to Java:

var abbreviation: String = "ChCh"

Let’s try making abbreviation uppercase in a separate statement:

var abbreviation: String = "ChCh"
abbreviation = abbreviation.toUpperCase()

Note the var keyword in our declaration. We have two choices of keywords when declaring variables: var and val. Let’s switch to val and see what happens:

val abbreviation: String = "ChCh"
abbreviation = abbreviation.toUpperCase()

What do you suppose will happen? The code will not compile. The keyword val introduces a variable that can be assigned only once, exactly like Java’s final. As in Java, some folks will mistakenly say that a variable declared with val is an immutable constant, but they are wrong. Kotlin’s val and Java’s final are about the name, not the value. If the value bound to the name is an object, it can itself change. It’s just the name that can’t be bound to anything else after the initial assignment.

Keywords val and var will play a more significant role when we start writing classes.

Types

The standard primitive types are Double, Float, Long, Int, Short, Byte, Char, and Boolean. Though they are capitalized, they are primitives and not objects.

Kotlin (and Java 10) allow you to omit the type in a variable declaration if it can be inferred from the context. In this case, the literal is a clue to the compiler that abbreviation is a String. The shorter version is less redundant:

var abbreviation = "ChCh"

Sometimes redundancy is good.

Type conversions are different in Kotlin. In Java, types form a hierarchy from wide to narrow. double is widest, and byte is narrowest. Widening conversions (or upcasts) are implicit:

int x = 64;
long y = x;

Narrowing conversions (or downcasts) require an explicit cast:

int x = 64;
byte z = (byte) x;

In Kotlin, all conversions must be explicit:

val x : Int = 64
val y : Long = x.toLong()
val z : Byte = x.toByte()

One place where this becomes painfully obvious is when assigning integer literals to Floats, which are prevalent in Android:

val a : Float = 3  // this doesn't compile

We can either invoke toFloat on the literal or, preferably, use the f suffix:

val a : Float = 3f

String Templates

We often want to embed data inside a string to present to the user. Like “You’ve got 1 new messages!” In many languages we use a percent-laden format string and a variable-length parameter list inspired by C’s printf to form such strings. Kotlin takes a different approach, one that we also see in Ruby. We embed arbitrary expressions directly in the string. Like this:

println("You passed ${args.size} command-line arguments.")

Arrays and Lists

To store a sequential collection we can use an array. Let’s create a list of names and have a little raffle:

import kotlin.random.Random

fun main(args: Array<String>) {
  val names = arrayOf("A", "B", "C")
  val winner = names[Random.nextInt(names.size)]
  println("The winner is $winner.")
}

There are several sequential collection structures available, including Array, List, and MutableList. An Array is fixed in size and is mutable. A List is fixed in size and immutable. A MutableList is not fixed in size and is mutable.

That’s enough for today. See you next time!

Sincerely,

P.S. It’s time for a haiku!

What if instead of
Computers getting smaller
Pockets got bigger

P.P.S. Here’s another.

Careful with that thing
It ate my wallet and keys
My camera too

P.P.P.S. Here’s just one more.

Your code doesn’t run?
Try putting it in an app
Then it will have legs

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *