Objective-C 에 관한 잡담
그렇게 오래는 아니지만 어쨌든 Objective-C를 수 년 간 이용해 왔다. 이제는 익숙해졌기 때문에 처음 봤을 때의 인상에 비해 호감이 가는 언어가 되었다. 심심해서 이 언어에 대한 썰을 한번 풀어본다.
이하 Objective-C는 한글로 '옵씨'로 줄여서 표현한다. 그리고 옵씨에 대한 설명이 아니다 보니 옵씨를 이제 시작하는 분들에게는 별 의미 없는 글일 것 같다.
컴파일이 가능한 언어!
요즘 들어서는 스크립트 언어들이 유명세를 타고 있긴 하다. 별도의 빌드 과정이 필요 없으며 (물론 일부는 바이트컴파일을 알아서 하기도 하지만) 코딩 자체가 많이 간단해지도 복잡한 코드도 간단한 문법으로 쓸 수가 있다.
하지만 이에 비해서 컴파일로 네이티브 코드를 만들어 내는 언어 만의 특징이 있다. 빠르다. 이것 뿐일지도... -_-;;;
옵씨는 C나 C++에 비해 뭔가 스크립트 언어스러운 점을 조금은 가지고 있는 언어다. 그런 의미에서 이런 언어가 네이티브 코드로 빌드가 가능하다는 점은 장점에 장점을 더하게 되는 셈이기도 하다.
어색한 용어들
옵씨의 용어는 다른 언어에 비해 어색한 편이다. 대표적으로 셀렉터(selector) 라던가 메시지(message) 라는게 있다.
셀렉터 라는건 '메소드 이름'이라고 보면 된다. 하지만 이 셀렉터를 표현하는 문법 자체가 다른 언어와는 획일적으로 다르다. (아래 항목에서 이어진다)
옵씨에서는 메소드 호출(call)을 '메시지를 보낸다' 라고 한다. 클래스 인스턴스에게 메시지를 보내면 그 클래스가 알아서 하고 나중에 결과를 알려준다는 의미로 이해하면 되는걸까? 덕분에 실제로 존재하지 않는 nil 인스턴스에게도 메시지를 보낼 수 있다.
하지만 메시지 동작은 일반적인 메소드 방식과 겉으로 보기엔 큰 차이가 없다.
프로퍼티(property)라는 표현은 생각보다 어색하지는 않다. 아니 오히려 이해가 잘 되는 표현 같다. 멤버 변수라는 표현 보다는 프로퍼티라는 표현이 더 적절하다고 느낄 때가 많다.
직관적인(?) 메소드 호출
가장 옵씨 다운 점이라면 역시나 메소드 호출에 있겠다. 정확히 말해서 옵씨는 '메소드 호출'이라는 말을 사용하지 않고 '메시지를 던진다' 라고 표현하지만 겉으로 보기엔 거기서 거기니 따질 필요는 없다. ;-)
옵씨의 메시징은 아래와 같은 스타일이다.
다른 언어에 비해 특징적인 면이 있다면 파라미터(Parameter)는 반드시 필드 이름과 파라미터 내용으로 구성되어야 한다는 점이다. 사실 위의 코드는 한줄로 적어도 되지만, 이렇게 적으면 마치 무슨 데이터베이스의 레코드를 표현하는 느낌이다. 어쩔때는 마치 표(Table)를 그린다는 기분으로 코드를 작성 할 때도 있다.
이런 식의 코딩은 굉장히 귀찮을 수도 있지만, 적어도 나중에 코드를 감상(?) 할 때는 굉장히 도움이 된다. 그리고 상황에 따라서는 코드 만으로 넘겨야 할 타입을 확인 할 수 있으니 잘못된 포인터를 넘겨버리는 실수를 방지하기에도 도움이 된다.
들여쓰기 모양에 관해 생각해보자. XCode에서 코딩 할 때 엔터키를 잘 활용(?)하면 위와 같은 형식으로 들여쓰시가 자동으로 된다. 이 모양에서 느껴지는 점이 있을까? 콜론(:)을 기준으로 예쁘게 정렬하는데 이런 식의 코드도 옵씨만의 특징일 것이다.
콜백이냐 추상클래스냐 셀렉터냐
Cocoa에서도 종종 자주 사용되는 것이 @selector 를 이용해 셀렉터를 C 의 콜백(callback) 스타일로 등록하는 것이다. C++이나 Java에서는 구경하기 힘든(?) 방식인데, 특정 클래스 오브젝트의 메소드를 콜백으로 등록 할 수 있다.
이런 콜백 등록 방식은 C에서는 쉽게 볼 수 있는 패턴이었지만 대부분의 OOP 언어에서는 잘 볼 수 없는 패턴같다. 왜냐하면 OOP에서는 콜백 형태 보다는 추상클래스(Abstraction Class) 패턴을 많이 사용하니깐.
물론 옵씨도 추상화 비슷하게 인터페이스만 구현 해 두는 방법이 있다. 프로토콜(protocol)이라는 녀석이다. 이 프로토콜에 등록한 셀렉터는 required냐 optional 이냐에 따라 구현하지 않으면 warning이 발생한다. 참 느슨한 컴파일러다. ;-)
옵씨의 셀렉터 관리는 느슨하다. 셀렉터(메소드)를 문자열을 이용해서도 호출하는 것이 가능하다. 이는 내부에서 셀렉터를 문자열로 관리하는 체계가 있어서 가능한거고 그래서 C나 C++에 비해서 좀 느리다. 그래도 요즘 시스템에선 크게 신경 쓸 정도로 느린건 아니다.
뭔가 동적인 언어삘
최상위 클래스인 NSObject에는 respondsToSelector 라는 메시지(메소드)가 정의되어 있다. 이 녀석은 해당 메소드가 현재 오브젝트에서 제공되는지를 확인 할 수 있게 해 준다. 앞서 protocol을 이용한 추상화(?)에 대한 이야기에서 optional 메소드는 이 녀석을 이용해 있으면 실행하고 없으면 말고 식의 구현이 가능하다. 이건 마치 유연한 스크립트 언어스러운 구현이 가능해진다는 말이다.
다른 것으로 동적으로 클래스 타입을 구분 할 수 있다는 점이 있다. 역시 NSObject에 구현되어 있는 isKindOfClass 라는 메소드와 class 라는 메소드가 있다. 앞의 것은 클래스 타입을 판단하기 위한 메소드이고 뒤의 것은 클래스 타입을 알려주는 메소드이다. 역시나 유연한 스크립트 언어를 연상시키는 메소드다.
멤버 프로퍼티
앞서 프로퍼티라는 용어에 대해 이야기 했는데, 옵씨가 2.0으로 발전하면서 부터 이런 프로퍼티 선언(멤버 변수)이 굉장히 단순화 되고 있다.
이전같으면 synthesize라 불리우는 패턴을 통해 일일이 실제 멤버 변수와 프로퍼티 사이를 연결해 주어야 했지만, 이제는 프로퍼티 자체가 자동으로 멤버 변수가 되는 세상이 왔다.
더구나 각 프로퍼티는 readonly이냐 아니면 기타 메모리 관리가 필요하냐 등을 알려 줄 수 있다. 자바나 C++이었다면 일일이 getter, setter를 만들어 가며 이런 규칙을 정리했을 텐데 옵씨는 그저 프로퍼티 문법으로 이것을 해결해 버린다. 친절하다.
결론적으로 멤버의 setter/getter 정의와 함께 retain 방식이나 메모리 관리, 크리티컬 섹션 등을 한 방에 정의할 수 있다는 놀라운 결론이 나온다. -_-;
retain과 release는 어떻게 보면 축복이다
옵씨가 가장 욕을 많이 먹는 부분이 있다면 바로 이 리테인 카운트(retain count)와 관련된 메모리 관리분야 일 것이다.
사실 C방식(alloc/free)에서 뻗어나온 단조로운 방식이 이해가 잘 되는건 사실이다. 그리고 자바나 스크립트 언어 같이 아예 관리 할 필요가 없는 것은 축복에 가깝다.
하지만 옵씨는 불편하다. 그런데 이 불편함은 어느 정도의 편리성과 어느 정도의 퍼포먼스 향상, 그리고 어느 정도의 효율성을 가져오기도 한다.
retain과 release를 이용한 메모리 관리는 결국 메모리를 내가 쓸 것이니 침 바르는 것 혹은 다 썼으니 침 닦아내는 표현이다. 메모리에 침이 안묻어 있으면 컴퓨터가 낼롬 가져가 버린다. 그래서 누군가 써야 할 것이 멋대로 사라지는(free) 경우는 없다.
요즘은 ARC(Auto Reference Counting)라는게 도입되어서 크게 신경 쓸 것은 없지만, ARC 하에서도 침 바르는 행위는 여전히 유효하다.
맥(OS X)과 iOS를 위한 언어
불행히도 옵씨가 빛을 제대로 보지 못 하는 건 아무래도 옵씨를 쓸 분야가 한정되어 있기 때문일 것이다. 바이너리 컴파일 방식의 빠른 결과물을 만들어 내는 언어이면서도 스크립트 언어에 한발짝 다가선 편리한 문법들이 있으면서도 인기가 없다.
이게 장점이라고는 말 할 수 없을 것이다. 좀 더 많은 곳에서 옵씨를 쓸 수 있다면 좋긴 하겠는데...
그런데 이런 특징으로 두 OS 사이를 서로 쳐다볼 때 서로를 잘 이해할 수 있는 환경이 되었다. 즉 OS X 앱 개발자는 iOS 앱 개발에 쉽게 접근이 가능하고, 반대로 iOS 앱 개발자도 OS X용 앱 개발 접근성이 쉬운 편이다. (이건 프레임워크 구조가 비슷해서 가능한 것이기도 하지만...)
짜증나게 왜 세세하게 클래스를 나눈 거냐!
이건 불만에 가까운 부분이긴 하지만 어쨌든 옵씨의 특징으로 보자. 사실 맥 환경에서만 쓰이기 때문에 이런 불만이 나올 수 있긴 하겠지만...
에 그러니까 한가지 예를 들자. 날짜와 시간을 저장하는 클래스로 NSDate 라는게 있다. 그런데 여기서 년 월 일 시 분 초 등 구성 요소를 하나하나 뽑아내려면 NSCalendar 라던가 NSDateComponent 등등 다른 클래스를 함께 끌어다 써야 한다.
하지만 Python 같은 경우는 datetime 내의 year/month/day 기타 등등의 멤버를 활용해서 쉽게 뽑아낼 수 있다.
왜 이렇게 복잡하게 만든거냐!
(물론 이유는 있을 것이다. NSCalendar만 봐도 지역화에 초점을 맞추고 있음을 알 수 있다. 그래도 불편한 것은 불편한 것...)
자동완성이 없으면 으악
사실상 옵씨는 XCode가 없으면 코딩이 너무 어려운 언어이다. 왜냐하면 자동완성이 필수이기 때문이다.
다른 언어들에 비해 옵씨가 가지는 특이성은 위에서도 이야기 했지만 각 필드의 이름을 명시해 주어야 한다. 필드의 이름도 메소드 이름에 포함되기 때문이다.
그래서 코딩 시 만약 자동완성이 되지 않는다면 메소드 호출 시 불편을 각오해야 한다. 기억하고 있다면 상관은 없겠지만 다수의 필드를 요구하는 메소드 필드명이 기억나지 않는다면 결국 그 메소드의 정의부(interface)를 뒤져봐야 한다.
내 생애 가장 발전이 빠른 언어?
이건 컴파일이 가능한 언어들에 한해서 생각해야 할 것 같지만, 어쨌든 옵씨는 내가 볼 때 발전이 가장 눈부신 언어 같다.
ARC의 도입이나 멤버 프로퍼티 선언의 간결화, 자바스크립트 스러운 블럭문법, 그리고 수 많은 오브젝트 타입의 네이티브 언어화가 있다. (다르게 생각한다면 불편한 점을 그나마 덜 불편하게 고친 것일지도...)
물론 C도 내 생애에서 엄청나게 많은 변화가 있었다. C++도 그렇다. Python은 무려 Python3로 오면서 많이 변하고 있다. 하지만 이 언어는 거의 안쓰고 있는 입장이다보니 관심도 사라져간다. 발전이라고 느끼려면 역시 해당 언어를 많이 써 봐야 할 것이다.
끝
한가지 걸고 넘어갈게 있다. 위에 이야기 한 특징들은 옵씨만이 가지고 있는 능력 이런 의미가 아니다. 다른 언어에서도 비슷한 특징이 있을 수도 있다. 그냥 옵씨는 요렇다 라는 걸로 넘어가자. X-D
이하 Objective-C는 한글로 '옵씨'로 줄여서 표현한다. 그리고 옵씨에 대한 설명이 아니다 보니 옵씨를 이제 시작하는 분들에게는 별 의미 없는 글일 것 같다.
컴파일이 가능한 언어!
요즘 들어서는 스크립트 언어들이 유명세를 타고 있긴 하다. 별도의 빌드 과정이 필요 없으며 (물론 일부는 바이트컴파일을 알아서 하기도 하지만) 코딩 자체가 많이 간단해지도 복잡한 코드도 간단한 문법으로 쓸 수가 있다.
하지만 이에 비해서 컴파일로 네이티브 코드를 만들어 내는 언어 만의 특징이 있다. 빠르다. 이것 뿐일지도... -_-;;;
옵씨는 C나 C++에 비해 뭔가 스크립트 언어스러운 점을 조금은 가지고 있는 언어다. 그런 의미에서 이런 언어가 네이티브 코드로 빌드가 가능하다는 점은 장점에 장점을 더하게 되는 셈이기도 하다.
어색한 용어들
옵씨의 용어는 다른 언어에 비해 어색한 편이다. 대표적으로 셀렉터(selector) 라던가 메시지(message) 라는게 있다.
셀렉터 라는건 '메소드 이름'이라고 보면 된다. 하지만 이 셀렉터를 표현하는 문법 자체가 다른 언어와는 획일적으로 다르다. (아래 항목에서 이어진다)
옵씨에서는 메소드 호출(call)을 '메시지를 보낸다' 라고 한다. 클래스 인스턴스에게 메시지를 보내면 그 클래스가 알아서 하고 나중에 결과를 알려준다는 의미로 이해하면 되는걸까? 덕분에 실제로 존재하지 않는 nil 인스턴스에게도 메시지를 보낼 수 있다.
하지만 메시지 동작은 일반적인 메소드 방식과 겉으로 보기엔 큰 차이가 없다.
프로퍼티(property)라는 표현은 생각보다 어색하지는 않다. 아니 오히려 이해가 잘 되는 표현 같다. 멤버 변수라는 표현 보다는 프로퍼티라는 표현이 더 적절하다고 느낄 때가 많다.
직관적인(?) 메소드 호출
가장 옵씨 다운 점이라면 역시나 메소드 호출에 있겠다. 정확히 말해서 옵씨는 '메소드 호출'이라는 말을 사용하지 않고 '메시지를 던진다' 라고 표현하지만 겉으로 보기엔 거기서 거기니 따질 필요는 없다. ;-)
옵씨의 메시징은 아래와 같은 스타일이다.
Human *guy = [[Human alloc] initWithName:@"Byontae" gender:kMale age:18 andPartner:nil];이 코드는 실제로 작동하는 예제가 아니라 메소드 호출의 형식과 들여쓰기(Indentation) 모양을 보여주기 위한 예제일 뿐이다. 결론적으로 Human 클래스 타입의 guy라는 인스턴스를 생성하는데 이름과 성별, 나이, 그리고 파트너 이름을 이용해 초기화를 한다는 의미이다.
다른 언어에 비해 특징적인 면이 있다면 파라미터(Parameter)는 반드시 필드 이름과 파라미터 내용으로 구성되어야 한다는 점이다. 사실 위의 코드는 한줄로 적어도 되지만, 이렇게 적으면 마치 무슨 데이터베이스의 레코드를 표현하는 느낌이다. 어쩔때는 마치 표(Table)를 그린다는 기분으로 코드를 작성 할 때도 있다.
이런 식의 코딩은 굉장히 귀찮을 수도 있지만, 적어도 나중에 코드를 감상(?) 할 때는 굉장히 도움이 된다. 그리고 상황에 따라서는 코드 만으로 넘겨야 할 타입을 확인 할 수 있으니 잘못된 포인터를 넘겨버리는 실수를 방지하기에도 도움이 된다.
들여쓰기 모양에 관해 생각해보자. XCode에서 코딩 할 때 엔터키를 잘 활용(?)하면 위와 같은 형식으로 들여쓰시가 자동으로 된다. 이 모양에서 느껴지는 점이 있을까? 콜론(:)을 기준으로 예쁘게 정렬하는데 이런 식의 코드도 옵씨만의 특징일 것이다.
콜백이냐 추상클래스냐 셀렉터냐
Cocoa에서도 종종 자주 사용되는 것이 @selector 를 이용해 셀렉터를 C 의 콜백(callback) 스타일로 등록하는 것이다. C++이나 Java에서는 구경하기 힘든(?) 방식인데, 특정 클래스 오브젝트의 메소드를 콜백으로 등록 할 수 있다.
이런 콜백 등록 방식은 C에서는 쉽게 볼 수 있는 패턴이었지만 대부분의 OOP 언어에서는 잘 볼 수 없는 패턴같다. 왜냐하면 OOP에서는 콜백 형태 보다는 추상클래스(Abstraction Class) 패턴을 많이 사용하니깐.
물론 옵씨도 추상화 비슷하게 인터페이스만 구현 해 두는 방법이 있다. 프로토콜(protocol)이라는 녀석이다. 이 프로토콜에 등록한 셀렉터는 required냐 optional 이냐에 따라 구현하지 않으면 warning이 발생한다. 참 느슨한 컴파일러다. ;-)
옵씨의 셀렉터 관리는 느슨하다. 셀렉터(메소드)를 문자열을 이용해서도 호출하는 것이 가능하다. 이는 내부에서 셀렉터를 문자열로 관리하는 체계가 있어서 가능한거고 그래서 C나 C++에 비해서 좀 느리다. 그래도 요즘 시스템에선 크게 신경 쓸 정도로 느린건 아니다.
뭔가 동적인 언어삘
최상위 클래스인 NSObject에는 respondsToSelector 라는 메시지(메소드)가 정의되어 있다. 이 녀석은 해당 메소드가 현재 오브젝트에서 제공되는지를 확인 할 수 있게 해 준다. 앞서 protocol을 이용한 추상화(?)에 대한 이야기에서 optional 메소드는 이 녀석을 이용해 있으면 실행하고 없으면 말고 식의 구현이 가능하다. 이건 마치 유연한 스크립트 언어스러운 구현이 가능해진다는 말이다.
다른 것으로 동적으로 클래스 타입을 구분 할 수 있다는 점이 있다. 역시 NSObject에 구현되어 있는 isKindOfClass 라는 메소드와 class 라는 메소드가 있다. 앞의 것은 클래스 타입을 판단하기 위한 메소드이고 뒤의 것은 클래스 타입을 알려주는 메소드이다. 역시나 유연한 스크립트 언어를 연상시키는 메소드다.
멤버 프로퍼티
앞서 프로퍼티라는 용어에 대해 이야기 했는데, 옵씨가 2.0으로 발전하면서 부터 이런 프로퍼티 선언(멤버 변수)이 굉장히 단순화 되고 있다.
이전같으면 synthesize라 불리우는 패턴을 통해 일일이 실제 멤버 변수와 프로퍼티 사이를 연결해 주어야 했지만, 이제는 프로퍼티 자체가 자동으로 멤버 변수가 되는 세상이 왔다.
더구나 각 프로퍼티는 readonly이냐 아니면 기타 메모리 관리가 필요하냐 등을 알려 줄 수 있다. 자바나 C++이었다면 일일이 getter, setter를 만들어 가며 이런 규칙을 정리했을 텐데 옵씨는 그저 프로퍼티 문법으로 이것을 해결해 버린다. 친절하다.
결론적으로 멤버의 setter/getter 정의와 함께 retain 방식이나 메모리 관리, 크리티컬 섹션 등을 한 방에 정의할 수 있다는 놀라운 결론이 나온다. -_-;
retain과 release는 어떻게 보면 축복이다
옵씨가 가장 욕을 많이 먹는 부분이 있다면 바로 이 리테인 카운트(retain count)와 관련된 메모리 관리분야 일 것이다.
사실 C방식(alloc/free)에서 뻗어나온 단조로운 방식이 이해가 잘 되는건 사실이다. 그리고 자바나 스크립트 언어 같이 아예 관리 할 필요가 없는 것은 축복에 가깝다.
하지만 옵씨는 불편하다. 그런데 이 불편함은 어느 정도의 편리성과 어느 정도의 퍼포먼스 향상, 그리고 어느 정도의 효율성을 가져오기도 한다.
retain과 release를 이용한 메모리 관리는 결국 메모리를 내가 쓸 것이니 침 바르는 것 혹은 다 썼으니 침 닦아내는 표현이다. 메모리에 침이 안묻어 있으면 컴퓨터가 낼롬 가져가 버린다. 그래서 누군가 써야 할 것이 멋대로 사라지는(free) 경우는 없다.
요즘은 ARC(Auto Reference Counting)라는게 도입되어서 크게 신경 쓸 것은 없지만, ARC 하에서도 침 바르는 행위는 여전히 유효하다.
맥(OS X)과 iOS를 위한 언어
불행히도 옵씨가 빛을 제대로 보지 못 하는 건 아무래도 옵씨를 쓸 분야가 한정되어 있기 때문일 것이다. 바이너리 컴파일 방식의 빠른 결과물을 만들어 내는 언어이면서도 스크립트 언어에 한발짝 다가선 편리한 문법들이 있으면서도 인기가 없다.
이게 장점이라고는 말 할 수 없을 것이다. 좀 더 많은 곳에서 옵씨를 쓸 수 있다면 좋긴 하겠는데...
그런데 이런 특징으로 두 OS 사이를 서로 쳐다볼 때 서로를 잘 이해할 수 있는 환경이 되었다. 즉 OS X 앱 개발자는 iOS 앱 개발에 쉽게 접근이 가능하고, 반대로 iOS 앱 개발자도 OS X용 앱 개발 접근성이 쉬운 편이다. (이건 프레임워크 구조가 비슷해서 가능한 것이기도 하지만...)
짜증나게 왜 세세하게 클래스를 나눈 거냐!
이건 불만에 가까운 부분이긴 하지만 어쨌든 옵씨의 특징으로 보자. 사실 맥 환경에서만 쓰이기 때문에 이런 불만이 나올 수 있긴 하겠지만...
에 그러니까 한가지 예를 들자. 날짜와 시간을 저장하는 클래스로 NSDate 라는게 있다. 그런데 여기서 년 월 일 시 분 초 등 구성 요소를 하나하나 뽑아내려면 NSCalendar 라던가 NSDateComponent 등등 다른 클래스를 함께 끌어다 써야 한다.
하지만 Python 같은 경우는 datetime 내의 year/month/day 기타 등등의 멤버를 활용해서 쉽게 뽑아낼 수 있다.
왜 이렇게 복잡하게 만든거냐!
(물론 이유는 있을 것이다. NSCalendar만 봐도 지역화에 초점을 맞추고 있음을 알 수 있다. 그래도 불편한 것은 불편한 것...)
자동완성이 없으면 으악
사실상 옵씨는 XCode가 없으면 코딩이 너무 어려운 언어이다. 왜냐하면 자동완성이 필수이기 때문이다.
다른 언어들에 비해 옵씨가 가지는 특이성은 위에서도 이야기 했지만 각 필드의 이름을 명시해 주어야 한다. 필드의 이름도 메소드 이름에 포함되기 때문이다.
그래서 코딩 시 만약 자동완성이 되지 않는다면 메소드 호출 시 불편을 각오해야 한다. 기억하고 있다면 상관은 없겠지만 다수의 필드를 요구하는 메소드 필드명이 기억나지 않는다면 결국 그 메소드의 정의부(interface)를 뒤져봐야 한다.
내 생애 가장 발전이 빠른 언어?
이건 컴파일이 가능한 언어들에 한해서 생각해야 할 것 같지만, 어쨌든 옵씨는 내가 볼 때 발전이 가장 눈부신 언어 같다.
ARC의 도입이나 멤버 프로퍼티 선언의 간결화, 자바스크립트 스러운 블럭문법, 그리고 수 많은 오브젝트 타입의 네이티브 언어화가 있다. (다르게 생각한다면 불편한 점을 그나마 덜 불편하게 고친 것일지도...)
물론 C도 내 생애에서 엄청나게 많은 변화가 있었다. C++도 그렇다. Python은 무려 Python3로 오면서 많이 변하고 있다. 하지만 이 언어는 거의 안쓰고 있는 입장이다보니 관심도 사라져간다. 발전이라고 느끼려면 역시 해당 언어를 많이 써 봐야 할 것이다.
끝
한가지 걸고 넘어갈게 있다. 위에 이야기 한 특징들은 옵씨만이 가지고 있는 능력 이런 의미가 아니다. 다른 언어에서도 비슷한 특징이 있을 수도 있다. 그냥 옵씨는 요렇다 라는 걸로 넘어가자. X-D
댓글