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: I’ll read books about writing 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
Reality: Let’s go back to basics. The Elements of Style , Strunk & White Politics & The English Language , George Orwell
natural language noun a language that has developed naturally in use (as contrasted with an artificial language or computer code).
Natural language depends on context
Natural language is ambiguous “Take a bow.”
“Take a bow.”
“Take a bow.”
“Take a bow.”
“[English] becomes ugly and inaccurate because our thoughts are foolish, but the slovenliness of our language makes it easier for us to have foolish thoughts.” George Orwell
formal language noun a language designed for use in situations in which natural language is unsuitable, as for example in mathematics, logic, or computer programming
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 slipper. The glass slipper is wearable. Understand "shoe" or "heel" or "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 slipper. The glass slipper is wearable. Understand "shoe" or "heel" or "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
Kotlin falls in the middle Takes its source vocabulary from English define terms more narrowly (ex: open, return, if / else ) modify (ex: fun(ction), foreach) some is just added ( -> )
This is not a programming talk If your code compiles, you can communicate with your computer. This talk is about communicating with people.
The official Kotlin style guide Mechanics : Whitespace, capitalization, punctuation, ordering Naming Idiomatic usage : immutability, when, defaults vs overloads, var vs function, scope functions
Naming 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.”
Choosing good 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.”
Choosing good 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
The optional feature In general, if a certain syntactic construction in Kotlin is optional […], you should omit it in your code . Do not leave 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
Infix functions class function or extension function with one parameter a and b “Hello, World" matches “^Hello".toRegex()
Infix: custom “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)
Why not infix everywhere? All custom infix functions have the same precedence (Lisa likes (Food and Wine)) and (Bob likes (Yoga and Hiking))
Why not infix everywhere? 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
Great use: testing infix fun Person.likes(interest: Interest) {…} infix fun Person.dislikes(interest: Interest) {…} assert(lisa likes Food) assert(lisa dislikes Hiking)
The passive voice Active : Bob throws the ball. Passive : The ball was thrown by Bob.
The passive voice King: “You should avoid the passive tense.” Strunk: “Use the active voice.” Orwell: “Never use the passive where you can use the active.”
The passive voice 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.”
The “evasive voice” “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 object Alive: State() class Dead(val cause: Cause): State() class Person(var state: State = Alive)
sealed class State object Alive: 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))
Scope functions 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
Scope functions … in English? “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 out of ice cream.”
“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”
Recommend
More recommend