[궁금시리즈] 1-4. var는 동적 타입일까?
C#을 배우다 보면 다음과 같은 코드를 자주 보게 된다.
var number = 10;
이를 처음 본 사람들은 흔히 이렇게 생각한다.
“var는 타입을 안 적었으니까 동적 타입 아닌가?”
실제로 다른 언어(JavaScript, Python 등)에서 경험이 있는 개발자라면 더욱 그렇게 느끼기 쉽다.
하지만 결론부터 말하면,
var는 동적 타입이 아니다.
var는 컴파일러가 타입을 대신 써주는 문법(Syntax Sugar) 일 뿐이며, C#은 여전히 정적 타이핑 언어이다.
이번 글에서는 var가 실제로 어떻게 동작하는지 알아보자.
var는 타입이 아니다
먼저 가장 중요한 사실부터 알아보자.
많은 사람들이
var number = 10;
을 보고
var라는 새로운 타입이 존재한다고 생각한다.
하지만 그렇지 않다.
컴파일러는 위 코드를 보면 내부적으로
int number = 10;
으로 해석한다.
즉, var는 타입이 아니라
컴파일러에게 타입을 추론해 달라고 요청하는 키워드
이다.
컴파일러는 어떻게 타입을 알까?
컴파일러는 오른쪽 값을 보고 타입을 추론한다.
예를 들어
var number = 10;
↓
int number = 10;
var message = "Hello";
↓
string message = "Hello";
var list = new List<string>();
↓
List<string> list = new List<string>();
즉, 오른쪽 표현식을 분석하여 컴파일 시점에 타입을 결정한다.
컴파일이 끝나면 var는 사라진다
이 부분이 가장 중요하다.
컴파일이 끝난 후에는 IL 코드 안에 var라는 개념은 존재하지 않는다.
예를 들어
var age = 20;
컴파일 이후에는
int age = 20;
와 동일한 IL이 생성된다.
즉, 런타임에서는
var
라는 정보 자체가 존재하지 않는다.
var인데 다른 타입을 넣을 수 있을까?
동적 타입이라면 다음 코드가 가능해야 한다.
let value = 10;
value = "Hello";
하지만 C#에서는
var value = 10;
value = "Hello";
컴파일 오류가 발생한다.
Cannot implicitly convert type 'string' to 'int'
왜냐하면 첫 번째 줄에서 이미
int value
로 결정되었기 때문이다.
즉, var 역시 타입이 고정된다.
var는 언제 사용할 수 있을까?
컴파일러가 타입을 추론할 수 있어야 한다.
따라서 다음 코드는 가능하다.
var number = 100;
var text = "Hello";
var person = new Person();
반면
var value;
은 사용할 수 없다.
왜냐하면 오른쪽 값이 없으므로 타입을 추론할 수 없기 때문이다.
또한
var value = null;
도 사용할 수 없다.
null만으로는 어떤 타입인지 알 수 없기 때문이다.
var를 사용하면 성능이 달라질까?
결론부터 말하면
전혀 달라지지 않는다.
예를 들어
int number = 10;
과
var number = 10;
은 컴파일 이후 완전히 동일한 코드가 된다.
즉,
- 메모리 사용량
- 실행 속도
- JIT 최적화
모두 동일하다. 성능 차이는 0이다.
그럼 왜 var를 사용할까?
타입 이름이 너무 길어질 수 있기 때문이다.
예를 들어
Dictionary<string, List<Person>> dictionary =
new Dictionary<string, List<Person>>();
가독성이 좋지 않다.
var를 사용하면
var dictionary = new Dictionary<string, List<Person>>();
처럼 훨씬 읽기 쉬워진다.
또한 LINQ에서는 거의 필수적으로 사용된다.
var result = people
.Where(p => p.Age >= 20)
.Select(p => p.Name);
실제 타입은
IEnumerable<string>
이지만, 굳이 길게 작성할 필요가 없다.
그렇다고 항상 var를 사용하는 것이 좋을까?
그렇지는 않다. 가독성이 더 중요하다.
예를 들어
var age = 20;
는 괜찮다.
누가 봐도 int라는 것을 알 수 있다.
하지만
var result = GetData();
는 GetData()가 무엇을 반환하는지 알 수 없다.
이런 경우에는
Customer customer = GetCustomer();
처럼 타입을 명시하는 편이 더 읽기 쉽다.
즉, 타입이 명확하면 var를 사용하고,
명확하지 않으면 타입을 직접 작성하는 것이 좋다.
var와 dynamic는 완전히 다르다
많은 사람들이 가장 헷갈리는 부분이다.
var value = 10;
는 컴파일 시
int
로 결정된다.
반면
dynamic value = 10;
는 타입 검사가 런타임으로 미뤄진다.
즉,
dynamic value = 10;
value = "Hello";
value = true;
value = new Person();
모두 가능하다. dynamic는 정말 동적 타입처럼 동작한다. 반면 var는 절대 그렇지 않다.
var와 dynamic 비교
| var | dynamic |
|---|---|
| 컴파일 시 타입 결정 | 런타임에 타입 결정 |
| 정적 타이핑 | 동적 타이핑 |
| IntelliSense 지원 | 제한적 |
| 컴파일 오류 발생 | 런타임 오류 가능 |
| 성능 저하 없음 | 런타임 바인딩 비용 발생 |
마무리
var는 새로운 타입이 아니다. 단지 컴파일러가 오른쪽 값을 보고 타입을 대신 작성해 주는 문법일 뿐이다. 따라서 var를 사용한다고 해서 C#이 동적 타이핑 언어가 되는 것은 아니다.
오히려 var는 정적 타이핑의 장점을 그대로 유지하면서 코드의 가독성을 높여주는 기능이라고 이해하는 것이 맞다.
다음 글에서는 C#에서 자주 볼 수 있는 string과 String은 무엇이 다른지 알아보겠다.
핵심 정리
- var는 타입이 아니라 타입 추론 키워드이다.
- 컴파일러가 오른쪽 값을 보고 타입을 결정한다.
- 컴파일이 끝나면 var는 실제 타입으로 대체된다.
- var를 사용해도 성능 차이는 전혀 없다.
- 타입이 명확한 경우에는 var를 사용하는 것이 가독성에 도움이 된다.
- dynamic는 런타임 타입을 사용하는 것으로 var와 완전히 다른 개념이다.