419
스칼라의 객체지향 프로그래밍 구현에 대해 많은 것을 배웠다. 장에서는 표준 라이브러리의
타입 계층구조에 대해 자세히 다루고,
Predef
(
http
://
bit
.
ly
/
1086O2z
) 등의 타입을 깊이 살펴
것이다.
하지만 우선 타입시스템에서 중요한 상속에 따른 변성
variance
이라는 특징을 논의하자. 이에 대해
알아야 뒷부분에서 다룰 라이브러리에 있는 여러 가지 타입을 이해할 있다.
객체의 동등성에 대해 논의하면서 장을 마칠 것이다.
10.1
매개변수화한 타입: 상속에 따른 변성
자바와 스칼라의 매개변수화한 타입(자바에서는 이를 보통 제네릭스라고 부른다 )중요한
이점은 상속에 따른 변성다루느냐에 있다.
예를 들어 어떤 메서드가
List
[
AnyRef
]
타입의 인자를 취한다고 가정하자. 그렇다면 이 메서드
List
[
String
]
값을 넘길 수 있을까? 즉,
List
[
String
]
List
[
AnyRef
]
서브타입으로
주해야 할까? 그에 대한 답이 참인 종류의 변성을 공변성
covariant
이라고 한다. 컨테이너(매개변
수화한 타입)슈퍼타입
-
서브타입 관계가 타입 매개변수 사이의 관계와 ‘동일한 방향으로
’하기 때문이다.
스칼라 객체 시스템
I
CHAPTER
10
420
2
기본기 다지기
또한 반공변성
contravariant
타입도 있다. 그런 경우 임의의 타입
X
대해
X
[
String
]
X
[
Any
]
슈퍼타입이다.
매개변수화한 타입이 공변성도 아니고 반공변성도 아닌 경우, 무공변성
invariant
이라고 한다. 일
매개변수화한 타입은 이상의 변성을 포함할 수도 있다.
자바와 스칼라는 모두 공변성, 반공변성, 무공변성 타입을 지원할 있다. 하지만 스칼라에서
변성 표기
variance
annotation
불리는 기호를 타입 매개변수에 추가하는 방식을 통해 변성에
한 선언을 타입 선언에 포함시킨다. 이때 공변성 타입 매개변수의 경우
+
를 사용하고, 반공변
성 타입 매개변수의 경우
-
를 사용한다. 무공변성인 타입 매개변수에 대해서는 아무런 표기도
사용하지 않는다. 다른 말로 하면, 매개변수화한 타입을 설계한 사람이 해당 타입에 대한 상속
이루어질 상속 관계가 어떻게 변할지 결정한다.
다음은 가지 선언 예다 (실제 타입에 대한 예는 잠시 후에 보여줄 것이다 ).
class W
[+
A
]
{...}
//
공변성
class X
[
-
A
]
{...}
//
반공변성
class Y
[
A
]
{...}
//
무공변성
class Z
[
-
A
,
B
,+
C
]
{...}
//
혼합
반면 자바의 매개변수화한 타입 정의에는 상속 하의 변성에 대한 정의가 들어 있지 않다. 대신
매개변수화한 타입의 변성은 예를 들어 호출 지점이나 변수가 선언될 때와 같이 해당 타입을
용할 지정된다.
스칼라와 자바의 가지 변성 표기와 의미를 [표
10
-
1
]에 정리했다.
T
sup
T
슈퍼타입이고,
T
sub
T
서브타입이다.
10-1
타입변성표기와그의미
스칼라 자바 설명
+
T
?
extends
T
공변성( 예를들면
List
[
T
sub
]
는
List
[
T
]
의서브타입)
-
T
?
super
T
반공변성( 예를들면
X
[
T
sup
]
는
X
[
T
]
의서브타입)
T T
무공변성( 예를들면
Y
[
T
sup
]
나
Y
[
T
sub
]
가
Y
[
T
]
를대치할수없음)
421
10
스칼라 객체 시스템 I
List
로 돌아가 보면, 리스트는 실제로는
List
[+
A
]
다. 이는
List
[
String
]
List
[
AnyRef
]
서브클래스라는 뜻이다. 따라서 리스트는 타입 매개변수
A
대해 공변성이다.
List
같이
변성 타입 매개변수가 하나만 있는 경우에는 때로
List
는 공변적이다
Lists
are
covariant
라고 짧게
말하는 것을 들을 있다. 이는 반공변인 경우에도 마찬가지다.
공변성이나 무공변성 타입은 이해하기 쉽다. 반공변성 타입은 어떨까?
10.1.1
함수 내부 들여다보기
반공변성의 가장 좋은 예는
scala
.
Function2
(
http
://
bit
.
ly
/
10Ft2tC
)같은
FunctionN
레이트다. 여기서
N
0
이상
22
이하로, 함수가 취하는 인자의 개수를 나타낸다. 스칼라는 이런
트레이트를 사용해서 익명 함수를 구현한다.
책에서는 계속 익명 함수, 함수 리터럴을 사용했다. 예를 들면 다음과 같다.
List
(
1
,
2
,
3
,
4
)
map
(
i
=
>
i
+
3
)
//
결과
:
List
(
4
,
5
,
6
,
7
)
함수
i
=
>
i
+
3
실제로는 컴파일러가 다음과 같이
scala
.
Function1
(
http
://
bit
.
ly
/
13KD90C
)익명 서브클래스의 인스턴스로 변환하는 구문적 편의
syntactic
sugar
다.
val f
:
Int
=
>
Int
=
new Function1
[
Int
,
Int
]
{
def apply
(
i
:
Int
):
Int
=
i
+
3
}
List
(
1
,
2
,
3
,
4
)
map
(
f
)
//
결과
:
List
(
4
,
5
,
6
,
7
)
NOTE
_
객체 뒤에 인자 목록을 넣으면 기본으로 호출되는 메서드의 이름인
apply
함수 적용
function
application
에서 온 것이다. 그러므로 함수나 객체
f
를 정의하면, 그곳에 인자 목록을 적용해서 호출할 수 있다.
예를 들어
f
(
1
)실제로
f
.
apply
(
1
)호출한다.
422
2
기본기 다지기
역사적으로
JVM
은 바이트 코드에서 ‘단순한’ 함수를 허용하지 않았다. 모든 것을 객체로 둘러
싸야만 했다. 최근의 자바 버전, 특히 자바
8
에서는 이런 제한이 완화되긴 했지만, 스칼라가
전의
JVM
에서도 작동하기 위해서는 컴파일러가 익명 함수를 적당한
FunctionN
트레이트의
서브클래스로 변환해야 한다. 자바 프로그래머라면 자바 프로젝트에서 이런 식으로 자바
터페이스의 익명 서브클래스를 작성한 경우가 많을 것이다.
apply
추상 메서드이기 때문에,
FunctionN
추상 트레이트다. 여기서는
apply
정의했다.
우리가
i
=
>
i
+
3
같은 간단한 함수 리터럴 구문을 사용하면, 컴파일러가 이런 정의를 대신
해준다. 컴파일러는 함수 리터럴의 본문 부분을
FunctionN
apply
정의에 사용한다.
NOTE
_
자바
8
에서는 람다라고 부르는 함수 리터럴에 대한 지원이 추가되었다. 람다의 구현은 스칼라가 사
용하는 방식과 다르다. 스칼라는 예전의
JVM
지원해야 하기 때문이다.
반공변성으로 돌아와서, 다음은
scala
.
Function2
(
http
://
bit
.
ly
/
10Ft2tC
)선언이다.
trait Function2[-T1, -T2, +R] extends AnyRef
마지막 타입 매개변수인
+
R
반환 타입이다. 타입 매개변수는 공변성이다. 앞의 타입
개변수는 번째와 번째 인자의 타입이다. 둘은 반공변성이다. 다른
FunctionN
트레이트
경우에도 함수 인자에 해당하는 타입 매개변수는 반공변성이다.
따라서 함수는 상속에 대해 혼합된 공변성을 가진다.
이것은 어떤 의미일까? 변성의 동작을 이해하기 위한 몇 가지 예를 보자.
//
src
/
main
/
scala
/
progscala2
/
objectsystem
/
variance
/
func
.
scX
class CSuper
{
def msuper
()
=
println
("
CSuper
")
}
//
class C extends CSuper
{
def m
()
=
println
("
C
")
}
class CSub extends C
{
def msub
()
=
println
("
CSub
")
}
var f
:
C
=
>
C
=
(
c
:
C
)
=
>
new C
//
f
=
(
c
:
CSuper
)
=
>
new CSub
//

Get 프로그래밍 스칼라: 실용적인 스칼라 활용법을 익히는 가장 확실한 실전 바이블 (2.11.x 버전 기반) now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.