**More basics** # Type inference - We have been declaring the type of every variable at the same time that we define it. It turns out for almost all the time we can omit type declaration. - For example, instead of writing `val n: Int = 3`, we can simply write ```kotlin val n = 3 ``` - The Kotlin compiler has a builtin algorithm called _type inference engine_ that can infer the type of the variable being declared from the type of the expression used to initialize it. - You can still declare the type of a variable explicitly. In that case the compiler checks that the declared type agrees with the type of the initializing expresssion, and gives an error message if they don't. # Arrays - Arrays is an _aggregate type_. An array is made up of pieces of data of the same type called _elements_. The type of elements is called the _base type_. If B is a base type, the type "array of B" is written in Kotlin as `Array`. - For example, we can have `Array`, `Array>`, etc. Thus, array types allow us to construct an infinite number of new types. - If an array has $n$ elements, the elements are indexed using the nonnegative integers from $0$ to $n-1$. - We can access and modify an individual element through its index using the [] notation, e.g., `a[3]` is the element of `a` at index 3. - The (references to) array elements are located at consecutive memory locations. - The reason arrays is an efficient data structure for keeping bunches of things together is because we can get at each individual element quickly by doing arithmetic on its index. # Arrays of primitive types - Arrays of primitive types are efficient running-time-wise and memory-wise. You should try to use it if you care about efficiency. - The names of arrays of primitive types are + `BooleanArray` + `CharArray` + `ByteArray` + `ShortArray` + `IntArray` + `LongArray` + `FloatArray` + `DoubleArray` # Constructing primitive arrays - Kotlin does not provide a way to write array literals. The only way to create a new array is by calling some special function. Here are example declarations of arrays of primitive types: ```kotlin val a1 = IntArray(5) val a2 = intArrayOf(3, 5, 2) ``` The first statement declares the variable `a1` to be an `IntArray`, creates an array of 5 `Int`s, initializes all elements to zero, then makes `a1` point to the beginning of this array. The second statement declares the variable `a2` to be an `IntArray`, creates an array of 3 elements, initializes the 0th element to 3, the 1st element to 5, and the 2nd element to 2, then makes `a2` point to the beginning of this array. - You will learn later that `IntArray(5)` is calling an _array constructor_ while `intArrayOf(3, 5, 2)` is calling a _factory function_. # Constructing primitive arrays, continued - In a similar manner, you have constructors + `BooleanArray(n)` for constructing a `BooleanArray` of size n and initializing all elements to `false` + `ByteArray(n)` for constructing a `ByteArray` of size n and initializing all elements to `0` + `ShortArray(n)` for constructing a `ShortArray` of size n and initializing all elements to `0` + `LongArray(n)` for constructing a `LongArray` of size n and initializing all elements to `0` + `FloatArray(n)` for constructing a `FloatArray` of size n and initializing all elements to `0.0F` + `DoubleArray(n)` for constructing a `DoubleArray` of size n and initializing all elements to `0.0` - You also have factory functions `booleanArrayOf(...)`, `byteArrayOf(...)`, `shortArrayOf(...)`, `longArrayOf(...)`, `floatArrayOf(...)`, and `doubleArrayOf(...)` for creating and initializing arrays of the other primitive types to the values you provide as arguments. # Reading and modifying array elements - Here is an example of performing various operations on arrays. ```kotlin val a = intArrayOf(0, 1, 2, 3, 4) println("originally a = ${a.joinToString()}") for (i in 0 until a.size) a[i] *= a[i] println("after the for loop, a is now = ${a.joinToString()}") val b = a println("originally b = ${b.joinToString()}") b[0] = b[2] - b[1] println("after modifying b[0], b = ${b.joinToString()}") println("and a = ${a.joinToString()}") ``` - Executing the code gives this output ``` originally a = 0, 1, 2, 3, 4 after the for loop, a is now = 0, 1, 4, 9, 16 originally b = 0, 1, 4, 9, 16 after modifying b[0], b = 3, 1, 4, 9, 16 and a = 3, 1, 4, 9, 16 ``` # Arrays is a mutable, reference type - A data object that allows changes to be made to its value is said to be _mutable_. (To _mutate_ means to change.) A data object that does not allow changes to be made to its value is said to be _immutable_. The last piece of code snippet taught us that arrays are mutable. - Except for primitive types, all Kotlin types are _reference types_. The data itself is kept within an _object_, and the variable only keeps a reference to the location of the object. Objects are created during runtime. - When we execute the code snippet ```kotlin val b = a ``` where a, b are variables of the same reference type, the variable `b` is made to point to the same object that `a` is pointing to. Modifying the content that `b` points to will change the content that `a` points to as well since they are the same! - The lesson here is that being a `val` variable does not mean the data itself is immutable. It just means that you can't change that variable to make it reference something else. # Iterating an array - Arrays are iterable, so you can use the `for` loop to walk through them to perform some task on their elements without having to refer to their indexes at all. - For example, you can print all the elements by ```kotlin val a = intArrayOf(1, 2, 3) for (e in a) println(e) ``` - If you also want the indexes, you can write ```kotlin for ((i, e) in a.withIndex()) println("$i: $e") ``` instead of the usual ```kotlin for (i in 0 until a.size) println("$i: ${a[i]}") ``` # Characters and strings - A `String` value is essentially a sequence of `Char` values. - Even though `String` is not a primitive type, it is so heavily used that Kotlin provides literals for it like for the primitive types. It also has the concatenation operator `+` that returns another string that results from appending the second string to the first. - `String` is an immutable type. You can't change its data. - But you can access the individual characters of a string using the indexing operator [], exactly like the arrays. - The String type differs from the array type in that strings don't have a `size` property; it has a `length` property instead. - You can iterate through strings just like arrays. # Strings, continued - Here is some code that manipulates strings. ```kotlin val message = "Hello" println(message + " World") println(message.length) for (c in message) println(c) for (i in 0 until message.length) println(message[i]) for ((i, c) in message.withIndex()) println("$i: ${message[i]}") ``` - Strings can be compared using these operators as well: ```kotlin == != < <= > >= in !in ``` Comparison is done in dictionary order. # Escape sequences - The `Char` data represents 16-bit Unicode characters. The Unicode characters are supposed to represent all the symbols used in all languages in the world, whether the language is alphabet-based or not, and then some. However, some Unicode characters are either not printable or not easy to see when printed; Kotlin provides a special notation called _escape sequences_ for writing these characters. - These are the escape sequences and their meanings: ``` Escape Sequence Represented Character \t Tab \b Backspace \n Newline \r Carriage Return \' Single Quotation Mark \" Double Quotation Mark \\ Backslash \$ Dollar sign ``` - You can also write any Unicode character using the escape sequence syntax like '\\uFF00'. # Raw strings - A regular Kotlin string literal can contain escape sequences. However, literals containing many escaped characters can be hard to read, so Kotlin provides another way to write string literals. - A _raw string_ does not understand escape sequences. Instead of using just one quotation mark `"` to enclose a string, a raw string uses three quotation marks `"""` like this: ```kotlin """Roses are red, Violets are blue, sugar is sweet, And so are you.""" ``` # Raw strings, continued - If you try to print out the raw string in the last slide you'll find it has undesirable blanks at the beginning of the last 3 lines. To eliminate them, Kotlin provides a function `trimMargin()` so we can write the above raw string as ```kotlin """ |Roses are red, |Violets are blue, |sugar is sweet, |And so are you. """.trimMargin() ``` - The default margin prefix is the `|` character but you can provide your own and pass it in as argument to `trimMargin()` like this: ```kotlin """ >Roses are red, >Violets are blue, >sugar is sweet, >And so are you. """.trimMargin(">") ``` # String templates (or string interpolations) - We have used string templates already. The simplest string template starts with the `$` character, followed by a variable name. Instead of variable name, we can also put an arbitrary expression enclosed in braces. - A string template tells Kotlin to construct a new string by replacing the `$` character and the ensuing variable name or brace-enclosed expression with its value (after converting it to a string if necessary). - For example, ```kotlin val name = "John" val age = 20 println("Last year $name was ${age-1} years old.") ``` will print ``` Last year John was 19 years old. ``` # Fine points - The escape sequences can be used both within character literals and regular (non raw) string literals. Escape sequences do not work within raw strings but we can write the newline character directly within it. Therefore, the two string variables `s1` and `s2` below have the same content. ```kotlin val s1 = "One\nTwo\n\Three" val s2 = """One Two Three""" ``` - Both regular string literals and raw strings understand string templates. - To get the dollar sign into regular string literals, we can escape it with a backslash like this "\$100". - However, raw strings don't treat backslash in a special way, so there must be some other way to specify the dollar sign within raw strings. We can do it this way ```kotlin """That item costs ${'$'}20.""" ``` # String functions - There are lots of string functions that you will find helpful in your programming. We list some of them here. ``` indexOf( contains(s: CharSequence): Boolean char: Char, compareTo(other: String, startIndex: Int = 0, ignoreCase: Boolean = false): Int ignoreCase: Boolean = false startsWith(prefix: String): Boolean ): Int endsWith(suffix: String): Boolean isBlank(): Boolean replace( isNotBlank(): Boolean oldChar: Char, isEmpty(): Boolean newChar: Char isNotEmpty(): Boolean ): String last(): Char replace( lastIndexOf( target: CharSequence, char: Char, replacement: CharSequence startIndex: Int = lastIndex, ): String ignoreCase: Boolean = false toLowerCase(): String ): Int toUpperCase(): String repeat(n: Int): String toBoolean(): Boolean reversed(): String toByte(): Byte substring(startIndex: Int): String toShort(): Short substring( toInt(): Int startIndex: Int, toLong(): Long endIndex: Int ... ): String trim(): String ``` # Scanner - A Scanner is a class that allows you to parse many kinds of numeric and string literals in a text stream. It is appropriate when the exact format of input is known beforehand so you can tell it to read in and parse the right kind of literals at the right time. - The source code for the Scanner class is written in the Java programming language. Since Kotlin-JVM is 100% interoperable with Java, you can call any Java library function from Kotlin. Scanner is no exception. - A concept used by the Scanner is that of _whitespace_. This term refers to the characters blank ('  '), tab ('\t'), and newline ('\n'), and some others. Another concept is that of a _cursor_. Every Scanner object is equipped with a cursor. It starts scanning the stream by setting the cursor to the beginning of the stream. - As you tell the scanner to scan the next input token, it will move the cursor past any whitespace character until it encounters the first non-whitespace character. It will then try to read in as much of the input as possible that can be part of a token for the type of input it is parsing. It leaves the cursor at the first character that cannot be part of a valid token for that type of input. # Scanner, continued - Let's look at an example of how to scan the standard input. Suppose our input consists of a sequence of lines that look like this: ``` Albania 2.99 11100 Belgium 10.43 11787 Cuba 11.09 42803 Denmark 5.53 16639 ``` - Each line consists of three whitespace-separated pieces of data: country, population in millions, and area in square miles. Assume for simplicity that the name of a country is one word, population is a number with a decimal point, and area is a whole number. - We can use the scanner to parse the data like this. ```kotlin val scanner = java.util.Scanner(System.`in`) while (scanner.hasNext()) { val country = scanner.next() val population = scanner.nextDouble() val area = scanner.nextInt() // process data for this country here } ``` # Useful Scanner functions - Here is a list of some useful Scanner functions: ```kotlin hasNext() next() hasNextLine() nextLine() hasNextBoolean() nextBoolean() hasNextByte() nextByte() hasNextShort() nextShort() hasNextInt() nextInt() hasNextLong() nextLong() hasNextFloat() nextFloat() hasNextDouble() nextDouble() ``` # Formatted output - Imagine you have a piece of datum of primitive or string type. You may want to output it in various ways to make the output look nice. You can do that using the `String.format` function. - Let's first learn the concept of a _format specifier_. It's a string consisting of one required part and three optional parts ``` "[flags][width][.precision]type" ``` Only type is required. # Formatted output, continued - This table shows most of the possible types and their meanings. type specifier|meaning :-|:- %b|Boolean %c|Char %d|integral type %e|floating point type in scientific notation %f|floating point type in decimal format %g|floating point type in either decimal or scientific notation, depending on value %n|line separator %s|string %x|integer in hex %%|The % symbol itself # Formatted output, continued - This table shows examples of format specifiers and their effect on the output string. type|code|typical literal|sample format strings|converted string values for output :-|:-|:-|:-|:- Int|d|512|"%14d"|"              512" Long|d|512L|"-14d"|"512              " Float|f|1595.1680010754388F|"14.2f"|"        1595.17" Double|f|1595.1680010754388|".7f"|"1595.1680011" Double|e|1595.1680010754388|"14.4e"|"    15952e+03" String|s|"Hello, world"|"14s"|"  Hello, world" String|s|"Hello, world"|"-14s"|"Hello, world  " String|s|"Hello, world"|"-14.5s"|"Hello             " # Formatted output, continued - `format` is a String function. You call it using the . operator on the string whose content is the format specifier, and provide it with as many arguments as specified in the specifier. Examples: ```kotlin "%s %d pounds.".format("The baby weighs", 3) ``` gives the string ``` "The baby weighs 3 pounds." ``` _---San Skulrattanakulchai_