===========[ Helpful Kotlin links ]=========== https://fabiomsr.github.io/from-java-to-kotlin/ To lookup what a Kotlin operator or another syntax construct does, https://kotlinlang.org/docs/reference/keyword-reference.html is helpful. ===========[ Small mistakes, forgotten checks, serious bugs ]=========== When handling hostile inputs from the Internet---and any input from the Internet should be assumed potentially hostile---small mistakes can lead to serious bugs that totally destroy application's security. Some believe that "Many eyes make all bugs shallow". This is not the case: OpenSSL, one of the key pieces of the Internet infrastructure, surely had many eyes look at it. Yet the famous Heartbleed bug, found in 2014, existed for many years. It is, in essense, a forgotten check that two length fields in the input data structure agree: https://www.theregister.co.uk/2014/04/09/heartbleed_explained/ Some believe that code developed by large companies rather than open source communities has better security. As the "goto fail" bug in Apple's implementation of SSL (again, of criticial security importance) showed, this is not necessarily the case. Essentially, it came about from cutting-and-pasting an extra "goto fail;" like into a case statement: https://nakedsecurity.sophos.com/2014/02/24/anatomy-of-a-goto-fail-apples-ssl-bug-explained-plus-an-unofficial-patch/ ==================[ Java is not immune ]================== You might think that Java environments are immune from these kinds of bugs. After all, both of these examples are drawn from C/C++. However, this is not the case. The modes of exploiting bugs indeed changes, as the target is now not the C/C++ heap but the somewhat more complex Java heap, and the hostile crafted input must pass through more layers of code. Nevertheless, Java environments had (and probably still have) a series of exploitable bugs related to handling inputs. Such are _deserialization bugs_, for example: https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/ These bugs hit major companies such as PayPal: https://www.paypal-engineering.com/2016/01/21/lessons-learned-from-the-java-deserialization-bug/ ==================[ Static analysis must help ]================== These examples demonstrate that there is no such thing as a "small" mistake that programmers can surely avoid by being careful or by reviewing their code. The lesson here is that the programmers must have help from the language itself in catching bugs at compile time, via static analysis of the code. This means that the language must give them means to better specify what they mean about their data structures, so that the compiler may double-check that _all_ check for the data validity have been made and that no check no matter how small has been forgotten. In other words, programmers must have compiler help for checking that whatever the programmer _believes_ has been checked about potentially hostile data has _actually_ been checked. In order to get this kind of help, following a specific programming style is necessary. Android Studio already does a lot of static analysis---it's necessary for Kotlin's smart casts, for example---but the compiler can only check what is specified. The trick is to write code that makes the programmer's expectations about the incoming data _explicit_. ==================[ Algebraic Data Types ]================== The idea behind Algebraic Data Types (ADTs) is that if the data has structure, i.e., consists of units including many primitive data types such as integers and strings that are expected to work together, this structure must be expressed in type definitions for that data. Any allowed variation in the data structures must also be expressed as types, so that the compiler can check if your code handles all of these variations correctly. You should not leave checks for data variations till runtime, because then a forgotten check will lead to a crash, or worse. For example, if several types of records are allowed, each of these records must have a separate type definition, and the overall type for inputs should be constructed out of these types. Such constructed types that can be "either this or that" are called _union types_, and are a case of ADTs. You already use some kinds of ADTs: Enum types are ADTs, because they specify _all_ allowed values of a constant or a variable. Record types such as structs and objects with multiple fields are also ADTs, because they state that the type is made of several fields of simpler types (and only of these, which must all be present). Tuple types like Pair are also ADTs. Union types are an extension of this idea. In contrast to tuples and records, which can be said to be built from their components via a logical "AND" or conjunction (all fields must be present), union types express the logical "OR" or disjunction: "the type is either this _or_ that". Then the compiler can check if your code handles all the allowed alternatives without forgetting any. Kotlin has a special case of union types: those that allow nulls (e.g., Bundle?, String?, and other *? types). The compiler checks if you handle the "null" alternative correctly, and throws you a type error if you don't. Re-read https://kotlinlang.org/docs/reference/null-safety.html from this perspective. Kotlin also allows you to specify more complex union types, by declaring a base class as "sealed", and inheriting all the types for the specific cases from it. Then the compiler will check that your "where" case statements (Kotlin's version of "switch") handle all the alternatives. This makes the "where" statement the preferred way of programming with union types. It helps avoid such mistakes as Apple's "goto fail". "Where" might seem like just one of the ways to do things, but these compiler checks make it one of the most helpful parts of the language for finding forgotten checks, and you should be making use of it! ==================[ Kotlin ADT examples ]================== In class, we looked at how arithmetic expressions, a fundamental tree-like type, can be expressed as a Kotlin ADT. There are many other tree-like objects that are basic in programming; e.g., XML documents and complex JSON expressions are all trees. The commented in-class example is in examples/ADTs/ See these blog posts for more production-oriented examples: http://engineering.pivotal.io/post/algebraic-data-types-in-kotlin/ https://medium.com/car2godevs/kotlin-adt-74472319962a Resources for the in-class example and the above links: For the meaning of "sealed", see https://kotlinlang.org/docs/reference/sealed-classes.html For the meaning of "data class", see https://kotlinlang.org/docs/reference/data-classes.html For the meaning of "object", see "Object declarations" in https://kotlinlang.org/docs/reference/object-declarations.html For the meaning of "smart casts", see http://kotlinlang.org/docs/reference/typecasts.html#smart-casts You may skip the following NOTEs at a first reading, but continue to Menus and SAM conversions below. NOTE: Sealed classes are new to Kotlin 1.1 (see https://kotlinlang.org/docs/reference/whatsnew11.html, "Sealed and data classes" section), but it's very likely they will develop further, because they express a fundamental idea of modern programming. See also this example for generic trees: https://gist.github.com/evacchi/d6a1c93730b9b843982c https://stackoverflow.com/questions/28695254/kotlin-and-discriminated-unions-sum-types NOTE: you can represent List types as ADTs as well: https://discuss.kotlinlang.org/t/sealed-class-and-algebraic-data-type/2594 (in fact, this is how Haskell, Ocaml, and other modern languages define Lists). NOTE: See [Note on union types is Haskell] below. ==================[ Saving typing: SAM conversions ]================== Kotlin allows you to specify a single function where in Java you would need to create an anonymous Listener object, a Runnable object, or any other interface that has a _single function_ that you must implement to pass a callback to some code that will eventually call it. This is called "SAM conversion": http://kotlinlang.org/docs/reference/java-interop.html#sam-conversions See examples of its use in examples/ManulMeow/ , where it is used to define callbacks for menu item actions (instead of having to write twice as many lines of code, e.g., to define what a SnackBar does when clicked). ==================[ Menus, Actions, and SnackBar ]================== The in-class ManulMeow example shows how to display a menu bar in the app and handle the clicks on its items. You need to call setSupportActionBar(..) in onCreate(..), and also inflate the menu from the XML that defines it. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar); setSupportActionBar(myToolbar); } To inflate a menu defined in XML (which is the best way to lay out a complex View object such a menu), you need to add the onCreateOptionsMenu(..) callback: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); // or wherever your menu is defined return true; } To process clicks on action bar items, you need to add the onOptionsItemSelected(..) callback. @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: //.. } For more, see https://developer.android.com/guide/topics/ui/menus.html and https://developer.android.com/training/appbar/index.html ==================[ Note on union types is Haskell ]================== In Haskell and Ocaml, union types with a null are called "Maybe" types, and are defined with syntax such as Maybe a = a | Null where a is a type parameter (you'd write in Java and Kotlin to denote a type parameter) More general union types are called "Ether" types, and are defined with syntax such as Either a b = a | b e.g., MyMessageOrError = Ether Message Error