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 { ... }
์ปจํธ๋ํธ๋ 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