간단하거나, 복잡하거나. 세미콜론

예상보다 복잡한 세미콜론의 세계

세미콜론에서 다룬 것처럼 Go는 lexer가 세미콜론을 자동으로 삽입하기 때문에 소스코드에 쓸 일이 거의 없다.

Go 언어의 장점 중 하나로 얘기되지만, Go를 처음 접하는, 세미콜론을 반드시 써야하는 언어를 주로 사용하는 사용자들에게는 혼돈을 준다.

필요가 없다는 것이지, 쓰면 안되는 것은 아니다. 말 그대로 do not need 이지 must not 이 아니다.

자동으로(암시적으로; implicitly) 세미콜론이 추가되는 곳에 명시적으로(explicitly) 세미콜론을 써주면 lexer는 자동으로 추가하는 작업을 수행하지 않으며, 이 경우 소스코드가 세미콜론 언어와 굉장히 유사한 모양을 하게 된다.1

다시 한 번 lexer에 의해 세미콜론이 자동으로 삽입되는 규칙을 보면,

  • 개행 전 마지막 토큰이 identifier, literal이거나,

  • 다음 중 하나인 경우

break continue fallthrough return ++ -- ) } ]
  • 상황에 따라 닫는 괄호())나 닫는 중괄호(}) 직전

Go의 identifier에 대해서는 좀 더 자세히 짚고 넘어갈 필요가 있다.

Identifiers

Go 언어에는 4 종류의 토큰이 있다: identifiers, keywords, operators and punctuation, literal. 자세한 사항은 The Go Programming Language Specification을 참고한다.

다른 것들은 C/C++, Java와 유사한데, int, float 같은 흔히 얘기하는 기본 타입들이 Go의 경우에는 keyword가 아닌 identifier에 포함된다. Go의 Predeclared identifier는 다음과 같다.

// Types:
	bool byte complex64 complex128 error float32 float64
	int int8 int16 int32 int64 rune string
	uint uint8 uint16 uint32 uint64 uintptr

// Constants:
	true false iota

// Zero value:
	nil

// Functions:
	append cap close complex copy delete imag len
	make new panic print println real recover

Go가 자연스럽다(idiomatic) 주장하는 타입이 뒤에 오는 비상식적 선언법과 초기화 문법 등을 모두 포함해 단 하나의 문장,

Go는 개행 전 마지막 토큰이 identifier이거나 literal이면 세미콜론을 자동으로 삽입해 줍니다.

으로 표현해 버리는 용기, 그를 뒷받침하기 위해 익숙한 많은 것을 identifier로 몰아버림으로써 상식을 깨버리는 대범함. 멋지지 않은가?

세미콜론 가지고 놀기

위에서 언급한 것처럼 명시적으로 세미콜론을 써주면 Go lexer는 자동으로 세미콜론을 추가하는 기능을 수행하지 않으며, 거꾸로 소스코드 상에서 세미콜론이 쓰이는 자리에 위 규칙을 적용하면 이상야릇한 코드도 가능하다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main;

import "fmt";

type // type은 개행해도 ;가 추가되지 않는다.
Ints struct // struct도 개행할 수 있다.
{ a int; b int;
  c int; };


func main() { // main() 뒤 개행하면 ;가 추가된다.
	var s = "Hello, Go"; // auto s = "Hello, C++"
	fmt.Println(s);
	
	i := Ints{ 10, 20, 30 }; //i := Ints 뒤 개행하면 ;가 추가된다.
	fmt.Println(i.a);
	
	for
	j := 0
	j < 10
	j++ { // 개행하면 ;가 추가된다.
		fmt.Println(j);
	}
}

어떤 코드가 아름다운가?

어떤 코드가 더 아름다운가에 대한 케케묵은 논쟁을 겨우 세미콜론만으로 꺼내자는 것은 아니지만, 개인적으로는 “모든 가능성은 열려 있어. 너의 꿈을 펼쳐봐”를 주장하는 Perl보다는 “이 길이 꽃길이야. 이 길로만 가면 아름다운 세상이 펼쳐질거야”를 주장하는 Python의 철학을 좀 더 지지하는 편이다.2


Perl의 철학

TIMTOWTDI (There Is More Than One Way To Do It.)


Python의 철학

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Go는 디렉토리 구조 등 어떤 면에서는 개발자의 자유도를 구속하는 측면이 있다. 하지만 또 다른 면에서는 ‘그건 구속하면서 이건 왜 이렇게 헐렁해?’ 라는 의문을 갖게 하기도 한다.

“어떤 코드가 아름다운가?“라는 물음에는 각자의 답이 다르겠지만 “어떤 코드가 보기 좋은가?“에 대한 답은 대부분의 개발자가 비슷하지 않을까? 아름답다의 기준에는 분명 보기 좋다도 하나의 요소로 포함된다.


  1. 굳이 이 짓을 왜 하냐고 묻는다면, 마땅한 대답은 없다. [return]
  2. 표현이 좀 과격하긴 하다. 부디 Python에 대한 부정적 생각을 갖지 않길. [return]