덕 타이핑과 구조적 타이핑 두 가지는 비슷하면서, 근본적으로 다르다.
흔히 아는 것처럼, 덕 타이핑은 자바스크립트 등의 언어에서 쉽게 찾아볼 수 있었던 개념이었을 것이다. 하지만 구조적 타이핑은 흔히 접해보지 않은 이야기일 수 있다. 물론 C/C++ 등의 언어에서도 구조적 타이핑을 가능하도록 Template과 같은 친구들을 제공하지만. 이는 다른 이야기고 언어적인 차원에서 구조적 타이핑을 중점적으로 다루는 언어는 많지 않다. (OCaml, TypeScript, Go 등.)
그렇다면 덕 타이핑은 무엇이고, 구조적 타이핑은 무엇일까?
(위의 사진으로 설명 끝)
덕 타이핑은 객체의 변수, 메소드의 집합이 객체의 타입을 결정하는 것을 말한다. 즉, 위의 사진처럼 콘센트나 돼지코냐 "이름"은 중요하지 않다. 꽃을 수 있는가 없는가 꽃을 수 있으면 그것은 콘센트라고 부를 수 있다.
아래의 자바스크립트 코드를 보면, 아래와 같다 (이하 예제는 자바스크립트와 타입스크립트를 기준으로 설명한다)
class Duck {
quack() {
console.log('꽥!')
}
feathers() {
console.log('깃털은 검정색과 흰색')
}
}
class Human {
quack() {
console.log('사람인데요? 꽥!')
}
feathers() {
console.log('사람이라 깃털은 없어요. 하지만 털은 있습니다.')
}
}
function inTheForest(duck) {
duck.quack()
duck.feathers()
}
inTheForest(new Duck())
inTheForest(new Human())
inTheForest
함수는 duck(오리)을 parameter로 받는다. 오리의 울음소리와 날개를 가지면 숲속의 오리라고 생각하는 함수이다. 그래서 숲속의 오리는 quack()으로 소리를 내고, feathers()로 깃털을 보인다. 그렇기 때문에 duck이라고 생각할 수 있다. 하지만 위의 예제를 보면, Human과 Duck 두 클래스의 메소드로 quack과 feather를 선언했고 두 클래스의 인스턴스를 만들어 inTheForest에 넣어주었다. 동일하게 두 객체는 각각 해당하는 콘솔 로그를 실행한다.
여기서 주의깊게 봐야할 부분은 두 군데이다. 하나는 duck이라고 하는 인자를 받는 inTheForest 함수선언부이고, 하나는 inTheForest에 Duck과 Human의 인스턴스를 넣어 실행하는 함수실행부이다.
자바스크립트 코드를 보면, 기존의 정적 타이핑 언어(Java, C#)등과 다르게 함수선언부에 러프하게 파라미터를 넣는 것을 볼 수 있다. 흔한 애노테이션이나 심지어 타입도 없다. 이는 자바스크립트의 특성으로. 자바스크립트는 초기에 비개발자들의 접근을 쉽게 만들기 위해서 동적 타이핑 언어로써 설계되었다. 그렇기 때문에 지금 당장 코드를 짤 때 파라미터가 어떤 값을 들고 있는지는 상관없다. quack()이든 feathers()든 당장 있는지 검사를 하지 않지만 런타임에서 판별하면 되기 때문이다.
inTheForest의 함수실행부를 보면, Duck과 Human 다른 이름의 두 클래스 객체가 들어가는 걸 볼 수 있다. 두 클래스 객체뿐만 아니라 대충 함수, 변수, quack과 feathers가 없는 클래스까지 아무거나 다 들어간다. 다만, 내부에서의 실행조건이 quack, feathers가 없으니 런타임상에서 에러가 날 뿐이다.
함수선언부와 함수실행부를 통해 우리는 두 가지 사실을 알 수 있다.
이렇게 설계하므로써 얻는 이득은 두 가지가 있다.
여기서 집중해야 할 부분은 두 번째 영역이다. 하나의 함수로 여러 객체(개체) 단위의 행동을 유연하게 작성할 수 있다는 것은 타 강력한 타이핑 언어의 경우에는 동일하게 사용하기 위해 Generic 이라던지, 상속(다형성)을 위해서든 어떠한 테크닉을 배워야한다. 하지만 자바스크립트나 파이썬은? 그런거 없다. 그냥 구현해서 사용하면 될 뿐이다.
그렇다면 이러한 구현 방식이 가진 장점은 알게 되었는데, 왜 덕 타이핑이라고 불리는가?
덕 테스트 (Duck Test)
라는 용어가 있다.덕 테스트 (Duck Test)
란?
구조적 타이핑은 구조적 타입 시스템(Structural Type System) 이라고도 불린다. 실제 구조와 정의에 의해 결정되는 타입 시스템의 한 종류이다. 명시적 선언이나 이름을 기반으로 하는 명목적 타입 시스템(Nominal Type System) 인 Java, C#등과 다르고, 런타임에 타입을 체크하는 덕 타이핑과 다르다.
interface Vector2D {
x: number
y: number
}
interface NamedVector {
name: string
x: number
y: number
}
function calculateLength(v: Vector2D) {
return Math.sqrt(v.x * v.x + v.y * v.y)
}
const v: NamedVector = { x: 3, y: 4, name: 'mgh' }
calculateLength(v)
위 예제는 명목적 타입 시스템을 기준으로 Vector2D를 사용하도록 의도한 코드일 것이다. 하지만 구조적 타이핑 언어에서는 전혀 다른 개념으로 이해해야 한다. Vector2D의 속성에 해당하는 값이 값을 넣는 타입에 속성으로 존재하는가가 로 이해해야 한다. 이 개념은 집합과 관계가 있는데, 구조적 타이핑은 명목적 타이핑과 같은 명확한 상속 관계(A - B)를 지향하기보다 집합으로 포함한다는 개념을 지향하기 때문이다.
Cook, W.R.; Hill, W.L.; Canning, P.S. (January 1990). "Inheritance is not subtyping". Proceedings of the Seventeenth Annual ACM Symposium on Principles of Programming Languages. San Francisco, California: 125–135. doi:10.1145/96709.96721. ISBN 978-0897913430. 상속은 서브타이핑이 아니다를 증명한 논문도 있다. 즉 둘은 서로 다르고 집합관계와 구분된다.
집한 단위로 체크하기 때문에 중복되는 속성 혹은 중복되는 메서드를 획기적으로 줄일 수 있는 큰 장점이 존재한다. 그렇다면 이러한 구조적 타이핑의 역사를 살펴보면 아래와 같다.
그래서, 두 개를 알아보았는데, 덕 타이핑과 구조적 타이핑의 차이는 무엇인가?