Expressions are not allowed at the top level
스위프트를 배우는 입장이다 보니, 아직은 콘솔 환경에 무언가 결과를 띄우는 작업을 위주로 공부하고 있습니다. 그러다 보면 흔히 맞닥뜨리는 에러가 있는데요. 바로 "Expressions are not allowed at the top level" 에러.
궁금한 점이 있어서 하단에 print()
를 찍었는데 오류 메시지를 띄우기도 하고, DateFormatter
를 활용하거나 할 때도 오류 메시지가 뜨곤 했습니다. DateFormatter
의 경우에는 main.swift
파일에서는 잘 동작하던 코드였는데 옮기면서 오류 메시지가 뜨는 케이스였죠. 전체적으로 보면 main.swift
가 아닌 다른 파일에서는 꼭 이런 오류가 뜨는 걸 확인할 수 있었습니다.
// test.swift 파일
print("hello, world!") // 오류 메시지
let dateFormatter = DateFormatter() // 오류 없음
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" // 오류 메시지
node.js에서는 파일마다 별도로 실행해줄 수도 있었는데 하고 생각해보니, swift 프로젝트를 실행할 때는 특정 파일을 실행하라고 명령하지 않더라구요? 아마도 그래서 이런 문제가 있나보다 추측해볼 수 있었습니다. 그래서 간단한 내용들을 찍어볼 일이 있으면 얼른 main.swift 에 작성해서 해결하곤 했어요.
근데 문득 이게 왜 그런지 궁금하더라구요. 그래서 오늘은 간단하게 이 부분에 대해 생각해보고, 참고 자료가 되는 공식문서도 함께 공유해볼까 합니다.
The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions
스위프트 공식문서의 Declarations 부분에 보면 Top-Level Code 에 대해 언급하고 있습니다. 탑-레벨 코드는 다시 2가지로 나뉘는데요. top-level declarations 와 executable top-level code 입니다.
There are two kinds of top-level code: top-level declarations and executable top-level code. Top-level declarations consist of only declarations, and are allowed in all Swift source files. Executable top-level code contains statements and expressions, not just declarations, and is allowed only as the top-level entry point for the program.
위 내용 중에 볼드 처리 한 부분이 제가 궁금했던 부분과 맞닿아있습니다. 바로 실행 가능한 탑-레벨 코드는 탑-레벨 entry point 에서만 허용된다는 내용입니다. 결국 main.swift 파일은 탑-레벨 entry point 라서 허용이 되지만, 다른 파일들은 그렇지 않기 때문에 에러를 뱉어준다고 이해할 수 있겠네요.
// test.swift 파일
print("hello, world!") // "실행 가능한 탑-레벨 코드"
let dateFormatter = DateFormatter() // "탑-레벨 선언"
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" // "실행 가능한 탑-레벨 코드"
그렇다면 엔트리 포인트란 뭘까요? (공식 문서에서 특별히 언급하는 내용은 아니었지만) 검색해보니 엔트리 포인트란 어떠한 프로그램이 시작되는 포인트 라는 의미를 가지고 있었습니다. 즉 컴파일한 프로그램이 실행되기 위해서는 프로그램을 실행할 때 어디에서부터 시작해야 하는지 그 진입점을 알아야 하는데, 그게 바로 main.swift 파일이었던 거죠. (더 엄밀히 말하면 main.swift 파일의 첫 줄이겠죠?)
위에서 언급한 공식 문서 부분에서도 이 점을 언급하고 있습니다.
The Swift code you compile to make an executable can contain at most one of the following approaches to mark the top-level entry point, regardless of how the code is organized into files and modules: the main attribute, the NSApplicationMain attribute, the UIApplicationMain attribute, a main.swift file, or a file that contains top-level executable code.
우리가 무언가를 작성하고 이를 컴파일하면 스위프트 코드는 프로그램 실행을 위해 가장 먼저 시작되어야 할 엔트리 포인트를 지정하게 되는데, 그 중에 하나가 바로 main.swift 파일이었던 겁니다. 그래서 만약 main.swift
를 Main.swift
로 대문자로만 바꾸어줘도 아래와 같은 에러가 생기면서 컴파일이 되지 않는 것을 알 수 있었습니다.
여러 다른 파일에 각각 함수, 구조체, 클래스, 열거형 등을 선언해줘도 문제 없이 이를 불러올 수 있었던 것은 탑-레벨 코드(특별히는 탑-레벨 선언) 때문입니다. 마찬가지로 몇몇 실행 코드가 "Expressions are not allowed at the top level" 에러를 돌려준 이유도 이때문이죠. 그리고 이는 main.swift 파일이 콘솔 프로그램 실행을 위한 엔트리 포인트이기 때문이었습니다.
알고 나면 꽤나 단순한 내용이었다 싶은데, 왜 모를 때는 엄청 중요한 내용인 것만 같고 한지 모르겠어요. 그래도 이제는 고민할 필요가 없으니 후련한 마음이긴 합니다. 비슷한 궁금증이 있었던 분들이 보신다면 도움이 되면 좋겠네요.