WRITING the NEXT GREAT KOTLIN NOVEL
- r,
Kotlin Beyond the Style Guide
Lisa Wray @lisawrayz
WRITING the NEXT GREAT KOTLIN NOVEL or , Kotlin Beyond the Style - - PowerPoint PPT Presentation
WRITING the NEXT GREAT KOTLIN NOVEL or , Kotlin Beyond the Style Guide Lisa Wray @lisawrayz WRITING the NEXT GREAT KOTLIN NOVEL or , Kotlin Beyond the Style Guide Lisa Wray @lisawrayz My vision: Ill read books about writing On Writing ,
Lisa Wray @lisawrayz
Lisa Wray @lisawrayz
On Writing, Steven King On Writing Well, William Zinsser Bird by Bird, Annie Lamar What I Talk About When I Talk About Running, Haruki Murakami
The Elements of Style, Strunk & White Politics & The English Language, George Orwell
noun a language that has developed naturally in use (as contrasted with an artificial language or computer code).
George Orwell
noun a language designed for use in situations in which natural language is unsuitable, as for example in mathematics, logic,
If it compiles, then it’s clear to the computer.
If it compiles, then it’s clear to the computer. Only clear to the computer
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>—.+++++++..++ +.>>.<-.<.+++.———.--------.>>+.>++.
Brainfuck: “Hello World”
If it compiles, then it’s clear to the computer. Only clear to the computer
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>—.+++++++..++ +.>>.<-.<.+++.———.--------.>>+.>++.
Brainfuck: “Hello World”
Only clear to the author
"^\(*\d{3}\)*( |-)*\d{3}( |-)*\d{4}$”
Regex: ‘Validate’ a phone number in regex
Clear to anyone
Stage is a room. The old lady is a woman in the Stage. Understand "mother" or "stepmother" as the old lady. The old lady is active. […] The Prince is a man in the Stage. […] The prince carries a glass
"toe" or “foot" as the slipper. The description of the slipper is "It is very small for an adult woman's foot."
Inform 7: “Glass”, by Emily Short
Clear to anyone … but is this really better?
Stage is a room. The old lady is a woman in the Stage. Understand "mother" or "stepmother" as the old lady. The old lady is active. […] The Prince is a man in the Stage. […] The prince carries a glass
"toe" or “foot" as the slipper. The description of the slipper is "It is very small for an adult woman's foot."
Inform 7: “Glass”, by Emily Short
Takes its source vocabulary from English define terms more narrowly (ex: open, return, if / else ) modify (ex: fun(ction), foreach) some is just added ( -> )
If your code compiles, you can communicate with your computer. This talk is about communicating with people.
Mechanics: Whitespace, capitalization, punctuation, ordering Naming Idiomatic usage: immutability, when, defaults vs overloads, var vs function, scope functions
An object is a noun “The name of a class is usually a noun or a noun phrase explaining what the class is: List, PersonReader.” A method is a verb “The name of a method is usually a verb or a verb phrase saying what the method does: close, readPersons.”
What are bad names? “The names should make it clear what the purpose of the entity is, so it's best to avoid using meaningless words (Manager, Wrapper, etc.) in names.”
What are bad names? “The names should make it clear what the purpose of the entity is, so it's best to avoid using meaningless words (Manager, Wrapper, etc.) in names.” Translation: #$@&%*! Java
In general, if a certain syntactic construction in Kotlin is
unnecessary syntactic elements in code just "for clarity”.
Kotlin style guide
Orwell: “If it is possible to cut a word out, always cut it out.” Strunk: “Omit needless words.”
Android Studio is less opinionated …
fun function(): Boolean = true fun function() = true
class function or extension function with one parameter
a and b “Hello, World" matches “^Hello".toRegex()
“Lisa likes food.”
enum Interest ( Food, Wine, Hiking, Yoga ) data class Person(val interests: List<Interest>) val lisa = Person(listOf(Food, Wine)) fun Person.likes(interest: Interest) = person.interests.contains(interest) lisa.likes(Food)
“Lisa likes food.”
infix fun Person.likes(interest: Interest) {} lisa likes Food // true lisa likes Hiking // false
infix Interest.and(other: Interest) = listOf(this, other) infix fun Person.likes(interests: List<Interest>) = … lisa likes (Food and Wine)
All custom infix functions have the same precedence
(Lisa likes (Food and Wine)) and (Bob likes (Yoga and Hiking))
All custom infix functions have the same precedence
(Lisa likes (Food and Wine)) and (Bob likes (Yoga and Hiking))
Kotlin does not have verb conjugation Most functions are written in the imperative case.
val trash = TrashBag() if (trash.isFull) Lisa.takeOut(trash) Lisa takeOut trash Lisa takesOut trash
infix fun Person.likes(interest: Interest) {…} infix fun Person.dislikes(interest: Interest) {…} assert(lisa likes Food) assert(lisa dislikes Hiking)
Active: Bob throws the ball. Passive: The ball was thrown by Bob.
King: “You should avoid the passive tense.” Strunk: “Use the active voice.” Orwell: “Never use the passive where you can use the active.”
Can omit the subject Active: I performed the experiment. Passive: The experiment was performed. “I would have done my homework, but my data was deleted.”
“Darth Vader Dies On Death Star”
enum State { Alive, Dead } class Person (var state: State = Alive) val vader = Person() vader.state = Dead
Original: Darth Vader dies on Death Star Passive: Darth Vader killed by Emperor Palpatine Active: Emperor Palpatine kills Darth Vader
Original: Vader dies Passive: Vader killed by Palpatine Active: Palpatine kills Vader
Transitive: Palpatine kills Vader Intransitive: Vader dies Can’t do: Palpatine dies Vader
Bad headline: Vader dies. Good headline: Palpatine kills Vader. (Implied: Vader dies.)
enum State { Alive, Dead } class Person(var state: State = Alive)
sealed class State
class Dead(val cause: Cause): State() class Person(var state: State = Alive)
sealed class State
class Dead(val cause: Cause): State() class Person(var state: State = Alive) sealed class Cause class NaturalDeath(val reason: String): Cause() class Accident(val reason: String): Cause() class Killed(val by: Person): Cause() val PeacefullyDead = Dead(NaturalDeath("old age"))
This is still an exhaustive when.
when (state) { is Alive -> { } // do something else -> { } }
“Vader dies”
vader.state = Dead() No value passed for parameter “cause”
“Palpatine kills Vader”
val palpatine = Person() vader.state = Dead(Killed(by = palpatine))
The conjunctions of Kotlin “A common way to fall into wordiness is to present a single complex idea, step by step, in a series of sentences that might to advantage be combined into one.”
Strunk, The Elements of Style
“I’m going to the store now. The store gets busy after work.” vs: “I’m going to the store because it gets busy after work."
“I’m going to the store. The store is probably busy right now. But I’m out of ice cream." vs: “I’m going to the store, which is probably busy now, but I’m
“I’ll have an ice cream with sprinkles."
return IceCream().apply { add(sprinkles) }
“I’ll have an ice cream, and I need a receipt.”
return IceCream().also { printReceipt(it) }
“I’ll have an ice cream with sprinkles, and I need a receipt.”
return IceCream().apply { add(sprinkles); printReceipt(this) }
“I’ll have an ice cream with sprinkles, and I need a receipt.”
return IceCream().apply { add(sprinkles); printReceipt(this) } return IceCream().apply { add(sprinkles) }.also { printReceipt(it) }
“If they still have ice cream, get me one with sprinkles and a receipt.”
iceCream?.apply { add(sprinkles) }.also { printReceipt(it) }
Receipt for “null” 🍧
“If they still have ice cream, get me one with sprinkles and a receipt.”
iceCream?.apply { add(sprinkles) }?.also { printReceipt(it) }
Only get a receipt if there is still ice cream.
“Avoid a succession of loose sentences. This rule refers especially to sentences of a particular type: those consisting of two clauses, the second introduced by a conjunction … An unskilled writer will sometimes construct a whole paragraph of sentences of this kind.”
Strunk, The Elements of Style
“Avoid a succession of loose sentences. This rule refers especially to sentences of a particular type: those consisting of two clauses, the second introduced by a conjunction … An unskilled writer will sometimes construct a whole paragraph of sentences of this kind.”
Strunk, The Elements of Style
enum class Topping { Sprinkles, HotFudge, Caramel } class IceCream( vararg toppings: Topping, flavor: String, log: (IceCream) -> Unit )) IceCream(Sprinkles, HotFudge, flavor = “Vanilla”) { printReceipt(it) }
enum class Topping { Sprinkles, HotFudge, Caramel } class IceCream( vararg toppings: Topping, flavor: String, log: (IceCream) -> Unit )) IceCream(Sprinkles, HotFudge, flavor = “Vanilla”) { printReceipt(it) }
enum class Topping { Sprinkles, HotFudge, Caramel } class IceCream( vararg toppings: Topping, flavor: String, log: (IceCream) -> Unit ) IceCream(Sprinkles, HotFudge, flavor = “Vanilla”) { printReceipt(it) }
enum class Topping { Sprinkles, HotFudge, Caramel } class IceCream( vararg toppings: Topping, flavor: String, log: (IceCream) -> Unit ) IceCream(Sprinkles, HotFudge, flavor = “Vanilla”) { printReceipt(it) }
iceCream { toppings { sprinkles() } printReceipt() }
iceCream { toppings { sprinkles() } printReceipt() }
iceCream { this: IceCreamBuilder toppings { sprinkles() } printReceipt() }
If you’re writing them — Yes Adds boilerplate and maintenance overhead to your code Don’t use a DSL where named parameters will do Can you pollute your code base with DSLs?
If you’re writing them — Yes Adds boilerplate and maintenance overhead to your code Don’t use a DSL where named parameters will do Can you pollute your code base with DSLs? Not really
If you’re writing them — Yes Adds boilerplate and maintenance overhead to your code Don’t use a DSL where named parameters will do Can you pollute your code base with DSLs? Not really “Custom DSLs” in Kotlin are internal DSLs
Kotlin gives you new choices and paradigms You choose how to use (or abuse) them
Lisa Wray @lisawrayz