Contract

์ฝ”ํ‹€๋ฆฐ์˜ **์ปจํŠธ๋ž™ํŠธ(Contracts)**๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์—ฌ, ์ฝ”๋“œ๋ฅผ ๋” ์•ˆ์ „ํ•˜๊ณ  ์Šค๋งˆํŠธํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์‹คํ—˜์ ์ธ(Experimental) ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ฝ”๋“œ์˜ ํ๋ฆ„์„ ๋” ์ •ํ™•ํ•˜๊ฒŒ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๊ณ , ๋ถˆํ•„์š”ํ•œ ์Šค๋งˆํŠธ ์บ์ŠคํŠธ๋‚˜ ๋„ ์ฒดํฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


1. ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€?

์ฝ”ํ‹€๋ฆฐ์€ ๊ฐ•๋ ฅํ•œ ํƒ€์ž… ์ถ”๋ก ๊ณผ ๋„ ์•ˆ์ •์„ฑ(null safety)์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ๋•Œ๋•Œ๋กœ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ•จ์ˆ˜์˜ ๋ถ€์ž‘์šฉ(side-effects)์ด๋‚˜ ๋™์ž‘ ๋ฐฉ์‹์„ ์™„์ „ํžˆ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠน์ • ํ•จ์ˆ˜๊ฐ€ false๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ ์ธ์ž๊ฐ€ null์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Kotlin

fun isNull(value: String?): Boolean {
    return value == null
}

fun main() {
    val name: String? = "John"
    if (!isNull(name)) {
        // ์ปดํŒŒ์ผ๋Ÿฌ๋Š” isNull ํ•จ์ˆ˜์˜ ๋‚ด๋ถ€๋ฅผ ๋ชจ๋ฅด๋ฏ€๋กœ
        // ์—ฌ์ „ํžˆ name์ด null์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•จ
        // name.length // โŒ ์•ˆ์ „ํ•œ ํ˜ธ์ถœ์ด ์•„๋‹˜
    }
}

์œ„ ์ฝ”๋“œ์—์„œ if (!isNull(name)) ๋ธ”๋ก ๋‚ด๋ถ€์—์„œ name์€ ์—ฌ์ „ํžˆ ๋„ ๊ฐ€๋Šฅ(String?) ํƒ€์ž…์œผ๋กœ ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค. isNull ํ•จ์ˆ˜๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ๋งŒ name์ด null์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.


2. ์ปจํŠธ๋ž™ํŠธ์˜ ํ•ต์‹ฌ: contract { ... }

์ปจํŠธ๋ž™ํŠธ๋Š” contract { ... } ๋ธ”๋ก ๋‚ด์—์„œ kotlin.contracts ํŒจํ‚ค์ง€์˜ ํ•จ์ˆ˜๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์ปจํŠธ๋ž™ํŠธ๋Š” ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’๊ณผ ์ธ์ž ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” **returns**์™€ **returns์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” implies**์ž…๋‹ˆ๋‹ค.

returns์™€ implies

returns๋Š” ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ๋Œ€ํ•œ ์กฐ๊ฑด์„ ๋‚˜ํƒ€๋‚ด๊ณ , implies๋Š” ๊ทธ ์กฐ๊ฑด์ด ์ฐธ์ผ ๋•Œ ํŠน์ • ์ธ์ž์— ์–ด๋–ค ์กฐ๊ฑด์ด ์„ฑ๋ฆฝํ•˜๋Š”์ง€ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

Kotlin

import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.contracts.Returns
import kotlin.contracts.isNotNull

@OptIn(ExperimentalContracts::class)
fun isNull(value: String?): Boolean {
    contract {
        // returns(true)์ผ ๋•Œ, value๋Š” null์ด๋ผ๋Š” ๊ฒƒ์„ ๋ณด์žฅ
        returns(true) implies (value == null)
        // returns(false)์ผ ๋•Œ, value๋Š” null์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ๋ณด์žฅ
        returns(false) implies (value != null)
    }
    return value == null
}

fun main() {
    val name: String? = "John"

    if (!isNull(name)) {
        // ์ด์ œ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” !isNull(name)์ด true์ผ ๋•Œ,
        // name์ด non-null์ž„์„ ๋ณด์žฅ๋ฐ›์œผ๋ฏ€๋กœ ์Šค๋งˆํŠธ ์บ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅ
        println(name.length) // โœ… ์•ˆ์ „ํ•œ ํ˜ธ์ถœ!
    }
}

์œ„ ์ฝ”๋“œ์—์„œ returns(false) implies (value != null) ์ปจํŠธ๋ž™ํŠธ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ "์ด ํ•จ์ˆ˜๊ฐ€ false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด, value๋Š” ๋ฐ˜๋“œ์‹œ null์ด ์•„๋‹˜"์ด๋ผ๋Š” ๋ช…ํ™•ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋•๋ถ„์— if ๋ธ”๋ก ๋‚ด์—์„œ name์ด String ํƒ€์ž…์œผ๋กœ ์Šค๋งˆํŠธ ์บ์ŠคํŠธ๋ฉ๋‹ˆ๋‹ค.


3. ์ปจํŠธ๋ž™ํŠธ์˜ ์ข…๋ฅ˜

์ปจํŠธ๋ž™ํŠธ๋Š” ๋ฐ˜ํ™˜ ๊ฐ’๊ณผ ์ธ์ž ๊ฐ„์˜ ๊ด€๊ณ„ ์™ธ์—๋„ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • CallsInPlace: ๋žŒ๋‹ค ์ธ์ž๊ฐ€ ๋ช‡ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š”์ง€ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, run, with ๊ฐ™์€ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜๋“ค์€ ๋žŒ๋‹ค๊ฐ€ ์ •ํ™•ํžˆ ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ปจํŠธ๋ž™ํŠธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด val ๋ณ€์ˆ˜๋ฅผ run ๋ธ”๋ก ๋‚ด์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์ดˆ๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Kotlin

    val name: String
    run {
        name = "Kotlin"
    } // `run`์€ `CallsInPlace` ์ปจํŠธ๋ž™ํŠธ๋กœ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ name์ด ํ•œ ๋ฒˆ ์ดˆ๊ธฐํ™”๋จ์„ ์•Œ๋ฆผ
  • Effects: ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ค ๋ถ€์ž‘์šฉ์„ ์ผ์œผํ‚ค๋Š”์ง€ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์€ ์ œํ•œ์ ์ด์ง€๋งŒ, ๋ฏธ๋ž˜์—๋Š” ๋” ๋งŽ์€ ๋™์ž‘์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.


  • ์‹คํ—˜์  ๊ธฐ๋Šฅ: ์ปจํŠธ๋ž™ํŠธ๋Š” ํ˜„์žฌ ์‹คํ—˜์ (Experimental) ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. @OptIn(ExperimentalContracts::class) ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒ€์ฆ: ์ปจํŠธ๋ž™ํŠธ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ์ •๋ณด๋ฅผ ์ฃผ๋Š” ๊ฒƒ์ผ ๋ฟ, ๋Ÿฐํƒ€์ž„์— ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์ง€์ผœ์ง€๋Š”์ง€ ๊ฒ€์ฆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ปจํŠธ๋ž™ํŠธ์™€ ์‹ค์ œ ํ•จ์ˆ˜ ๋™์ž‘์ด ๋‹ค๋ฅด๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ปจํŠธ๋ž™ํŠธ๋Š” ์‹ค์ œ ํ•จ์ˆ˜์˜ ๋™์ž‘๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

Last updated