**Kotlin basics** # Types - A _type_ is a _set of values together with its associated operations_. Every piece of Kotlin datum has a type. - Kotlin is a _statically-typed_ language, i.e., the type of a variable is determined at compile time. This is in contrast to _dynamically-typed_ languages like Python and Scheme that determine the type of a piece of datum at run time, i.e., while the program is running. - Kotlin is an object-oriented language in the sense that it gives the user the illusion that every value is an object. - However, values of the following _basic types_ have special implementation, making it take less space and execute faster: _Boolean_, _Char_, _Byte_, _Short_, _Int_, _Long_, _Float_, _Double_. We'll call these the _primitive types_. - _String_ and _Array_ are basic but not primitive types. - There are a lot more types than the basic types; we'll study them later. # Primitive types - The primitive types represent values and operations that exist in most programming languages. - There are four main groups of primitive types: _boolean_, _character_, _integer_, and _floating-point_. - There's only one type in the boolean group, namely `Boolean`. There are only two possible values of this type: _true_ and _false_. - There's only one type in the character group, namely `Char`. A value of this type takes up two bytes of storage and represents a 16-bit Unicode character. - There are four types in the integer group, namely `Byte`, `Short`, `Int`, and `Long`. A Byte value takes up one byte of storage; a Short value takes up two bytes of storage; an Int value takes up four bytes of storage; and a Long value takes up eight bytes of storage. - There are two types in the floating-point group, namely `Float` and `Double`. A Float value takes up four bytes of storage, while a Double value takes up eight bytes of storage. # Primitive VS reference types - Besides the primitive types, Kotlin also has non-primitive types called _reference types_. - A value of reference type is accessed through its _reference_ (a kind of _pointer_) but a value of primitive type can be accessed directly without going through this kind of indirection. - The JVM also has special instructions for performing various operations on values of primitive types. - A value of reference type is an _object_. Associated with every object are _properties_ that a user may inspect and/or modify, and _functions_ that a user can invoke. Therefore, an object takes up space for its properties and functions. - Kotlin primitive types are therefore more efficient than reference types for all the above reasons. # Primitives and their wrapper types - In fact, every Kotlin value of primitive type has a corresponding object version of reference type, called its `wrapper type`! - Some operations (like the arithmetic operations) can operate on the primitive values, while others (like inspecting properties and function invocations) needs an object to operate on. - The Kotlin compiler takes care of switching between values of primitive types and their corresponding wrapper types behind the scene as needed! - As a result, the user can regard all values as objects and does not have to be aware of the existence of primitive types, reference types, the differences between them, or wrapper types. However, as a computer scientist using the language, you should know about these things so you can write efficient code. # Literals, integer literals - A literal is a _source code level representation of data value_. - An integer literal may be written in 3 different bases: two, ten, and sixteen. Here are the different ways to write the number twelve. + in binary (base-two): `0b1100` + in decimal (base-ten): `12` + in hexadecimal (base-sixteen): `0xC` - There are two kinds of type that an integer literal can have, either `Int` or `Long`. Kotlin chooses the smallest type that can contain the value. It is an error if the intended integer value of what you write is too large to fit in a `Long`. Examples: ```kotlin >>> 12345678232323291110 error: the value is out of range 12345678232323291110 ^ >>> 1234567890 res1: kotlin.Int = 1234567890 >>> 1234567823232329111 res2: kotlin.Long = 1234567823232329111 ``` - An `Int` literal can be assigned to a `Byte` or `Short` variable without getting a compile-time error if the value is within range. Examples: ```kotlin >>> val a: Byte = 256 error: the integer literal does not conform to the expected type Byte val a: Byte = 256 ^ >>> val a: Byte = -128 >>> a res1: kotlin.Byte = -128 ``` - An integer literal can be forced to have the type `Long` by appending the suffix `L`, e.g., `-1L` has a `Long` type. ```kotlin >>> val a = -1L >>> a res0: kotlin.Long = -1 ``` # Floating-point literals - A floating-point literal can be written in 2 different ways + like how we write real numbers in mathematics: `3.134` + in scientific notation: `2.1e10`, `3e-7` - The type of all floating-point literals is `Double` by default. - To get a `Float` literal, add a suffix 'f' or 'F'. E.g. `3.14F` has a `Float` type. - One cannot write an overflowing floating-point literal because any floating-point literal that overflows becomes `Infinity` or `-Infinity`. Also, floating-point numbers cannot be represented precisely. Examples: ```kotlin >>> 1.2e1111 res0: kotlin.Double = Infinity >>> -1.2e1111 res1: kotlin.Double = -Infinity >>> 1.2e-1111 res2: kotlin.Double = 0.0 ``` # Char literals - A character literal is written by quoting its content in a pair of single quotation mark. - Most printable characters can be written directly inside the quotes. Examples are 'a', '%', and '  '. - Some printable characters cannot be written directly because they have special meaning. For example, the backslash character is used to create what's called an _escape sequence_ (to be described momentarily), so you have to write it as '\\'. Similarly, the single quotation mark is used to delimit character literals, so needs to be escaped as well; it is written as '\\'' - Some characters are not printable, but we can still write a literal for such a character using an _escape sequence_. - An escape sequence starts with the backslash character, followed by one of + a single character (b, t, n, r, ", ', `$`, or \) + an octal number between 000 and 377 + a `u` followed by four hex digits specifying a unicode character. - Example escape sequences: Escape Sequence|Unicode|Meaning :-|:-:|:- '\b'|'\u0008'|backspace '\t'|'\u0009'|horizontal tab '\n'|'\u000a'|linefeed '\r'|'\u000d'|carriage return '\"'|'\u0022'|double quotation mark '\''|'\u0027'|single quotation mark '\$'|'\u0024'|dollar sign '\\'|'\u005c'|backslash # String literals - A string literal is any sequence of characters enclosed in a pair of double quotation marks. - Example string literals are + `"Hello"` + `"Good Bye!"` + `"123456"` + `"true"` + `"false"` + `"Int"` + `"print()"` - We will explore string literals in detail later. # Operators - The are several groups of operators, taking operand(s) of different types. Here is a selection of some operators: + arithmetic:   $+$   $-$   `*`   `/`   `%` + logical:   `&&`   `||`   ! + comparison:   `<`   `<=`   `>=`   `>` + equality:   `==`   `!=` + bit-wise:   `shl`   `shr`   `ushr`   `and`   `or`   `xor`   `inv` + increment & decrement:   `++`   `--` + assignment:   `=`   `+=`   `-=`   `*=`   `/=`   `%=` + miscellaneous:   $+$   $-$   .   `[]`   `()`   `in`   `!in`   `is`   `!is` - Some operators are _overloaded_. Therefore, it's important to know what each operator means in all possible contexts. Examples of overloaded operators are $+$   $-$   `*`   `/`   `%`. # Operator precedence - An expression like `2+3*4` is actually ambiguous, i.e., it has more than one possible interpretation, and thus meaning. In one interpretation the `+` is done before `*`; In the other interpretation the `+` is done after `*`. - The term _operator precedence_ denotes the degree of tightness of binding of operators to operand(s). Each operator has a _precedence level_. In an ambiguous expression, operator precedence is used to determine which operation to perform first. - For example, `*`, `/`, and `%` are at the same precedence level, while $+$ and $-$ are at another level. The `*`, `/`, and `%` are called the _multiplicative operators_, while $+$ and $-$ are called the _additive operators_. However, the precedence level of the multiplicative operators is higher than that of the additive operators. - Therefore, in the expression `2+3*4`, multiplication is performed before addition since the `*` operator has higher precedence than $+$. # Operator associativity - When an expression involves at least two operators of the same precedence level applied successively, Kotlin uses _associativity_ of operators to determine whether to associate the middle operand with the left operator (_left-associative_) or the right operator (_right-associative_). - For example, the expression `1-3-4` will be parsed by the Kotlin compiler as if we had written `(1-3)-4` due to the fact that the minus operator is left-associative. - Most operators in Kotlin are left-associative. Examples of right-associative operators are the unaryPlus + and unaryMinus $-$ operators. - **Notes.** + We can use parentheses to overide the precedence and associativity rules if desired. + When in doubt, parenthesize the expression to make your intention clear. # Basic types Type|Size in Bits|Sample Operators|Literals :-|:-:|:-|:- Boolean|unspecified| &&   `||`   !|true   false| Byte|8|+   $-$   *   /   %|| Char|16|+ |'a'   '0'   '\\'| Short|16|+   $-$   *   /   %|| Int|32| +   $-$   *   /   %|`321`   `0x3A`   `0b11`| Long|64|+   $-$   *   /   %|3L| Float|32|+   $-$   *   /   %|2F   14.2e23f| Double|64|+   $-$   *   /   %|3.21   14.2e23| String||+|`"Hello"`| Array||`[]`|| # String type - Strings have these features of basic types. + We can write a string value using literals, e.g., `"Hello"` + Strings can be _concatenated_ with the operator $+$, e.g., * `"This is an example" + " string"` ⇒ `"This is an example string"` * `"The value is " + 13` ⇒ `"The value is 13"` - We will study strings in more detail later. # Keywords - _Keywords_ are the reserved words of Kotlin. Their meanings are pre-defined and fixed. You cannot use a keyword to mean something else, unless you quote them in backticks, like this: \`in\`. - Here is a list of the hard keywords ```kotlin as as? break class continue do else false for fun if in !in interface is !is null object package return super this throw true try typealias val var when while ``` - There are other kinds of keywords. We may encounter some of them later. # Identifiers - Kotlin is a case-sensitive language; it distinguishes the uppercase from the lowercase letters. - _identifiers_ are programmer-invented names to denote program constructs like _variables_, _classes_, _interfaces_, _functions_, etc. - Syntactically, an _identifier_ is a sequence of letters, digits, or the underscore character such that its first character is not a digit. An identifier cannot be a keyword. - Convention for writing an identifier: + the camel hump style is recommended, e.g., `ticketNumber` + a variable name starts with a lowercase letter + a class name starts with an uppercase letter, e.g., `BigInteger` + constants & enumerated literals are in all caps, e.g., `MAX_LINE_LENGTH` # Variables and assignment - A _variable_ is a name associated with a memory location whose value is changeable via an assignment statement. - A variable has many attributes, e.g., _memory location_, _name_, _type_, _value_, _scope_, _life time_. - An assignment statement starts with the name of the variable, followed by the `=` symbol, followed by an expression. E.g. ```kotlin a = 2 * b + 6 ``` - The simplest case is when the variable on the left-hand-side (LHS) has primitive type. Then the assignment statement means to evaluate the expression on the right-hand-side (RHS) of `=`, then put its value in memory location of the variable on the LHS. Thus, the variable name appearing on the LHS denotes memory location while any variable name appearing on the RHS denotes value. - We'll explain what assignments mean when the LHS is a reference type when we study objects. - There are two kinds of variables, the _readonly_ kind, and the _read-write_ kind. - A better name for readonly variables is "assign-once" variables. A better name for read-write variables is "assignable-multiple-times" variables. - Both kinds must be declared before use. - You should preferentially use the _readonly_ kind of variables whenever possible. Use the _read-write_ kind only when necessary. # Readonly variables - The readonly variables are declared using the keyword `val`. - They must be initialized with some value (using the assignment syntax) exactly once in a program. - After initialization, the value of a readonly variable is fixed. You are not allowed to assign a value to it again. - Example declaration and usage: ```kotlin val c: Char = 'A' val digit: Char = '9' val greeting: String = "Hi" val person: String = "Alice" println(greeting + " " + person) ``` # Read-write variables - A read-write variable is declared with the keyword `var`. - It can be assigned values many times during the execution of a program. - Example declaration, usage, and reassignment: ```kotlin var n: Int = 1 var f: Float = 0F var d: Double = 2.1 n = 2 f = f * 3.1F d = 3e-2 var greet : String = "Hello!" greet = "Hi" ``` - Notice that you can reassign a different value to a `var` variable. However, these reassigned values still need to be of the same type as when the variable was declared. You are not allowed to change the type of a variable!. # Expressions - The simplest kind of expressions consists of literals, variables, and function calls joined together by operators. ```kotlin b * 2 / 3 + kotlin.math.sin(4.0) ``` - Every expression has a type and a value. - There are other kinds of expressions. We'll come to them soon. # Type conversion - In an arithmetic expression involving mixed types of numeric operands, Kotlin has overloaded the operators so it seems as if to convert the values in the following direction to make both operands have the same type as the "biggest" type. ``` Byte → Short → Int → Long → Float → Double ``` - Examples: ```kotlin 3 + 4.2 // value: 7.2, type: Double 1 + 7L - 2 // value: 6L, type: Long ``` - The user can also explicitly requests the compiler to convert a value of one type into another type. E.g. ```kotlin val a: Int = 2 val b: Byte = (a + 3).toByte() val s: Short = 4.toShort() ``` # Function calls - These type conversion functions are associated with objects. You call them using the . operator. + `toBoolean()` + `toChar()` + `toByte()` + `toShort()` + `toInt()` + `toLong()` + `toFloat()` + `toDouble()` + `toString()` - Example usage: ```kotlin "TrUe".toBoolean() ⇒ true 66.toChar() ⇒ 'B' 25.toByte() ⇒ a Byte type with value of twenty-five 265.toByte() ⇒ a Byte type with value of nine ``` # Input/Output functions - These are the output functions you can use. All of them output their argument to the standard output. + `print()` --- outputs its argument. + `println()` --- outputs its argument and a newline, and flushes the output buffer. - Both the `print()` and `println()` functions take exactly one argument. Their argument can be of any type, and it is automatically converted to the String type (if necessary) before being output. # The 'kotlin.math' package - There is a kotlin package that provides many useful mathematical functions and constants. Here is a partial selection of what's available. + `abs` --- for Double, Float, Int, and Long + `min`, `max` --- for Double, Float, Int, and Long + `floor`, `ceil`, `round`, `truncate` --- for Double and Float + `sin`, `cos`, `tan` --- for Double and Float + `exp`, `ln`, `log10`, `log2`, `log` --- for Double and Float + `pow` --- for Double and Float + `sqrt` --- for Double and Float + `roundToInt`, `roundToLong` --- for Double and Float + `E` --- the famous $e$ (the base of natural logarithm) + `PI` --- $\pi$ (the circle constant: circumference $\div$ diameter) - See [https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/index.html](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/index.html) for all possibilities. # Processing command line arguments - When a java class starts running, it also receives command line arguments as an array of strings. For example, when you type ```bash $ java MyClass zero ein deux ``` `MyClass` gets its zeroth argument `args[0]` as the string `"zero"`, its first argument `args[1]` as the string `"ein"`, and its second argument `args[2]` as the string `"deux"`. - By checking these command line arguments, your program can make sure the user provides reasonable arguments before starting to execute. If any provided argument is not reasonable, the program can print an error/help message and abort. - To abort a program, you call the `exitProcess()` function. This function takes an integer argument and returns that value to denote the success or failure result of running the program. - The `exitProcess()` function belongs to the `kotlin.system` package, which is not automatically loaded in by default. Therefore, you should include the line ```kotlin import kotlin.system.exitProcess ``` at the top of your source file that makes any call(s) to `exitProcess()`. - Another way to do error checking is to use the `try {...} catch {...}` statement. This involves _exception_, a concept we'll study later. # Generating random numbers - An essential routine heavily used in computer simulation is random number generation. - The sequence of numbers generated by a computer as random numbers are in fact predictable. However, they have properties common with random numbers and are usually good enough for use. The name we use for these numbers is _pseudo-random numbers_. - Kotlin provides pseudo-random number generators in the `kotlin.random` package. To use this package, you include the line ```kotlin import kotlin.random.* ``` at the top of your source file. - You call a function to generate a random number through the `Random` object. These functions include `nextBoolean()`, `nextInt()`, `nextLong()`, `nextFloat()`, `nextDouble()`. # Example program ```kotlin /* * This program demonstrates how to process command line arguments, and shows * how to call some random number generating functions. * See * * https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.random/-random/index.html * * for all possibilities. */ import kotlin.system.exitProcess import kotlin.random.* fun main(args: Array< String >) { val lo: Int val hi: Int if (args.size != 2) { println("Please give me exactly two nonnegative integers as arguments.") exitProcess(1) } try { lo = args[0].toInt() } catch (e: NumberFormatException) { println("'${args[0]}' is not an integer.") exitProcess(2) } try { hi = args[1].toInt() } catch (e: NumberFormatException) { println("'${args[1]}' is not an integer.") exitProcess(2) } if (lo < 0 || lo > hi) { println("Please give me 2 nonnegative integers lo and hi, with lo <= hi.") exitProcess(3) } // a pseudo-random integer var k = Random.nextInt() println("Your random integer is: $k") // a pseudo-random integer between 0 and hi-1 k = Random.nextInt(hi) println("Your random integer between 0 and ${hi-1} inclusive is: $k") // a pseudo-random integer between lo and hi k = Random.nextInt(lo..hi) println("Your random integer between $lo and $hi inclusive is: $k") // a pseudo-random real between 0.0 and 1.0 val r = Random.nextDouble() println("Your random real number in [0, 1) is: $r") } ``` # Running the above program - First, copy the kotlin source code above and save in in the file `Random.kt` under your `mcs178` directory. - Now, type at the terminal prompt ```bash kotlinc Random.kt ``` This will create a class file called `RandomKt.class` in your `mcs178` directory. - Now, you can type ```bash kotlin Randomkt ``` to see the output from the program. _---San Skulrattanakulchai_