{"id":17195953,"url":"https://github.com/npryce/learn-you-a-kotlin","last_synced_at":"2025-04-13T20:41:58.009Z","repository":{"id":66701976,"uuid":"53258644","full_name":"npryce/learn-you-a-kotlin","owner":"npryce","description":"Exercises for the tutorial \"Learn You a Kotlin For All The Good It Will Do You\"","archived":false,"fork":false,"pushed_at":"2024-03-12T09:18:01.000Z","size":566,"stargazers_count":16,"open_issues_count":0,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-22T02:41:19.340Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/npryce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-06T14:22:23.000Z","updated_at":"2023-06-13T11:49:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"712385d1-b904-4b79-a009-1d1dfcd52c7c","html_url":"https://github.com/npryce/learn-you-a-kotlin","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Flearn-you-a-kotlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Flearn-you-a-kotlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Flearn-you-a-kotlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/npryce%2Flearn-you-a-kotlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/npryce","download_url":"https://codeload.github.com/npryce/learn-you-a-kotlin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240405963,"owners_count":19796272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T01:51:57.637Z","updated_at":"2025-02-24T02:30:57.243Z","avatar_url":"https://github.com/npryce.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Exercise for the tutorial \"Refactoring to Kotlin\"\n=================================================\n\nAim of the session is to introduce Kotlin by converting Java code.\n\nFirst create a new branch. Check in after each change.  This lets you\neasily show how auto-converting code to Kotlin affects how its API\nlooks when used from Java\n\nSuggested progress\n\n* Part 0: Compiling Kotlin\n  * Open project in IntelliJ, build on command line, run tests in IntelliJ\n  * Tools/Kotlin/Configure Kotlin in Project\n  * Look at the changes to build.gradle\n  * Build and test\n  * Tools/Kotlin/Configure Kotlin Plugin Updates - use New Java To Kotlin Converter\n\n* Part 1: Class syntax and data classes\n  * Presenter\n    * note that this an immutable value class with a public final field \n    * convert to Kotlin, accept change other files.\n    * try to run tests - see compilation failure, talk about converter \n    * talk about properties v fields, fix JsonFormat.java (Alt-Enter)\n    * talk through the bits of the Kotlin class - ctor, property, methods\n    * run tests\n    * remove equals, hashcode, to string - show tests fail\n    * make a data class - show tests now pass\n    * remove the unneeded class body\n    * check in\n  * Session\n    * note that this is an immutable value class with public fields, one of which is nullable, and it defensively copies the presenters\n    * also that we have 2 constructors - one a convenience vararg\n    * convert to Kotlin\n    * Note subtitle is a `String?` - talk about nullability\n    * Note primary v secondary constructor, observe primary ctor invocation\n    * Note we can have a free property - presenters, initialised in class body\n    * Talk about init block, but then remove it\n    * show tests pass, remove equals etc - show tests fail\n    * convert to a data class\n    * can't have a val outside ctor, remove it\n    * No need to wrap List in unmodifiableList: discuss List/MutableList split, show List defn\n    * Observe spread operator in constructor, remove it and replace with presenters.toList() - discuss asList()\n    * Remove empty ctor body\n    * Convert withXxx methods to single expression  - note lack of new\n    * Convert withXxx methods to invoke .copy (do via add argument names and talk about argument names)\n    * run the tests, check diffs, talk about diffs, checkin\n  * SessionTests  \n    * convert to Kotlin\n    * run tests\n    * talk about \"internal\"\n    * talk about \"var\" vs \"val\"\n    * talk about lack of a \"new\" keyword -- classes look like, and can be used as, functions\n    * talk about listOf vs Arrays.asList -- Kotlin stdlib has lots of useful collection methods\n    * talk about lack of return type when Unit\n    * Now all of our Session clients are Kotlin we can inline the 'copy's, except for \n      withPresenters, which we can make vararg\n    * Now the copy invocations don't need testing\n    * Move withPresenters methods out of class into extension ... much nicer in Kotlin, yeah?\n    * Explain extension functions in more detail ... syntactic sugar for static methods\n    * Move withPresenters into SessionTests where it is used to illustrate convenience extensions\n    * Talk about top-level functions\n    * Rename test to `illustrate convenience extension methods` and talk about names\n    * run the tests, check diffs, talk about diffs, checkin\n  * Slots  \n    * Convert Slots.  It's all Kotlin!!! That was easy!\n    * run the tests, check diffs, talk about diffs, checkin\n\n* Part 2: Null and nullability\n  * Look at Sessions - a bunch of static convenience methods to manage a collection\n  * Look at SessionsTests - already Kotlin\n  * Talk about companion object, static etc\n  * `nulls` test\n    * show TypeCastException when we change the title\n    * change cast to !! and show KotlinNullPointerException when we change the title\n    * Show infers second reference cannot be null because of flow typing\n    * Show the type of notNullSession given as or !!\n  * Convert Sessions to Kotlin\n  * Run tests\n  * subtitleOf\n    * Compare with Java - talk about ?. \n  * subtitleOrPrompt\n    * Compare with Java - talk about ?:\n  * Move Session static methods to top level scope - talk about static scope\n  * Make into extension functions\n  * Note use of extension functions on nullable types\n  * Remove boilerplate\n  * Convert subtitleOrPrompt to property (Alt-Enter)\n  * Talk about properties v functions\n  * Convert findWithTitle to Kotlin (remove .stream()) - note lambda syntax and destructuring\n  * Remove the destructuring as unhelpful (even risky -- explain risks)\n  * Talk about the difference between iterables and sequences\n  * Use predicate form of firstOfNull\n  * Run tests\n  * Talk about API design by adding extension methods to existing types instead of defining new types \n  * typealias List\u003cSession\u003e to Sessions\n  * run the tests, check diffs, talk about diffs, checkin\n\n* Part 3: modules and functions\n  * Look at JsonFormatTests \n    * note that we want to marshall session to and from JSON\n  * Look at JsonFormat\n    * we're groping towards a Java DSL for JSON, using Json\n  * Look at Json\n    * Try annotating `props` param of `obj` method with `@Nullable` so comments about nullability\n      are not necessary -- you cannot!\n    * Note use of Map.Entry - used as a pair. But Kotlin has a pair.\n    * Import Map.Entry, replace Entry\u003c with Pair\u003c, fix issues, \n    * Run tests, checkin\n    * Convert to Kotlin, applying changes to affected code\n      * You'll get compiler errors - ignore them for now \n      * Look at the changes.  JsonFormat and JsonFormatTests are full of INSTANCE!\n         * Explain Kotlin objects -- they are singletons!!! :scream-emoji: \n         * Revert.\n      * We could annotate all methods in Json with @JvmStatic.  Or we could convert the dependent classes first.  Let's do the latter.\n  * JsonFormatTests\n    * Convert to Kotlin AND RERUN THE TESTS\n    * They fail, because JUnit needs `approval` to be a field.  Annotate with @JvmField\n    * Also mention the @Throws annotations, and then remove them\n    * Run and checkin\n  * JsonFormat\n    * Convert to Kotlin - IJ doesn't do a very good job in the face of Java lambdas sometimes\n    * Try the pedagogical object: java.util.function.Function\u003cPresenter, JsonNode\u003e fix\n    * Fix compilation errors by removing explicit `Function\u003c...\u003e` SAM notation\n    * Explain `it` variable in lambdas\n    * Don't convert lambdas to references - do move them outside parameter list\n    * That collect turns out to be `collect\u003cList\u003cPresenter\u003e, Any\u003e(Collectors.toList\u003cPresenter\u003e() as Collector\u003cin Presenter, Any, List\u003cPresenter\u003e\u003e?`\n    * Run tests\n    * Remove @Throws: it's not called from Java any more (we'll talk about type safe error handling later if we have time)\n    * Convert streams code to Kotlin map/flatMap/etc. (Remember that JsonNode is iterable, so has map, etc. defined for it)\n    * move functions to module scope\n    * convert to extension methods on domain types and JsonNode\n    * Test and checkin\n  * Back to Json\n    * Convert to Kotlin\n    * To make it compile:\n      * Use Kotlin's function type syntax instead of java.util.Function\u003cT,U\u003e\n      * remove some explicit type params that are not needed\n      * use nullable types to indicate that array and iterable *elements* can be null\n    * move functions to module scope\n    * remove streams\n    * use infix to\n    * observe `object`\n    * replace props.forEach with filterNotNull().toMap()\n    * in array use apply to initialise result ...\n    * ... but then replace it with ArrayNode(nodes, elements.toList())\n    * Convert functions to extension methods where applicable\n    * We can get rid of Iterable\u003cT\u003e.array(fn) now\n    * Convert `prop(name,value)` to `name of value` (infix function)\n      * Discuss gradual introduction of mini-DSLs, rather than up-front DSL design which often ends up inflexible\n  * Back to JsonFormat\n    * convert the JSON as text into multiline strings\n    * make extension properties from nonBlank functions\n    * use isNullOrBlank\n    * use let in Session.toJson\n    \nThemes\n\n  * pragmatic language\n  * Java interop\n  * tooling\n  * much less classy than Java\n  * extension functions for fun and profit  \n \nThere is a lot we still haven't covered\n  \n  * delegation\n  * sealed classes\n  * when expressions\n  * sequences \n  * inline functions\n  * reified types in functions\n  * coroutines\n  * error handling\n  * ...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnpryce%2Flearn-you-a-kotlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnpryce%2Flearn-you-a-kotlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnpryce%2Flearn-you-a-kotlin/lists"}