432
2
부
기본기 다지기
추가로 스칼라
2
.
10
부터는 사용자가
AnyVal
을 확장한 값 클래스를 정의할 수 있게 되었다. 이에
대해서는
8
.
2
절 ‘참조 타입과 값 타입’에서 다뤘다.
반대로 다른 모든 타입은 참조 타입이다. 그런 타입들은
AnyRef
에서 파생된다.
AnyRef
는 자바
의
java
.
lang
.
Object
(
http
://
bit
.
ly
/
1E8xJKR
)에 해당한다. 자바에서는 기본 타입을 특별하
게 취급하기 때문에, 자바 객체 모델에서는
Object
위에 참조 타입과 기본 타입을 아우르는 부모
타입이 없다.
NOTE
_
스칼라
2
.
1
0
이전에는 컴파일러가 스칼라 참조 타입의 모든 인스턴스에
ScalaObject
라는 ‘표
지’ 트레이트를 혼합했었다. 하지만 더 이상 컴파일러가 그런 일을 하지 않기 때문에 해당 트레이트는 스칼라
2
.
11
에서 제거되었다.
이미 여러 참조 타입에 대해 배웠으며, 진행하면서 다른 참조 타입도 많이 보게 될 것이다. 하지
만 지금이 널리 사용되는 몇 가지 타입에 대해 설명하기 좋은 시점이다.
10.3
Nothing
(그리고
Null
)에 대한 더 많은 내용
Nothing
(
http
://
bit
.
ly
/
1wNaLo6
)과
Null
(
http
://
bit
.
ly
/
1tIbUOQ
)은 타입 시스템의 밑바
닥에 있는 두 가지 특이한 타입이다. 특히
Nothing
은 모든 다른 타입의 서브타입이며,
Null
은 모
든 참조 타입의 서브타입이다.
Null
은 대부분의 프로그래밍 언어에 있는 내용과 비슷한 개념이다. 다만 다른 언어에서는 보통
Null
타입을 정의하는 일은 없고, 키워드인
null
을 참조에 ‘대입’해서 해당 참조가 실제로는 아
무 값이 들어 있지 않음을 표현한다.
Null
은 컴파일러에 의해 마치 다음과 같은 선언이 있는 것
처럼 구현된다.
1
package scala
abstract final class Null extends AnyRef
1
역주_ 여기서
Nothing
과
Null
에대해설명하면서사용한코드는개념을설명하기위한것으로,실제
Nothing
이나
Null
의구현과는
다르다.두가지타입모두컴파일러가특별히제공하는타입이며,별도의소스파일에구현되어있는것이아니다.
433
10
장
스칼라 객체 시스템 I
어떻게
final
이면서
abstract
일 수 있을까? 이 선언은
Null
을 상속해서 여러분이 원하는 인
스턴스를 만드는 것을 금지한다. 하지만 실행 환경이 이 타입에 대한 인스턴스를 하나 제공하는
데, 바로 그것이 우리 모두 익히 알고 좋아하는
null
이다.
Null
은
AnyRef
의 서브타입이라고 명시되어 있다. 하지만 또한 모든
AnyRef
타입의 서브타입
이기도 하다. 그것이
null
을 모든 참조 타입의 인스턴스 대신 대입할 수 있도록 타입 시스템이
허용하기 위한 엄밀한 방식이다. 반대로
Null
이
AnyVal
의 서브타입은 아니기 때문에, 예를 들어
null
을
Int
에 대입할 수는 없다. 따라서 스칼라의
null
은 정확히 자바의
null
과 같은 동작을
한다. 이는 그 둘이
JVM
상에서 함께 존재해야 하기 때문이다. 그렇지 않다면 스칼라에서
null
이라는 개념을 없애고 그로 인해 발생할 수 있는 잠재적인 수많은 버그를 줄일 수 있었을 것이다.
반면
Nothing
과 비슷한 것을 자바에서는 찾을 수 없다. 하지만 그 타입은 자바의 타입 시스템에
존재하는 구멍을 메워준다.
Nothing
은 컴파일러에 의해 마치 다음과 같은 선언이 있는 것처럼 구
현된다.
package scala
abstract final class Nothing extends Any
Nothing
은 결과적으로
Any
를 확장한다. 동시에 (타입 시스템의 구성에서)
Nothing
은 참조 타
입뿐 아니라 값 타입까지 포함하는 모든 다른 타입의 서브클래스다. 다른 말로 하면,
Nothing
은 조금 이상하게 들리겠지만, 모든 것의 서브클래스다.
Null
과 달리
Nothing
에는 인스턴스가 없다. 그 대신 그것은 타입 시스템의 설계를 튼튼하고 타
입
-
안전하게 만들어주기 위해 두 가지 기능을 제공한다.
첫 번째 기능은 우리에게 익숙한
List
[+
A
]
(
http
://
bit
.
ly
/
1toub3N
) 클래스로 가장 잘 설명할
수 있다. 우리는 이제
List
가
A
에 대해 공변적임을 안다. 따라서
List
[
String
]
은
List
[
Any
]
의 서브타입이다.
String
이
Any
의 서브타입이기 때문이다. 따라서
List
[
String
]
의 인스턴스
를
List
[
Any
]
타입의 변수에 대입할 수 있다.
스칼라는 빈 리스트를 표현하는 특별한 타입인
Nil
(
http
://
bit
.
ly
/
1wN8LMz
)을 정의한다. 자
바였다면
Nil
은
List
와 마찬가지로 매개변수화한 클래스여야 할 것이다. 하지만
Nil
이 아무런
값도 저장하지 않기 때문에 그런 구현은 좋지 않다. 그러므로
Nil
[
String
]
과
Nil
[
Any
]
는 서로
다르다. 그러나 차이는 없다.
434
2
부
기본기 다지기
스칼라는 이 문제를
Nothing
을 사용해서 해결한다.
Nil
은 실제로 다음과 같이 정의된다.
package scala
.
collection
.
immutable
object Nil extends List
[
Nothing
]
with Product with Serializable
Product
에 대해서는 다음 절에서 설명할 것이다.
Serializable
은 자바의 내장 기능을 활용해
서 직렬화가 가능하다는 사실을 알려주는 이미 익숙해진 ‘표지’ 인터페이스다.
Nil
이
object
며,
List
[
Nothing
]
을 확장한다는 사실을 기억하라. 아무런 상태 (원소)도 운반하
지 않기 때문에,
Nil
의 인스턴스는 하나만 필요하다.
List
가 타입 매개변수에 대해 공변적이기
때문에,
Nil
은 모든 타입
A
에 대해
List
[
A
]
의 서브타입이다. 따라서 별도의
Nil
[
A
]
인스턴스
를 만들 필요가 없다. 하나면 충분하다.
Nothing
과
Null
은 바닥
bottom
타입이라 불린다. 왜냐하면 이 둘은 타입 계층의 맨 밑바닥에 위
치하기 때문이다. 따라서 이들은 모든 (또는 대부분의 ) 다른 타입의 서브타입이다.
Nothing
의 다른 사용법은 예외를 던지는 것과 같이 프로그램이 끝나게 만드는 식을 표현하는 것
이다.
8
.
9
절 ‘내포된 타입’에서 본
Predef
(
http
://
bit
.
ly
/
1086O2z
)의 특별한
???
메서드를 기
억하자. 그 메서드는 구체적 메서드이기 때문에, 컴파일을 가능하게 하기 위해 구체적 메서드가
필요한 곳에 들어갈 수 있는 임시 메서드로 호출될 수 있다. 하지만 해당 메서드가 호출되면 예
외가 던져진다. 다음은
???
의 정의다.
package scala
object Predef
{
...
def
???
:
Nothing
=
throw new NotImplementedError
...
}
???
이
Nothing
을 ‘반환’하기 때문에, 어떤 함수라도 자신의 반환 타입과 관계없이 이를 호출할
수 있다. 다음은 자세한 예다.
scala
>
def m
(
l
:
List
[
Int
]):
List
[
Int
]
=
l map
(
i
=
>
???)
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.