Skip to content

Latest commit

 

History

History
74 lines (74 loc) · 15.9 KB

kotlin.md

File metadata and controls

74 lines (74 loc) · 15.9 KB
  • Decorators can go inside a method declaration.
  • The name "Kotlin" came from Kotlin Island, not an anagram of anything, such as Kinton.
  • Kotlin was invented by JetBrains, the people who made Android Studio. It is impossible not to get first-class support for it.
  • There is a repl (called kotlinc-jvm), but it's hella slow. Install with instructions.
  • Kotlin has longer compilation times compared to Java, with the exception of incremental builds, which may match Java's compile time. So, while developer efficiency goes up (with less boilerplate code), machine efficiency goes down. A fair tradeoff.
  • f() ?: g() is f() ? f() : g(), except f doesn't get called twice.
  • Apparently, one of Kotlin's big selling points is null safety, where normal variables can never point to a null. But null is still a thing and can be explicitly checked and/or allowed (by adding ? after the variable name declaration). Saying "no more NullPointerException" is not true.
  • In constrast, instead of using ? to make something nullable, you can use !! to make sure something absolutely isn't null, usually when you run java code, which has no null safety. (Yes, it then crashes if something is null.)
  • A data class (the Java equivalent would be a generic class with getters, setters, hashCode(), and toString()?) is built-in, using data class ClassName(*val fields). All it does is contain data.
  • A nullable variable cannot have its methods called unless its null-ness is checked (literally, in your code, write != null).
  • Classes can have multiple constructors, but only one unique primary constructor. The primary one is just the stuff you put inside class ClassName constructor(*args). All other constructors need to reference the primary constructor one way or the other.
  • init blocks are pre-constructor methods. A class can have any number of these, interleved with pretty much anything you like, including statements. And then constructors are called.
  • Kotlin does not have a new keyword.
  • The default base class is Any. All classes implicitly inherit from Any.
  • "Overridable" methods are called "open functions", and must be called that to be overridden (e.g. open fun foo() { ... }). Overridden methods must also call themselves overrides (e.g. override fun foo() { ... }). Like Java, any function that is not open can have final in front of it to ensure it is never overridden.
  • Classes themselves must also be marked as open/override and final with the open class syntax.
  • Properties (i.e. attributes) must also be marked as open/override and final.
  • A file can contain multiple classes. See also: coding conventions.
  • So Kotlin classes ("KClass") are not Java classes. To get the reference to a class, use ClassName::class (a KClass) instead of just ClassName. To get the Java class equivalent, use SomeJavaClass::class.java instead.
  • Method calls can seemingly contain bodies for no reason. See this example: assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
  • A lambda's parameters are declared inside its braces, so onClick({ view -> doSomething() }) is a lambda. If you hate that, you're in luck, because if you don't need any arguments, you can skip view -> and make it look like something sane, i.e. onClick({ doSomething() }).
  • For some reason, instead of stopping there, kotlin enjoys having function arguments outside the parents iff it is the last argument of the function call, so you get onClick() { doSomething() } instead. But wait, there's fucking more. If the function call takes just one thing, and that one thing is a function, then you have to skip the parentheses anyway, resulting in the final form: onClick { doSomething() }.
  • But if you want to pass in a named function? Fuck you, use parens: onClick(doSomething).
  • The with(obj, func) built-in (bearing in mind the last argument is a function, so the lambda stuff above syntactically applies) is the same as what you used to use in VB6: unresolved names are to be found in the object's attributes.
  • Comment styles are the same as the majority of others (//, /* */).
  • Built-in keywords can be hard or soft. You cannot change hard ones, like if/else, class, and fun. You can change soft keywords like file, get, and set.
  • ALL functions with blocks, i.e. not a one-liner, need an explicit return statement if they have a return type.
  • Because you need to declare parameter types now, the type of a lambda is usually () -> Unit, unless they take arguments. That's because Unit maps to a java void by default. () -> Unit means an anoymous function that returns nothing.
  • You can also use () -> Any? for "function type", for functions that can literally return anything.
  • The function that accepts a lambda specifies what types the lambda needs to take. The lambdas themselves do not need to (but can) do that.
  • "In most cases, Kotlin follows the Java coding conventions", where the official Oracle Java convention says "Avoid lines longer than 80 characters ... Examples for use in documentation should have a shorter line length—generally nomore than 70 characters."
  • A one-liner lambda that takes a single argument can be written as something like it % 2 instead of num -> num % 2.
  • Java's "anything of some type" syntax, <?>, might have been replaced by <*>.
  • An array of strings is Array<String>. An array of ints is either IntArray, because it's a modern language and is very consistent, or Array<Int>, which is not proven to work.
  • A google map won't load until you add the key.
  • unlike Java, functions can be top-level. It has however no static methods. The "static method" equivalent would be setting up a companion object. Any method you put in that object (similar syntax to how to put methods in ES6 classes) will be effectively static.
  • Coroutines are not strictly-speaking threads, but in some cases they are implemented as such.
  • The built-in arrayOf(...args) gives you an array of those args. You don't need to specify the types. If you want to have an empty array, guess what? emptyArray()
  • getApplicationContext() becomes applicationContext in Kotlin, even though it is a "global".
  • Double quotes are still strings. Single quotes are still chars.
  • Then when built-in, actually just switch-case, requires you to specify -> in front of each case's code block, i.e. 1 -> { ... }.
  • /* Block comments /* can */ be nested. */
  • Strings can have "substitutions like $this" (where val this = "this").
  • It is possible to suffix something to a class, including seemingly built-in ones like Number, and instantly create a new attribute. klock does it like so: DateTime.now() + 10.seconds (where seconds is an attribute on Number now.)
  • Nested this can be a problem sometimes. JS tackles this by allowing you to assign this to some variable. Kotlin allows you to refer to this with this@OuterClassName. This works at any level.
  • vararg (*args equivalent) can only be used once in a function signature, and everything after the vararg must be named (**kwargs equivalent).
  • The spread operator is still *.
  • Kotlin occasionally uses something called the infix notation. Method calls like a.to(b).as(c) can simply be written as a to b as c... but only if you mark the function as infix, i.e. infix fun to(b: Int), and the function must accept exactly one parameter. Example. tl;dr: for reduce overhead on readability, just don't use infix.
  • String interpolation is done with "this $syntax" or "that ${syntax(its, up, to, you)}".
  • All functions return : Unit (which is void) by default; there is no need to specify it. You can also omit the return type when the compiler can infer it, which is most of the time.
  • Triple-quoted strings are raw strings (not docstrings). Raw strings don't support escaping but support interpolation (wtf?), so if you want a $ sign inside your raw string literal, guess what you'll have to do: """That sucks a${"$$"}"""
  • trimMargin() and trimMargin('|') (optional margin character) lets you trim off each line of the string, and return one where it starts after the margin character.
  • I don't think there is a difference between arrayOf<Int>() and emptyArray<Int>(). Both throw ArrayIndexOutOfBoundsException when you try to access an element. But there is also an IntArray class, and its helper function intArrayOf(). An IntArray(size) is equivalent java's int[size], which (if I may take an educated guess) is a primitive array, storing literal values insteaad of objects, that is faster than the Array<T> or something. A good rule of thumb is to use Array unless a function explicitly asks for an IntArray (or of any other primitive type). You may encounter primitive arrays of type: booleanArrayOf (boolean[]), byteArrayOf (byte[]), charArrayOf (char[]), doubleArrayOf (double[]), floatArrayOf (float[]), intArrayOf (int[]), longArrayOf (long[]), and shortArrayOf (short[]). There is no string[]; a string is a char[].
  • There is no way to print an array like you would print a python list. Use something like array.forEach(::println) to achieve a similar effect, but each item will be on a different line.
  • But you know what you can print in one line? lists, maps, and sets. lists are effectively tuples because they are not mutable.
  • Sets and Lists print out in the same style: [1, 2, 3], with square brackets.
  • Arrays are fixed-length. Lists may change in size later.
  • But wait, what the fuck is a mutableList then? (It's a list that is mutable, yes. But, at the same time, this seems to raise more questions about a java/kotlin developer's long-term mental health.)
  • BUT WAIT. If you think that isn't complicated enough, there is more for you, you mastermind. I present to you: the ArrayList (arrayListOf), a mutable data type that stores values in an array, but can also be resized. Also, fuck you.
  • ::function will reference the function without calling it. So functions aren't exactly first-class in terms of syntax. If you just function, it is not a silent statement; it is Function invocation 'function()' expected.
  • Inline functions (inline fun vs just fun) are like lambdas, except they have a name. Use inline functions for functions that accept another function or block of code, where declaring a function as inline may occasionally speed up the function by not requiring a new function object to be declared within the callee. You should definitely look more into it.
  • A for loop like 1..10 includes 10. To not include 10, use 1 until 10.
  • If a for loop is labelled (e.g. outer@ for(i in 0..10)), a break@outer will break that loop. This is useful for nested loops.
  • Because of the unique way the Kotlin team is funded, to loop from 1 to 5, you write for (i in 1..5), but if you want to loop from 5 to 1, you write for(i in 5 downTo 1).
  • There is no such thing as an open data class. That means all data classes are final, and are not extendable or reusable in any way.
  • var foo: Type by Bar() works through delegating getting and setting that variable to a delegate class. A delegate is a class with getValue() and setValue() defined.