타입 앞에 이름: 왜 'int age'보다 'age int'가 더 나은가
원문은 Ben Hoyt님이 에 게재했습니다. 이 블로그 구독하기
요약: 변수의 이름은 타입보다 중요하므로, 선언에서 이름이 더 눈에 띄고 먼저 나와야 한다.
C, C++, Java, C#을 비롯한 많은 인기 프로그래밍 언어에서는 필드나 변수를 정의할 때 타입을 이름보다 먼저 쓴다. 예를 들어 C++에서는 다음과 같다:
// Struct definition
struct person {
std::string name;
std::string email;
int age;
};
// Stand-alone variables
std::vector<person> people = get_people();
int min_age = find_minimum_age(people);
std::string domain = parse_email_domain(people[0].email);반면 Go, Rust, TypeScript, Python(타입 힌트 사용 시) 등 다른 언어에서는 이름을 타입보다 먼저 쓴다. 예를 들어 Go에서는 다음과 같다:
// Struct definition
type Person struct {
Name string
Email string
Age int
}
// Stand-alone variables
var people []Person = getPeople()
var minAge int = findMinimumAge(people)
var domain string = parseEmailDomain(people[0].Email)
// Though it's more typical in Go to use := (short variable declarations)
people := getPeople()
minAge := findMinimumAge(people)
domain := parseEmailDomain(people[0].Email)Go FAQ에는 Go가 왜 이런 순서를 선택했는지에 대한 훌륭한 답변이 있다: “왜 선언이 거꾸로 되어 있나요?”. 이 글은 “C에 익숙해서 거꾸로 보이는 것뿐이다”라는 말로 시작하는데, 일리 있는 지적이다. 이름-먼저-타입 방식은 Pascal 같은 언어에서 오랜 역사를 가지고 있다. 실제로 Go의 타입 선언 구문(과 패키지)은 Pascal로부터 직접 영감을 받았다.
FAQ는 이어서 이름-먼저-타입 방식이 파싱이 더 간단하고 여러 변수를 선언할 때 C보다 오류가 덜 발생한다고 지적한다. C에서는 다음 코드가 x는 포인터로 선언하지만, (처음 보면 놀랍게도!) y는 일반 정수로 선언한다:
int* x, y;반면 Go에서 이에 해당하는 코드는 예상대로 동작하여 둘 다 포인터로 선언한다:
var x, y *intGo 블로그에는 Rob Pike가 쓴 Go의 선언 구문에 대한 심층 글도 있는데, 특히 배열과 함수 포인터와 관련해 Go 구문이 C보다 갖는 장점을 더 자세히 설명한다.
이상하게도 이 글은 일상적인 프로그래밍에서 이름-먼저-타입을 선호해야 하는 더 중요한 이유를 살짝 언급하는 데 그친다. 바로 더 명확하다는 점이다.
변수의 이름은 타입보다 중요하므로, 선언에서 이름이 더 눈에 띄고 먼저 나와야 한다.
이 점은 몇 가지 다른 방식으로 쉽게 증명할 수 있다고 생각한다:
- 변수 선언에서 타입 추론이 인기를 끌고 있다는 점으로, 이제 대부분의 언어에 포함된 기능이다. C#와 Java의
var, Go의:=, C++의auto등이 그 예다. - 타입이 전혀 필요 없고 이름만 있는 동적 타입 언어(Python, Ruby 등)가 존재한다는 점으로.
- 이름이 더 많은 의미 정보를 담고 있다는 점으로. 위 예시에서
minAge는 최소 연령 값을 명확히 의미하며, 그것이int라는 사실은 별로 많은 정보를 더해주지 않는다. 물론 타입 검사를 위해서는 유용하지만, 타입이 추론되는 경우에도 코드는 명확하다. (영어도 타입 추론을 쓴다. “Person Ben Hoyt가 이 텍스트 글을 썼다”라고는 절대 말하지 않는다.)
나는 한동안 이런 견해를 가지고 있었지만, 이를 글로 쓰게 된 계기는 최근 출시된 Cap’n Proto 1.0이었다. 이를 보며 Protocol Buffers와 Cap’n Proto의 스키마 문법 차이를 떠올리게 됐다.
아래 두 예시 중 어느 쪽에서 필드 이름을 더 쉽게 찾을 수 있을까? 다음은 Protocol Buffers 스키마다:
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}아니면 다음은 Cap’n Proto 스키마다:
struct SearchResponse {
results @1 :List(Result);
}
struct Result {
url @1 :Text;
title @2 :String;
snippets @3 :List(Text);
}어떨지 모르겠지만, 나는 가장 중요한 부분인 필드 이름이 Protocol Buffers 버전에서는 약간 묻힌다고 생각한다. Cap’n Proto 버전에서는 왼쪽 정렬 덕분에 훨씬 쉽게 눈에 띈다.
결론은 이렇다. 과거를 바꿀 수는 없지만, 새로운 언어를 만들고 있다면 제발 이름을 타입보다 먼저 두자!
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기