项目作者: ruXlab

项目描述 :
Kotlin is pretty, don't abuse it [antipatterns collection]
高级语言: Kotlin
项目地址: git://github.com/ruXlab/absurd-kotlin.git
创建时间: 2018-11-21T21:21:46Z
项目社区:https://github.com/ruXlab/absurd-kotlin

开源协议:

下载


Kotlin ~bad~ weird code collection

Kotlin is very powerful. With great power comes great responsibility.

Please don’t abuse it, we don’t need another scala and perl*

Repeat

Repeat with overloaded operator

  1. 3 * { println("kotlin rocks") }

Output:

  1. kotlin rocks
  2. kotlin rocks
  3. kotlin rocks

Map function on closure

  1. fun main(args: Array<String>) {
  2. println( (3 * { "kotlin #$it"}).joinToString(", "))
  3. println( ({ it: Int -> "wow #$it"} * 3).joinToString(", "))
  4. }

Output:

  1. kotlin #1, kotlin #2, kotlin #3
  2. wow #1, wow #2, wow #3

Abusing kotlin scoping functions

What is this?

Say, we’ve got number of processors for different inputs, mappings are finite and no dynamic.

  1. fun run(arg: String?) = mapOf("a" to ::f1, "b" to ::f2, "c" to ::f3).apply {
  2. arg.let { it?.trim() }
  3. .let { this[it] }
  4. ?.let { println(it()) }
  5. }

How does it feel after quick look on snippet above? It’s very easy to get lost while scanning code

Operator overloading abuse

We have learnt from c++ that operators overloading should be used with a great care.
Misuse might confuse your fellow colleague and even yourself

Invoke on object

Object are meant to be singleton-like object or
used as a place for factory methods.

  1. object Sum {
  2. operator fun invoke(a: Int, b: Int) = a + b
  3. }
  4. fun main(args: Array<String>) {
  5. println(Sum(40, 2))
  6. }

It is possible to use object with overloaded invoke operator as a function, but
why would someone use it instead of higher order functions?

Invoke on self-constructing interface

Why would you use interfaces as a classes, simulating constructor by using invoke?

  1. interface Person {
  2. val firstName: String
  3. val lastName: String
  4. companion object {
  5. operator fun invoke(firstName: String, lastName: String): Person {
  6. return object : Person {
  7. override val firstName: String = firstName
  8. override val lastName: String = lastName
  9. override fun toString(): String = "$firstName $lastName"
  10. }
  11. }
  12. val NONAME = this("NO NAME", "")
  13. }
  14. }
  15. fun main(args: Array<String>) {
  16. println(Person("Alex", "Popov"))
  17. println(Person.NONAME)
  18. }

Output:

  1. Alex Popov
  2. NO NAME

It’s kinda cool to make interface behave as a object or function but what that point?

Extension functions

Extension function instead of member

While code looks almost the same what is the point of breaking classic encapsulation?
Extension function can serve a great deal when it comes to foreign code extension
or to tame your own for clarity

  1. package extentionfunctions
  2. class Mumbler(var counter: Int = 0)
  3. private fun Mumbler.incAndSay(sound: String) {
  4. counter++
  5. println(sound)
  6. }
  7. fun Mumbler.meow() = incAndSay("meow")
  8. fun Mumbler.bark() = incAndSay("wuff")
  9. fun Mumbler.stats() = println("Mumbled $counter times")
  10. fun main(args: Array<String>) {
  11. val mumbler = Mumbler()
  12. mumbler.stats()
  13. mumbler.bark()
  14. mumbler.meow()
  15. mumbler.stats()
  16. }

If there is no good reason to do so - just put those properties and functions
inside the class, as it expected in OOP

..and most importantly

Remember - we write code not for processor but for our colleagues and businesses.
Otherwise we could use asm.


Originally published at ruXlab/absurd-kotlin, inspired by twitter thread

Disclaimer

  • Please use tool which helps to resolve daily needs for your company in a way it works for you
  • Don’t associate yourself with particular language or technology, you’re The Human.
  • * no offence to scala and perl devs, some of us have a hard time reading that code`