https://github.com/npryce/learn-you-a-kotlin
Exercises for the tutorial "Learn You a Kotlin For All The Good It Will Do You"
https://github.com/npryce/learn-you-a-kotlin
Last synced: about 1 year ago
JSON representation
Exercises for the tutorial "Learn You a Kotlin For All The Good It Will Do You"
- Host: GitHub
- URL: https://github.com/npryce/learn-you-a-kotlin
- Owner: npryce
- Created: 2016-03-06T14:22:23.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2024-03-12T09:18:01.000Z (about 2 years ago)
- Last Synced: 2025-02-22T02:41:19.340Z (over 1 year ago)
- Language: Java
- Homepage:
- Size: 553 KB
- Stars: 16
- Watchers: 5
- Forks: 8
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
Exercise for the tutorial "Refactoring to Kotlin"
=================================================
Aim of the session is to introduce Kotlin by converting Java code.
First create a new branch. Check in after each change. This lets you
easily show how auto-converting code to Kotlin affects how its API
looks when used from Java
Suggested progress
* Part 0: Compiling Kotlin
* Open project in IntelliJ, build on command line, run tests in IntelliJ
* Tools/Kotlin/Configure Kotlin in Project
* Look at the changes to build.gradle
* Build and test
* Tools/Kotlin/Configure Kotlin Plugin Updates - use New Java To Kotlin Converter
* Part 1: Class syntax and data classes
* Presenter
* note that this an immutable value class with a public final field
* convert to Kotlin, accept change other files.
* try to run tests - see compilation failure, talk about converter
* talk about properties v fields, fix JsonFormat.java (Alt-Enter)
* talk through the bits of the Kotlin class - ctor, property, methods
* run tests
* remove equals, hashcode, to string - show tests fail
* make a data class - show tests now pass
* remove the unneeded class body
* check in
* Session
* note that this is an immutable value class with public fields, one of which is nullable, and it defensively copies the presenters
* also that we have 2 constructors - one a convenience vararg
* convert to Kotlin
* Note subtitle is a `String?` - talk about nullability
* Note primary v secondary constructor, observe primary ctor invocation
* Note we can have a free property - presenters, initialised in class body
* Talk about init block, but then remove it
* show tests pass, remove equals etc - show tests fail
* convert to a data class
* can't have a val outside ctor, remove it
* No need to wrap List in unmodifiableList: discuss List/MutableList split, show List defn
* Observe spread operator in constructor, remove it and replace with presenters.toList() - discuss asList()
* Remove empty ctor body
* Convert withXxx methods to single expression - note lack of new
* Convert withXxx methods to invoke .copy (do via add argument names and talk about argument names)
* run the tests, check diffs, talk about diffs, checkin
* SessionTests
* convert to Kotlin
* run tests
* talk about "internal"
* talk about "var" vs "val"
* talk about lack of a "new" keyword -- classes look like, and can be used as, functions
* talk about listOf vs Arrays.asList -- Kotlin stdlib has lots of useful collection methods
* talk about lack of return type when Unit
* Now all of our Session clients are Kotlin we can inline the 'copy's, except for
withPresenters, which we can make vararg
* Now the copy invocations don't need testing
* Move withPresenters methods out of class into extension ... much nicer in Kotlin, yeah?
* Explain extension functions in more detail ... syntactic sugar for static methods
* Move withPresenters into SessionTests where it is used to illustrate convenience extensions
* Talk about top-level functions
* Rename test to `illustrate convenience extension methods` and talk about names
* run the tests, check diffs, talk about diffs, checkin
* Slots
* Convert Slots. It's all Kotlin!!! That was easy!
* run the tests, check diffs, talk about diffs, checkin
* Part 2: Null and nullability
* Look at Sessions - a bunch of static convenience methods to manage a collection
* Look at SessionsTests - already Kotlin
* Talk about companion object, static etc
* `nulls` test
* show TypeCastException when we change the title
* change cast to !! and show KotlinNullPointerException when we change the title
* Show infers second reference cannot be null because of flow typing
* Show the type of notNullSession given as or !!
* Convert Sessions to Kotlin
* Run tests
* subtitleOf
* Compare with Java - talk about ?.
* subtitleOrPrompt
* Compare with Java - talk about ?:
* Move Session static methods to top level scope - talk about static scope
* Make into extension functions
* Note use of extension functions on nullable types
* Remove boilerplate
* Convert subtitleOrPrompt to property (Alt-Enter)
* Talk about properties v functions
* Convert findWithTitle to Kotlin (remove .stream()) - note lambda syntax and destructuring
* Remove the destructuring as unhelpful (even risky -- explain risks)
* Talk about the difference between iterables and sequences
* Use predicate form of firstOfNull
* Run tests
* Talk about API design by adding extension methods to existing types instead of defining new types
* typealias List to Sessions
* run the tests, check diffs, talk about diffs, checkin
* Part 3: modules and functions
* Look at JsonFormatTests
* note that we want to marshall session to and from JSON
* Look at JsonFormat
* we're groping towards a Java DSL for JSON, using Json
* Look at Json
* Try annotating `props` param of `obj` method with `@Nullable` so comments about nullability
are not necessary -- you cannot!
* Note use of Map.Entry - used as a pair. But Kotlin has a pair.
* Import Map.Entry, replace Entry< with Pair<, fix issues,
* Run tests, checkin
* Convert to Kotlin, applying changes to affected code
* You'll get compiler errors - ignore them for now
* Look at the changes. JsonFormat and JsonFormatTests are full of INSTANCE!
* Explain Kotlin objects -- they are singletons!!! :scream-emoji:
* Revert.
* We could annotate all methods in Json with @JvmStatic. Or we could convert the dependent classes first. Let's do the latter.
* JsonFormatTests
* Convert to Kotlin AND RERUN THE TESTS
* They fail, because JUnit needs `approval` to be a field. Annotate with @JvmField
* Also mention the @Throws annotations, and then remove them
* Run and checkin
* JsonFormat
* Convert to Kotlin - IJ doesn't do a very good job in the face of Java lambdas sometimes
* Try the pedagogical object: java.util.function.Function fix
* Fix compilation errors by removing explicit `Function<...>` SAM notation
* Explain `it` variable in lambdas
* Don't convert lambdas to references - do move them outside parameter list
* That collect turns out to be `collect, Any>(Collectors.toList() as Collector>?`
* Run tests
* Remove @Throws: it's not called from Java any more (we'll talk about type safe error handling later if we have time)
* Convert streams code to Kotlin map/flatMap/etc. (Remember that JsonNode is iterable, so has map, etc. defined for it)
* move functions to module scope
* convert to extension methods on domain types and JsonNode
* Test and checkin
* Back to Json
* Convert to Kotlin
* To make it compile:
* Use Kotlin's function type syntax instead of java.util.Function
* remove some explicit type params that are not needed
* use nullable types to indicate that array and iterable *elements* can be null
* move functions to module scope
* remove streams
* use infix to
* observe `object`
* replace props.forEach with filterNotNull().toMap()
* in array use apply to initialise result ...
* ... but then replace it with ArrayNode(nodes, elements.toList())
* Convert functions to extension methods where applicable
* We can get rid of Iterable.array(fn) now
* Convert `prop(name,value)` to `name of value` (infix function)
* Discuss gradual introduction of mini-DSLs, rather than up-front DSL design which often ends up inflexible
* Back to JsonFormat
* convert the JSON as text into multiline strings
* make extension properties from nonBlank functions
* use isNullOrBlank
* use let in Session.toJson
Themes
* pragmatic language
* Java interop
* tooling
* much less classy than Java
* extension functions for fun and profit
There is a lot we still haven't covered
* delegation
* sealed classes
* when expressions
* sequences
* inline functions
* reified types in functions
* coroutines
* error handling
* ...