프로토타입 기반 프로그래밍
프로토타입 기반 프로그래밍은 객체지향 프로그래밍의 한 형태의 갈래로 클래스가 없고, 클래스 기반 언어에서 상속을 사용하는 것과는 다르게, 객체를 원형(프로토타입)으로 하여 복제의 과정을 통하여 객체의 동작 방식을 다시 사용할 수 있다. 프로토타입기반 프로그래밍은 클래스리스("class-less"), 프로토타입 지향(prototype-oriented) 혹은 인스턴스 기반(instance-based) 프로그래밍이라고도 한다.
프로토타입 기반 언어의 가장 원조격인 프로그래밍 언어인 셀프는 데이비드 엉거와 랜덜 스미스가 개발했다. 클래스리스 프로그래밍은 최근에 와서 많이 유명해졌는데, 자바스크립트와 모픽 프레임워크를 사용하는 스퀵에 적용되었고, 그 외에 세실, 뉴튼스크립트, 아이오, 무, 리볼, 케보 등에 적용되었다.(#프로토타입 기반 언어 목록 참고.)
클래스기반 언어에서 객체는 일반적으로 두 가지 형태가 있다. '클래스'는 객체의 기본적인 만듦새와 기능을 정의하고, '인스턴스'는 "사용할 수 있는" 객체로 특정 클래스의 양식을 기반으로 한다. 클래스기반 언어에서 '클래스'는 동작 방식인 메소드의 모임으로 동작하고, 모든 인스턴스의 구조는 동일하고, 인스턴스는 객체의 자료를 가지고 있다. 한쪽에는 구조와 동작 방식, 다른 한쪽에는 상태로 구분된다.
프로토타입 기반 프로그래밍을 지지하는 사람들은 클래스기반 언어에서는 개발자가 클래스들 사이의 분류와 관계에 먼저 초점을 맞추기 쉽다고 한다. 이와는 달리, 프로토타입기반 프로그래밍은 프로그래머가 여러 가지 표본의 동작 방식에 초점을 맞추고, 이 객체들을 나중에 클래스와 비슷한 방식의 "객체의 원형"으로 분류하는 것은 나중에 걱정해도 된다. 많은 프로토타입기반 체계가 실행시간에 프로토타입을 대체하기 쉬우나, 클래스기반 객체지향 체계에서는 최초의 동적 객체지향 체계인 스몰토크와 같이 프로그램의 실행 중에 클래스를 바꿀 수 있는 것은 몇 가지 되지 않는다.
프로토타입 기반 프로그래밍은, 학습의 과정의 주요한 특징으로 프로토타입이나 이그젬플러를 강조하는, 인지 심리학과 같은 특정 학문과 관련되어 있는 경우가 많다.
프로토타입 기반 체계의 대부분은 인터프리터이고 동적 타입 프로그래밍 언어이다. 하지만 프로토타입기반의 정적 타입의 체계가 기술적으로 가능하다. 오메가는 그런 체계의 한 예이다.
클래스기반 언어에서, 클래스의 생성자를 통하거나 필요하다면 생성자와 생성자의 매개변수를 통하여 인스턴스를 새로 만든다. 결과로 만들어진 인스턴스는 선택된 클래스의 설계와 행동을 따르게 된다.
프로토타입기반 체계에서, 새 객체를 만드는 두 가지 방법이 있다. 하나는 원래 있던 객체를 '복제(cloning)'하는 방법이고, 다른 하나는 '무(無)에서("ex nihilo")' 객체를 생성하는 방법이다. 대부분 다양한 복제 방식을 제공하기 때문에, "무에서" 객체를 생성하는 것은 흔하지 않다.
"무에서" 객체를 생성할 수 있는 체계는 이미 있던 프로토타입을 복제하지 않고 아무것도 없는 상태에서 새로운 객체를 생성할 수 있게 해 준다. 이런 체계는 새 객체의 특성과 행동을 이미 있던 객체를 참조하지 않고도 지정할 수 있다. 많은 프로토타입기반 언어에서 기본 객체 프로토타입인 "codice_1" 프로토타입이 있는데, 여기에 공통적으로 필요한 메서드가 들어있고, 모든 객체의 마스터 프로토타입으로 사용된다. "무에서" 객체를 창조하는 방식의 유용한 한 가지는 새 객체의 슬롯 이름이 최상위의 "codice_1" 객체와 네임스페이스 충돌이 일어나지 않는다는 것이다. 모질라 자바스크립트는 객체의 "codice_3" 프로퍼티를 codice_4로 지정하면 이것이 가능하도록 구현되어 있다.
'복제'는 원래 있던 객체의 프로토타입의 행동을 복제하여 새 객체를 생성하는 과정을 거친다. 새 객체는 원본의 모든 특성을 가진다. 이 상태에서 새 객체를 수정할 수 있다. 어떤 체계에서 복제된 자식 객체는 명시적으로 프로토타입과 '위임'(delegation)이나 '닮음'(resemblance)으로 연관되어 있다. 그래서 프로토타입을 변경하면 복제품에 영향을 끼친다. 포스와 케보 같은 다른 체계에서는 프로토타입을 번식시키는 이런 방식을 따르지 않고, 대신에 프로토타입을 수정하더라도 복제품에는 영향을 끼치지 않는 "연쇄된" 형태를 사용하여 원본 객체를 수정하더라도 그 자손으로 자동 번식되지 않는다.
실행시간에 '위임'하는 프로토타입기반의 언어들은 올바른 메서드로 동적 디스패치를 할 수 있거나, 맞는 자료 조각에 이를 때까지 객체에서 프로토타입으로 간단히 위임 포인터를 연속적으로 따라가서 찾을 수 있다. 객체들 사이에서 동작을 공유하는 것을 확립하기 위해 필요한 것들은 위임 포인터뿐이다. 클래스기반 객체지향 언어에서 클래스와 인스턴스의 관계와 달리 프로토타입과 파생된 객체는 이 연결을 통하여 프로토타입과 자식 객체가 메모리나 구조적인 유사성을 가질 필요가 없다. 마찬가지로, 자식 객체는 클래스 기반의 연관된 클래스의 구조를 재배치하지 않고 계속해서 수정할 수 있다. 또 중요한 점은, 자료뿐만 아니라 메서드도 추가되거나 변경될 수 있다는 것이다. 이런 이유로 대부분의 프로토타입기반 언어들은 자료와 메서드 두가지 모두 슬롯으로 관리한다.
순수 프로토타입은 '연쇄적' 프로토타입이라고도 하는데 케보가 그 예이다. 원본 프로토타입에서 복제된 객체로 포인터는 보이지 않는다. 프로토타입 객체는 정확히 복사되지만, 다른 이름이나 참조값을 갖는다. 이 과정은 생물학적인 미토시스와 비교할 수 있다. 메서드와 속성은 대응되는 것으로 중복된다.
이렇게 접근하면 객체 작성자가 한 부모 객체의 자식 객체들간에 부수효과를 신경쓰지 않고 복제할 수 있다는 이점이 있다. 또 다른 이점은, 디스패치 중 메서드 미리보기의 계산 비용이 위임에 비해서 급격히 줄어든다는 것이다. 위임을 하면 적합한 메서드나 슬롯을 찾는 것을 실패한다면 전체 위임 사슬에서 찾아봐야 하기 때문이다.
연쇄 접근 방식의 단점은 시스템을 통해 바뀌는 것을 번식시키는 데에 조직적으로 어렵다는 것이다. 프로토타입에 변화가 생기면 이것은 복제품에 즉시 혹은 자동적으로 적용되지 않는다. 그러나 케보는 위임 방식에서 주로 쓰는 분류상의 원형을 사용하지 않고, 추가적인 기본형을 제공하여 '가족 닮음'(family reseemblances)라고 하는 유사한 객체들을 모아서 변화를 적용한다.
다른 단점은 이 형태를 세련되게 구현하지 못하면 원형과 복제품이 같은 부분에서 복제품들이 위임 형태에 비해서 메모리가 더 많이 낭비된다는 것이다. 그러나 케보에서 실제로 하고 있는 접근 방식처럼 공유하도록 구현하고 자료는 배후에 두는 방식으로 프로그래밍에 대한 연쇄적 행동이 가능하다.
프로토타입기반 시스템을 비판하고 클래스기반 객체 모델을 지지하는 사람들은 프로그래밍 언어의 정적 타입 시스템을 지지하는 사람들이 동적 타입 시스템에 대하여 우려하는 것과 비슷한 점을 우려하고 있다(자료형 참조). 특히, 프로그램의 정확성, 안전성, 예측성, 효율을 떨어뜨린다고 우려한다.
정확성, 안전성, 예측성의 관점에서 보면, 클래스는 타입과 비슷하며, 실제로 대부분의 정적 타입 객체지향 언어에서 클래스는 타입의 역할을 한다. 그리고 클래스의 인스턴스는 주어진 방식대로 동작하리라는 확실한 보장이 된다.
효율성의 관점에서 보면, 클래스를 선언하면 대부분의 컴파일러는 더 효율적인 메서드와 인스턴스 변수 미리보기가 가능하여 최적화하기 쉽게 된다. 셀프 (프로그래밍 언어)에서 보면, 클래스기반에 비해서 프로토타입 기반 체계는 수행 속도를 빠르게 하는 컴파일과 인터프리트 기술을 개발하는 데 많은 시간이 걸린다. 예를 들어 리삭 컴파일러는 C만큼이나 빨리 코드를 만든다. 테스트는 C 버전에서 복사한 리삭으로 작성된 MPEG-2 코덱으로 하였다. 이 테스트 결과로 리삭 버전이 C 버전보다 1.9% 속도가 느리지만 37%만큼 줄 수가 적었다.
마지막으로, 비록 자바스크립트와 같은 언어들이 유명세를 떨치고, 시장에 침투하고 있지만 프로토타입기반 언어가 소프트웨어 개발자들 사이에서 익숙하지 않아서 때문에 많은 비판을 받는다. 그래서 ECMA스크립트 표준의 4번째판이 자바스크립트를 클래스기반 언어로 만들려고 하고 있다. 게다가 프로토타입기반 체계가 상대적으로 기발하고 별로 사용되지 않고 있으며, 소프트웨어를 개발할 때 널리 퍼지지 못하여 최고관행과 멀기 때문이다.