- 어떠한 입력에 대해 항상 같은 출력을 만드는 함수를 의미한다.
- 즉, 외부의 영향을 받거나 주지 않는 것,
side-effect
(부수 효과)가 없는 것을 말한다.
- 동일한 입력에 대해 동일한 출력을 가진다.
side-effect
가 없다.- 두 개의 순수한 표현식 사이에 데이터 의존성이 없는 경우,
- 순서를 반대로 하거나 병렬로 수행이 가능하다.
- 서로 간섭을 할 수 없다.
- 그렇기 때문에
thread-safe
하다.
// side-effect (O)
var counter: Int = 0
func increament(num: Int) -> Int {
counter += 1
return counter
}
increament(num:)
함수는 함수 바깥에 있는 전역 프로퍼티counter
값을 변경 시킨다.- 다른 함수가
counter
프로퍼티에 접근할 지도 모른다. - 그렇기에 이러한 로직은 프로퍼티의 값이 바뀜으로써(
mutating the property
) 예상치 못한 부수효과(side-effect
)를 발생시킬 여지가 있으므로 순수함수가 아니다.
// side-effect (O)
func getRamdomNumber(maxNum: Int) -> Int {
return Int.random(in: 0...maxNum)
}
- 함수에 랜덤적 요소가 포함되어있다면 테스트하기 힘들다.
- 순수함수는 나의 코드를 테스트하기 쉽게 한다.
getRandomNumber(maxNum:)
함수는0부터
maxNum` 사이의 숫자를 랜덤하게 리턴해준다.- 위와 같이 랜덤 요소를 리턴하는 함수로 테스트(= 충분한 unit test)를 할 수 있을까?
- 여러
input
을 통해 함수의output
을 테스트해볼 수는 있을 것이다. output
은getRandomNumber(maxNum:)
에 주어진input
에 의존하게 된다.- 그 말은, 여러
input
경우의 수에 따른 테스트를 실행함으로써 테스트가 가능하고, 그 당시 다른 테스트들을 방해하는 테스트는 없을 것이다. - 그래서 순수함수라고 착각할 수 있다.
- 여러
- 이 함수는 함수를 실행할 때마다 같은 결과를 낸다는 보장이 없다.
XCTest
를 통해 테스트를 작성할 수 없듯 이 함수는 테스트가 불가능하다는 뜻이다. (=untestable
)- XCTest 관련 참고 링크 : How to Test Asynchronous Functions Using Expectation in Swift
[ 순수함수의 조건 ]
1. 항상 같은 결과를 리턴한다.
2. 전역으로 선언된 것의 상태를 변경 시키지 않고 그대로 둔다.
// side-effect (X)
func hello(name: String) -> String {
return "안녕! \(name)아!"
}
hello(name:)
함수는 위의 두 조건을 만족하므로 순수함수라고 볼 수 있다.- 1번 조건 만족: 항상 같은
input
에 같은output
을 리턴한다. - 2번 조건 만족: 전역 변수 즉, 전역적으로 선언된 상태값(
global state
)을 변경시키지 않는다.
- 1번 조건 만족: 항상 같은
-
읽기 쉽고,
side-effect
가 없다.- 그러므로 문제가 발생시 그 이유에 대해 쉽게 추론이 가능하다.
- 명확히 정의된 함수의 파라미터를 가지고 있다. 그러므로 도출된
output
은 온전히input
파라미터에 의해 결정된다.
-
함수는 오직
input
파라미터에 의해 결정되므로, 해당 코드는 이식이 가능하다. (=portable
)- 이 말은, 함수는 앱 전체 어느 곳에서든 사용히 가능하다는 뜻이다.
-
테스트 코드 작성에 용이하다.
- 주어진 다양한
input
에 대한 예측가능한 결과를 코드를 통해 유추할 수 있다면, 우리는 테스트할 수 있다. - 여기저기 공유되고 있는 가변상태(
mutable state
)는 모든 경우의 수를 빼놓지 않고 테스트 하기 어렵다. - 이것은
독립적
이고반복 가능한
테스트에 반하는 아이디어이다.
- 주어진 다양한
-
정의상으로 순수함수는 참조 투명성(referential transparency)을 갖는다.
- 이는 프로그램의 결과를 변경하지 않고 표현식을 값으로 대체할 수 있음을 의미한다.
(1) : f(x) = x + 1
(2) : y = f(x) + 1
(3) : y = x + 1 + 1
위의 3 가지 수식이 있다고 할 때, (2)와 (3)은 다른가? 둘은 같다.
식이 원래 가지는 의미가 변하지 않고 대체가 가능하다.
-
메모리의 관점에서는
- 한번 값이 할당된 메모리 위치에는 새로운 값을 다시 할당하지 않는다는 것이 참조 투명성의 필수 조건이다.
- 이 조건이 만족된다면, 어떤 함수를 많이 호출(callback) 하더라도, 항상 동일한 결과를 얻게 된다.
- (프로그램이 사용하는 컴퓨터 메모리의 값은 프로그램이 실행되는 동안에는 절대 변하지 않는다.)
-
구조체, 열거형과 같은 값 타입(value type)은 우리가 상태를 변경하고자할 때 명확히 명시한다.
-
즉, 함수가 상태를 변경하고자 할 때는
mutating
키워드를 꼭 필요로 한다는 뜻이다. -
이 키워드를 통해 참조 투명성을 갖을 수 있다.
- 순수함수들은 작성하기 좋고, 테스트가 가능한 코드에 중요하다는 것을 나타내기 때문에 유용하다.
[ 참조 투명성(referential transparency) ]
- 일반적으로 응용프로그램의 동작에 영향을 미치지 않고 항상 함수를 반환값으로 대체할 수 있음을 의미한다.
- 코드의 재사용성을 보장합니다.
- 데이터가 가변상태인 것을 거부한다. (데이터의 상태 변경 불가)
- 가변이 가능하다면, 동일한 함수의 두 호출은 잠재적으로 두 개의 서로 다른 결과를 만들어낼 가능성이 있고, 텍스트와 유지보수가 어렵다.
- 표현식을 결과값으로 대체했을 때 아무 문제가 발생하지 않는다면, 해당 표현식은 "참조 투명성"을 갖는다고 한다.