최근 수정 시각 : 2024-10-09 13:04:34

Scala


파일:나무위키+유도.png  
은(는) 여기로 연결됩니다.
물리나 수학에서 쓰이는 Scalar에 대한 내용은 스칼라 문서
번 문단을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
참고하십시오.
프로그래밍 사이트 선정 프로그래밍 언어 순위 목록
{{{#!wiki style="margin: 0 -10px -5px; word-break: keep-all"
{{{#!wiki style="display: inline-table; min-width: 25%; min-height: 2em;"
{{{#!folding [ IEEE Spectrum 2024 ]
{{{#!wiki style="margin: -5px 0"
<rowcolor=#fff> 스펙트럼 부문 상위 10개 프로그래밍 언어 직업 부문 상위 10개 프로그래밍 언어
1 Python 1 SQL
2 Java 2 Python
3 JavaScript 3 Java
4 C++ 4 TypeScript
5 TypeScript 5 SAS
6 SQL 6 JavaScript
7 C# 7 C#
8 Go 8 HTML
9 C 9 Shell
10 HTML 10 C++
}}}
}}}
}}}
[ Stack Overflow 2024 ]
[ TIOBE 2024 ]
||<tablewidth=100%><width=9999><-4><bgcolor=deepskyblue><tablebgcolor=#fff,#222> 2024년 8월 기준 검색어 점유율 상위 20개 프로그래밍 언어 ||
1 Python 11 MATLAB
2 C++ 12 Delphi / Object Pascal
3 C 13 PHP
4 Java 14 Rust
5 C# 15 Ruby
6 JavaScript 16 Swift
7 SQL 17 Assembly language
8 Visual Basic 18 Kotlin
9 Go 19 R
10 Fortran 20 Scratch
{{{#!wiki style="margin: 0 -10px -5px; min-height: calc(1.5em + 5px);"
{{{#!folding [ 21위 ~ 50위 펼치기 · 접기 ]
{{{#!wiki style="margin: -5px -1px -11px"
21 COBOL 36 Scala
22 Classic Visual Basic 37 Transact-SQL
23 LISP 38 PL/SQL
24 Prolog 39 ABAP
25 Perl 40 Solidity
26 (Visual) FoxPro 41 GAMS
27 SAS 42 PowerShell
28 Haskell 43 TypeScript
29 Dart 44 Logo
30 Ada 45 Wolfram
31 D 46 Awk
32 Julia 47 RPG
33 Objective-C 48 ML
34 VBScript 49 Bash
35 Lua 50 Elixir
}}}}}}}}} ||
[ PYPL 2024 ]

}}} ||
프로그래밍 언어 목록 · 분류 · 문법

// scala 2
  object HelloWorld extends App {
   println("Hello, World!")
 }

// scala 3
  @main def hello() = println("Hello, World!")
<colbgcolor=#ffffff,#1f2023><colcolor=#380D09,#ffffff> Scala
파일:Scala-full-color.svg 파일:Scala-white-color_inkscape.svg
개발 마틴 오더스키
라이선스 Apache 2.0
최초 공개일 2004년 1월 20일
버전 3.5.1
파일:홈페이지 아이콘.svg
1. 개요2. 주요 특징
2.1. 쉬운 언어 확장과 DSL
2.1.1. 연산자2.1.2. 이름으로 평가(call-by-name evaluation)
2.2. 트레이트(trait)2.3. 짧은 소스
2.3.1. 생성자, 상속2.3.2. 게터/세터 자동 생성2.3.3. 싱글톤2.3.4. 타입 추론2.3.5. apply2.3.6. 그 외 편의 문법
2.4. 패턴 매칭
2.4.1. unapply
2.5. 함수형 프로그래밍 언어
2.5.1. 함수는 값이다2.5.2. 불변성2.5.3. for comprehension2.5.4. 타입클래스2.5.5. 함수형 프로그래밍 생태계2.5.6. 스칼라에서의 함수형 프로그래밍에 대한 한계
2.6. 문맥적 추상화
2.6.1. 확장 메소드(Extension method)2.6.2. 암묵적 변환(Implicit Conversion)2.6.3. 문맥 파라미터(Context Parameter)/문맥 바운드(Context Bound)
2.7. 자바와의 상호 호환2.8. XML 지원
3. 기타4. 외부 링크5. 관련 문서

[clearfix]

1. 개요

스칼라(Scala)는 다중 패러다임 프로그래밍 언어로, 객체지향 언어의 특성과 함수형 언어의 특성을 함께 가진다. JVM 상에서 구동되고 Java와 상호 호환이 가능하다. 스위스 로잔 연방 공과대학교( EPFL)의 마틴 오더스키(Martin Odersky)가 개발했다. 트위터, LinkedIn 등의 기업에서 활발하게 사용 중이지만, 메이저 언어의 자리는 아니다. 마이너 중에서 메이저인 정도이다.

Scala라는 명칭은 이탈리아어로 계단을 뜻하기도 하지만[1][2], Scalable Language에서 따온 것이기도 하다. 후자의 이유로 scala는 한국에서 이르는 것과 같이 '스칼라(skah-lah)'라고 읽으라 마틴 오더스키가 공인했지만, 영어권에서는 '스케일러(skay-lah)'라고 자주 부르는 모양이다.

여담으로, Pascal 언어를 만든 Niklaus Wirth 교수는 ETH(Eidgenössische Technische Hochschule) Zürich에 재직할 당시 Martin Odersky를 지도했고, Odersky는 이 연구실에서 박사 학위를 받았다. 이후 Odersky가 EPFL에 교수로 재직하면서 함수형 언어와 함께 Java의 기능 확장에 대한 연구 도중 탄생한 언어가 Scala다. 프로그래밍 언어론을 제대로 연구한 사람이 만들어서 그런지 매우 강력하나 그만큼 잘 공부하고 사용하는 것이 생각보다 쉽지 않다.

Stack Overflow 2018년 개발자 설문에 따르면, 미국에서 언어별 평균 연봉 1위라고 한다.(전세계 기준으로는 7위) 언어별 연봉 항목이 생긴 2016년 이래로 미국에서는 쭉 1위를 유지하고 있다.

2. 주요 특징

스칼라는 마틴 오더스키가 자바 제네릭 컴파일러를 개발하며 느꼈던 자바의 여러 가지 단점들을 근본적으로 수정하고, 추후 프로그램 언어 연구를 위한 연구 플랫폼으로 함께 사용하기 위하여 디자인한 언어이다. 따라서 언뜻 보기에는 자바와 비슷해 보일지 모르나 여러가지 측면에서 더욱 발전된 형태를 가지고 있다.

2.1. 쉬운 언어 확장과 DSL

언어 이름이 괜히 Scalable[3] Language인 게 아니다. 쉽게 언어를 확장하여 도메인 특화 언어(Domain Specific Language;DSL)을 만들 수 있다. 스칼라에서는 DSL 제작을 언어 차원에서 작정하고 밀어주기 때문에 DSL 제작이 적은 소스로도 용이하며 DSL과 오리지널 스칼라를 섞어 쓰기도 쉬워 DSL 사용도 어렵지 않다.[4] DSL 정의의 단적인 예로 BASIC 문법을 정의한 BAYSICK이 있다.[5]

2.1.1. 연산자

스칼라에서는 자바에선 불가능했던 식별자명(+, % 등)을 식별자에 붙일 수 있다. 예를 들어 +라는 메소드를 정의하면 first.+(second)같은 식이 유효해진다. 여기에 더해 스칼라에선 a.f(b)a f b의 형태로 쓸 수 있기 때문에 first + second도 유효하다. 이런 식으로 자바에선 불가능했던 연산자 오버로딩을 할 수 있다.[6]

2.1.2. 이름으로 평가(call-by-name evaluation)

인자로 함수를 넘기다 못해 아예 코드 블록을 넘길 수 있다. 사실 구현 자체는 단순히 인자 없는 익명 함수에서 인자를 받는 부분을 생략하는 것 뿐이지만, 호출 측에서는 코드를 그대로 넘겨서 호출할 수 있다. 즉 아예 처음부터 언어에 있었던 것 같은 기능을 만드는 것도 가능하다.

2.2. 트레이트(trait)

트레이트는, 얼핏 보면 클래스는 아닌데 상속[7]을, 그것도 여러 번 할 수 있는 점에서 자바 인터페이스와 비슷해 보일 수도 있다. 실제로 자바 인터페이스를 스칼라에서는 트레이트로 인식하며, 그냥 트레이트를 자바 인터페이스처럼 사용해도 좋다. 하지만 트레이트는 자바 인터페이스와는 달리[8] 구체적인 구현을 담고 있으며[9] 믹스인이 가능하다.
// 예를 들어 아래와 같은 클래스가 있다고 쳐보자.
Server extends Logger

// Server의 인스턴스를 만들 때 아래처럼 선언하면 파일로 로깅한다.
Server extends FileLogger

// 아래처럼 하면 네트워크를 통해 로그를 남긴다.
Server extends NetworkLogger

// 아니면 아래처럼 하면 파일과 네트워크에 모두 로그를 남길 수 있다.
Server extends FileLogger with NetworkLogger
물론 상응하는 FileLoggerNetworkLogger는 미리 작성해두어야 한다. 즉 AOP를 언어 차원에서 지원한다. 또한 자바 인터페이스와 마찬가지로 구현하지 않은 메소드는 상속하는 쪽에서 구현해야 하므로 트레이트를 추상 클래스 급으로 만들어 놓고 믹스인으로 의존성을 주입할 수도 있다. 이런식으로 인터페이스처럼 보이지만 실은 믹스인할 수 있는 모듈이라고 보면 된다. 트레이트를 모듈로 쓰게 되면 with로 트레이트를 쭉 쌓게 되는데, 여기서 착안해서 이런 방식을 케이크 패턴이라고 부른다.

2.3. 짧은 소스

자바의 장황함이 많이 개선되었다.

2.3.1. 생성자, 상속

클래스의 생성자, 슈퍼클래스 상속, 슈퍼클래스 생성자 호출이 클래스 선언과 융합(...)되었다. 보통 class 클래스명(인자1,인자2,...) extends 슈퍼클래스명(인자1, 인자2, ...){...}의 형태가 된다. 클래스명 옆의 인자 목록은 기본 클래스 생성자의 인자 목록이며, 슈퍼클래스명 옆의 인자 목록은 호출할 슈퍼클래스의 생성자에 해당하는 인자 목록이다. 이 외에 생성자를 오버로딩하고 싶다면 보조 생성자를 추가로 만들 수 있다. 자바와는 달리 보조 생성자의 이름은 무조건 this이다. 위 형태에서 기본 생성자의 본문이 어디있나 궁금할 수도 있는데, 클래스 본문 전체가 기본 생성자의 본문이 된다는 구성이다.

2.3.2. 게터/세터 자동 생성

필드를 선언하면 그 필드에 따라[10] 내부적으로 게터/세터가 생성된다. "객체.필드"이나 "객체.필드=값"으로 게터와 세터를 호출할 수 있다. 자동 생성된 게터와 세터는 명시적으로 오버라이드 가능하다. 단, 내부적으로 생성되는 게터/세터는 자바 스타일[11]이 아니기 때문에 자바 쪽에서 쉽게 호출할 수 있게 하려면 @BeanProperty 어노테이션을 사용해야 한다.

2.3.3. 싱글톤

object 키워드로 싱글톤 오브젝트를 만들 수 있다[12]. 또한 스칼라에는 자바의 static에 대응하는 키워드가 없고 클래스와 같은 이름의 오브젝트(컴패니언 오브젝트)를 만들 수 있다. 때문에 자바에서라면 한 클래스 안에 존재했을 정적 코드와 클래스 코드가 자연스럽게 분리된다. 싱글톤을 원클릭으로 만들 수 있는 것도 장점이지만 static을 일일이 붙이지 않아도 되는 것도 사소한 장점이다.

2.3.4. 타입 추론

변수의 타입, 함수의 반환값의 타입 등을 컴파일러가 추론해준다. 별 거 아닌 것 같아 보여도 코드 양이 줄어드는 데 큰 공여를 한다. 자바에서 아래처럼 썼던 것을 생각해보자.
Person p = new Person();
자바 10부터는 var 키워드로 타입 추론이 가능해졌다. 스칼라에서는 같은 타입 이야기를 두 번 하지 않아도 된다. 함수 반환값 추론은 사실 의식적으로는 거의 쓰이지 않는다. 재귀에서는 추론이 불가능하며 재귀가 아니더라도 클래스의 public 함수에서는 타입을 명시하는 게 관행이기 때문이다. 함수 반환값 추론이 빛을 발할 때는 익명 함수를 사용할 때이다.

2.3.5. apply

apply는 C++에서 () 연산자를 오버로드하는 것을 떠올리면 된다. 예를 들어 배열을 임의 참조할 때 자바는 배열이 특수 객체로서 []을 사용할 수 있지만, 스칼라에서는 배열도 보통 객체 취급을 받으며 대신 apply가 구현되어 있어 ()로 임의 위치를 참조 가능하다. 또한 컴페니언 오브젝트에 apply를 구현해두면 생성자 대용으로도 쓸 수 있는데, 배열 등을 중첩할 때 new를 사용하지 않아도 되므로 편리하다. 심지어는 사실 함수 객체도 apply로 구현되어 있다(...).

2.3.6. 그 외 편의 문법

익명 함수에 대한 편의 문법을 제공한다. 예를 들어. 아래와 같은 익명 함수가 있다고 쳐 보자.
(a, b) => a + b
이것만으로도 익명 클래스에 메소드를 구현하는 것에 비해 충분히 짧지만 _+_라는 단 세글자로, 그것도 가독성이 매우 높게 축약하는 게 가능하다.

2.4. 패턴 매칭

굳이 따지자면 자바의 switch~case문에 대응한다. 겉으로 보이는 차이점은 fall-through[13]가 없다는 점 정도지만, 가드와 unapply 메소드와 연계되어 switch문보다 복잡하게 실행된다. 사실상 unapply가 없으면 별 거 없는 그냥 시체가 된다.

2.4.1. unapply

unapply는 이름처럼 apply의 반대인데, apply처럼 괄호 안에 목록을 집어넣으면 그 안에 값을 집어넣는다. 즉 구조 분해(destructuring)를 손쉽게 해준다. 예를 들어 조금 특수한 경우이기는 하지만 ("namu","나무위키")라는 순서쌍이 t라는 이름으로 선언되어 있을 때 아래처럼 써 넣으면 keyval에 각각 "namu""나무위키"가 들어간다.
(key, val) = t
이 예제처럼 단독으로 쓰일 수도 있지만 보통은 패턴 매칭에서 구조를 분해하는 데 사용한다.

2.5. 함수형 프로그래밍 언어

스칼라는 함수형 프로그래밍을 잘 지원한다.

2.5.1. 함수는 값이다

#!syntax kotlin
val increment = (i: Int) => i + 1
함수형 언어의 기본 특징인데, 함수도 일반적으로 '데이터'라고 생각하는 IntString 타입의 값들과 동일한 취급을 받는다. 또한, 스칼라에서 모든 값은 객체이므로 함수도 객체이다.[14] 스칼라에는 인자의 갯수에 따라 Function0부터 Function22까지의 클래스가 기본으로 정의되어 있다. 따라서 함수도 다른 값처럼 변수에 담기고, 인자로 넘어가고, 값으로 반환될 수 있다. 함수 리터럴도 지원된다. 1Int 타입의 리터럴이고 "안녕 세계!"String타입의 리터럴이듯이, (i: Int) => i + 1Function1[Int, Int]타입의 리터럴이다. 요새 자주 들을 수 있는 그 람다식 맞다.

2.5.2. 불변성

스칼라를 처음 배우는 사람들을 대상으로 하는 많은 서적에서 변수 선언의 기본 방식은 val로 가르친다. val로 선언된 변수는 그 변수가 더이상 유효하지 않게 될 때 까지 그 값을 바꾸는 것이 불가능하다. 명령형 언어에서 자주 보이는 재 대입이 가능한 변수는 var로 선언해야 한다.

하지만 변수가 한번 선언된 이후에 다른 객체를 가리키지 못하게 하는 것만으로는 충분한 불변성을 제공해주지는 않는다. val로 선언된 변수는 다른 객체를 가리킬 수는 없지만, 가리키고 있는 객체의 상태가 바뀌는 것은 막지 못한다.
예를 들어,
#!syntax kotlin
val arr = Array(1, 2, 3, 4, 5)
arr = Array(1, 2, 3) //다른 객체를 가리키는 것은 금지
은 불가능하지만
#!syntax kotlin
val arr = Array(1, 2, 3, 4, 5)
arr(0) = 0 //가리키고 있는 객체의 상태가 바뀌는 것은 허용
은 가능하다.[15]

이러한 결점을 보완하기 위해, 스칼라의 내장 콜렉션은 mutable(가변)과 immutable(불변)으로 나뉘어져 있고, 불변 콜렉션에는 원소에 대한 재대입이 불가능하다. 따라서 변경을 위해서는 변경된 새로운 콜렉션을 리턴하는 방식을 사용해야 한다. 위에서 든 예시인 Array는 가변 콜렉션이지만[16], 기본적으로 임포트되는 스칼라의 고유 콜렉션들(ListVector 등)은 불변이 기본값이다.

스칼라에서는 클래스 안에서도 되도록이면 var를 쓰지 않도록 권장한다.

2.5.3. for comprehension

스칼라의 for - yield문은 Haskelldo 와 같은 기능을 가진 것으로, 루프와는 전혀 다른 성질의 것이다(스칼라를 시작할 때에는 거부감을 적게 하기 위해 for을 가지고 루프하는 것부터 배우긴 한다). for - yield 문은 모나드를 위한 문법으로, 중첩된 flatMapmap, 그리고 filter (정확히 말하면 withFilter) 메소드 호출을 깔끔하게 해주는 역할을 한다. 모나드를 많이 사용하다 보면 언어 내부의 일종의 미니 언어라고 생각하고 작성하게 되는 경우가 많다.

For문의 활용에 대한 영상. 56분으로 꽤 길고, 영어임에 주의

2.5.4. 타입클래스

파일:상세 내용 아이콘.svg   자세한 내용은 Haskell/특징 문서
7번 문단을
부분을
참고하십시오.
OOP의 서브타이핑이 아니라 타입클래스를 통한 다형성을 자연스럽게 지원하는 몇 안 되는 정적타입 언어 중 하나이다.(다른 언어로는 Haskell, Rust 등이 있다.) 이 중에서도 서브타이핑과 타입클래스가 동시에 자연스럽게 지원되는 언어는 스칼라가 유일하다.(스칼라가 하이브리드라고 불리는 이유 중 큰 부분을 차지한다.)

서브타이핑과 타입클래스가 동시에 지원되는 바람에 생긴 문제가 없는 것은 아니다. classtrait이나 extends와 같은 것들이 언어 차원에서 키워드로 지원되는 것과 달리 스칼라에서의 타입클래스는 하나의 패턴으로서 다른 언어의 기능들을 활용해서 지원되는 것이고 언어 차원의 키워드가 제공되지 않는다. 따라서 라이브러리에 따라 조금씩 타입클래스를 작성하는 방법이 살짝씩 달라 호환되지 않는 경우가 발생할 수도 있다. 하지만 모든 분야마다 실질적인 표준으로 자리매김한 라이브러리들이 존재하고 대부분의 라이브러리들이 타입클래스의 작성 방식을 한 가지 방식으로 통일한 현 시점에서는 호환성 문제는 크게 걱정하지 않아도 된다.

2.5.5. 함수형 프로그래밍 생태계

스칼라의 모기업(?)인 Lightbend의 도구들이(Play, Akka 등) 엔터프라이즈 영역과 자바와의 호환성을 타겟으로 한다면 Typelevel 프로젝트의 도구들은 함수형 프로그래밍을 포함해, 스칼라 컴파일러의 능력을 극한으로 끌어낸 타입 안정성에 초점을 둔다. 따라서 함수형 프로그래밍을 하게 되면 scalazcats라이브러리를 자주 보게 될 것이다.

2.5.6. 스칼라에서의 함수형 프로그래밍에 대한 한계

  • JVM이 TCO를 미지원하기 때문에 많은 경우에 트램폴린을 통해 안정성을 확보하지만 코드가 복잡해지고 스택이 아니라 힙을 사용하는 이상 캐시미스가 필연적이라 성능이 하락한다.(JVM 19부터 실험적인 기능으로 TCO를 활용할 수 있게 되기 때문에 해결될 가능성이 있다.)
  • 서브타이핑 지원으로 인해 전역 타입추론이 불가능하고, 지역 타입추론만이 가능하다.
  • 타입클래스 인코딩에 대한 언어 자체적인 내장 기능이 없다.
  • 암묵적인 요소를 많이 사용하면 컴파일 시간이 늘어난다.
  • Haskell보다 타수가 많다.
  • Kind polymorphism 등 Haskell이 지원하는 몇몇 고급 기능을 지원하지 않는다. 예를 들면 TypeTag의 표현이 있다. TypeTag[Int]TypeTag[List] 모두 스칼라에 존재하지만 전자는 Kind * -> *, 후자는 Kind (* -> *) -> *이기 때문에 엄연히 다르다. 현재 스칼라의 문법으로는 이 둘을 올바르게 구분/표현해낼 방법이 없다. Dotty에서 AnyKind라는 새로운 타입이 추가될 예정이다.
  • 함수들이 기본적으로 커링(Currying) 된 상태가 아니다.

2.6. 문맥적 추상화

문맥적 추상화는 코드의 문맥(여기서 문맥이란 스코프 내에 존재하는 식별자나 요구되는 타입 등을 뜻 한다.)에 따라서 일부 구현이 필요한 부분을 컴파일러에게 맡겨 추상화를 달성하는 스칼라의 주요 특징이다.[17][18]

스칼라 2 버전부터 사용한 사람들은 암묵(implicit)이라는 용어로 많이 접했던 내용이며 스칼라 3에서 문맥(Context) 이라는 개념으로 바뀌는 중이다.

대표적으로 아래의 기능들이 있다.

2.6.1. 확장 메소드(Extension method)

확장 메소드는 스칼라 3에서 추가된, 기존 클래스의 정의를 수정하지 않고 기능을 추가하는 방법이다.

이런 확장 메소드의 구현 자체는 사실 문맥적 추상화 기능을 사용하지 않아도 된다.

예를 들면 A라는 클래스에 isEven라는 메소드를 추가하고 싶다면 아래 처럼 구현하면 된다.
#!syntax kotlin
class A {
  val x: Long
}

object Extension {
  def isEven(a: A) =  a.x % 2 == 0
}

// 실제 사용하는 곳
Extension.isEven(a)
하지만 스칼라의 확장 메소드는 여기에서 더 나아간 문법을 보여주는데 외부에 구현된 메소드를 마치 내부 메소드의 호출과 같이 다룰 수 있다는 점이다.
#!syntax kotlin
extension (a: A)
  def isEven =  a.x % 2 == 0  // 확장 메소드 정의

a.isEven // 확장 메소드 기능으로 이와 같이 가능
위와 같이 컴파일러가 외부 메소드를 문맥에 맞게 내부 메소드처럼 사용할 수 있도록 하는 기능이 확장 메소드이다.

2.6.2. 암묵적 변환(Implicit Conversion)

암묵적으로 어떤 객체를 다른 타입으로 변환할 수 있다. 이것을 이용해서 위임을 편하게 만들어 원래 타입에 존재하지 않는 메소드를 애초에 있던 것처럼 호출할 수 있다. 예를 들어 자바의 {{BigInteger}}}를 사용하려 하는데 .add() 등을 사용하지 않고 암묵 변환을 이용해서 보조 클래스를 만들면 BigInteger+ 등의 연산자를 적용할 수도 있다.

2.6.3. 문맥 파라미터(Context Parameter)/문맥 바운드(Context Bound)

메소드 인자에 쓰일 값을 컴파일러가 문맥 내에서 선택하고 메소드로 넘기도록 할 수 있다.(디폴트 인자와는 다르다. 디폴트 인자는 메소드 정의에서 값을 써 놓는 반면 문맥 파라미터는 메소드 정의에선 문맥 파라미터를 사용한다는 선언만 하고 외부 범위에서 값을 받아온다.) 따라서 프로그래머가 별도로 인자를 넘기지 않아도 되며 별 생각 없이 쓰던 메소드의 정의를 살펴보면 듣도 보도 못한 인자 몇 개가 붙어있는 것을 가끔 볼 수 있다.

또한 문맥 파라미터의 타입이 메소드의 타입 파라미터와 연관되어 있을 경우 이를 쉽게 표현 가능한 문맥 바운드라는 기능을 사용 할 수 있다.

2.7. 자바와의 상호 호환

스칼라에서 별다른 절차 없이 자바 코드를 100% 가져다 쓸 수 있다.[19] 원하는 자바 라이브러리가 있으면 sbt에서 불러오게 하면 된다. 자바에서 스칼라 코드를 그대로 쓸 순 없는데, 컴파일 결과물은 자바 바이트코드지만 스칼라에서 정의한 연산자, apply 등을 자바에서는 (당연히) 스칼라에서 쓰던 식으로 쓸 수 없기 때문이다. 명시적으로 바뀐 이름으로 호출할 수 있긴 하지만, 그렇게 하면 가독성이 안드로메다로 가므로 스칼라 쪽에서 자바 스타일로 인터페이스 계층을 깔자.

2.8. XML 지원

XML 리터럴을 지원한다. 즉 XML 문서를 만들어내고 싶으면 스칼라 소스 내에 XML을 하드코딩하는 행위가 가능하다. 또한 XML 리터럴 내에서 스칼라 코드를 집어넣어 동적으로 XML을 생성할 수 있다.(XML 리터럴 내에 있는 스칼라 코드 안에 XML 리터럴을 집어넣고 하는 무한 루프도 가능하다.) 또한 XPath 탐색을 지원해서 XML 파싱이 쉽다.

그러나 현재 가장 많이 사용되는 Semi-structured Document를 위한 사실상의 표준은 JSON이며 이 때문에 왜 스칼라가 XML을 문법 수준에서 지원하는지 의아할 수 있다. 이에 대해 한 발표회에서 밝힌 스칼라의 아버지 마틴 오더스키 교수의 대답은 아래와 같았다.
스칼라를 처음 만들 당시에는 XML이 잘 나갈 줄 알았다.
마틴 오더스키
참고로 2000년대 초중반에는 이제 막 등장했던 XML에 대한 관심과 열기가 지금과 달리 대단했으므로 오더스키 교수가 저렇게 판단한 것도 무리는 아니다. JSX를 생각하면 그렇게까지 틀린것도 아니다.

스칼라 3(Dotty)에서는 지원 중단이 예정되어 있다.

3. 기타

컴파일 언어[20]이며 인터프리터가 따로 있는 것도 아닌데도 REPL[21]을 지원한다. 원리가 뭔가 하면 입력→컴파일→실행→출력의 과정을 거친다. (사실 REPL의 원조인 LISP 인터프리터도 이렇게 동작한다) 스칼라는 그렇게 느린 편은 아니라 컴파일까지 해도 웬만큼 긴 소스가 아니라면(사실 그만큼 긴 소스를 REPL에 넣는 게 이상하지만) 체감되진 않지만, 이 때문에 웹이나 안드로이드 등으로 스칼라 REPL을 포팅하기는 매우 귀찮다어렵다. 라이벌(?) 언어인 Clojure는 태생이 스크립트 언어라 안드로이드 REPL까지 나오는데도 스칼라는 소식이 없다.[22]

IDE는 이클립스[23]와 이클립스 기반으로 개발된 ScalaIDE가 있지만, Scala 지원을 정식으로 해주는 IntelliJ IDEA의 사용도가 더 높다.[24] 애초에 공식 홈페이지에서부터 IntelliJ를 권장하고 있다. 자바의 장황함이 많이 개선되었다지만 import 목록은 버틸 수가 없으니 날코딩은 추천하지 않는다. 텍스트 에디터에서 작업하려면 Metals를 활용해보자. Metals는 베타 버전의 LSP 서버 구현체인데, 실 사용에 큰 지장이 없을 정도로까지 개선되었다. Metals를 통한 VSCode나 Vim 서포트가 좋은 편이다.
빌드 툴은 Maven, Gradle이 이분하고 있는 자바와는 달리 sbt가 사실상 표준이며, 나머지 자리는 Maven과 Gradle이 조금씩 차지하고 있다. 웬만한 스칼라 라이브러리 설치 가이드엔 대부분 sbt에서 설치하는 법이 포함되어 있다. build.sbt 파일에 빌드 스크립트를 작성하는데, 사실 sbt 파일도 약간의 암묵적인 정의가 들어간 스칼라 DSL이기 때문에 스칼라 코드의 대부분을 작성할 수 있다. 대신 build.sbt 대신 build.scala을 쓴다면 써야 할 양이 늘어나지만 일반 스칼라 코드와 완전 동일하게 작성할 수 있다.

웹 애플리케이션 개발용 프레임워크로 Play 프레임워크가 있다. Play는 많은 기업들에게 채택되어 안정성을 입증받은 프레임워크이다.

테스팅 프레임워크는 ScalaTest가 폭넓은 테스트 선택폭[25]으로 인해 널리 쓰인다. ScalaTest 외에도 Spec2, Scalacheck 등의 프레임워크가 있다. JUnit을 그냥 사용하는 것도 가능하다.

4. 외부 링크

5. 관련 문서



[1] 더 나은 프로그래밍 언어로 나아가는 계단의 역할을 한다고 한다. 문서 상단의 공식 로고도 로잔 연방 공과대학교의, Scala가 개발된 곳에 있는 나선형 계단을 형상화한 것이다. # [2] 어원인 라틴어 scāla도 계단이라는 뜻이 있다. 다만 사다리라는 의미로 쓰는 용례가 더 많다. [3] 확장이 용이한 [4] 단 연산자 우선순위 문제가 있으므로 DSL 제작 시에 모양 좋아보이는 것만 고르지 말고 적절한 연산자를 골라야 한다. [5] https://github.com/fogus/baysick [6] ++--가 스칼라에는 없는데 이 규칙의 일관성을 위해서다. 겨우 한 글자 덜 타이핑하자고 예외 조항을 만들기는 싫었다는 듯하다. 실제로 C++에서는 ++/--의 오버로딩이 가능한데 좀 복잡하다. 어차피 함수형 성격이 강해서 고전적인 루프문을 쓸 일이 적으므로 ++/--의 부재가 크게 느껴지진 않을 것이다. [7] 자바와는 달리, 스칼라에서는 트레이트도 그냥 extends 키워드를 사용한다. [8] 자바 7까지 한정 [9] 구체적인 구현이 있는데 다중상속이 가능하면 다이아몬드 문제가 일어날 지도 모른다고 생각할 수도 있지만, 트레이트를 믹스인하는 순서에 따라 호출 메소드가 결정되므로 문제는 없다. [10] 수정 불가능한 val일 경우 세터는 생성되지 않는다. [11] 정확히는 자바빈즈 스타일. getXXX나 setXXX 꼴을 말한다. [12] 문서 상단의 예제가 바로 이 키워드를 사용한다. [13] case에서 break;가 없으면 다음 case로 넘어가는 것 [14] 주의할 점은 메소드는 객체가 아니라는 것이다. 스칼라 내에서는 메소드와 함수는 전혀 다른 것이고, Eta-expansion을 통해 메소드가 함수로 변환되는 경우가 있지만 본질적인 차이를 이해하지 못하면 컴파일 에러를 이해하지 못하는 경우가 발생할 수 있다. 자세한 것은 여기 참조. [15] 이 부분은 C++의 const와는 다르고, Java의 final과 비슷하다. [16] 자바와의 상호호환을 위한 것 [17] https://docs.scala-lang.org/scala3/book/ca-contextual-abstractions-intro.html [18] https://docs.scala-lang.org/scala3/reference/contextual [19] 물론 자바 스타일로. 스칼라 스타일로 자바 코드를 쓰고 싶다면 작은 DSL을 구축하면 된다. [20] 물론 자바 바이트코드로 [21] Read-Eval-Print-Loop. 입력받은 것을 읽은 후 평가(실행)해서 그 결과를 출력하는 것을 반복하는 작업. [22] 다만 스칼라가 이런 정신나간 짓을 한 덕분에 자바 9에서도 JShell이라는 이름으로 REPL이 추가될 예정이므로, 안드로이드에서도 볼 수 있을지도 모른다. [23] 물론 플러그인 필요 [24] JDK만 미리 설치되어 있으면 나머지 툴은 번들로 설치된다. [25] 기본적으로 BDD이며, JUnit식 테스트부터 spec식 테스트까지 다양한 테스트 스타일이 가능하다. [26] 한국어 번역 [27] 트위터 사 제작. [28] 역시 트위터 사에서 제작했다. 다른 이펙티브 시리즈(이펙티브 자바, 이펙티브 C++ 등)와는 달리 책이 아니라 웹 문서이다.