타입과 클래스를 구별 한 다음 서브 타이핑과 서브 클래 싱의 차이점을 살펴 보는 것이 가장 유용 할 것입니다.
이 답변의 나머지 부분에서는 논의중인 유형이 정적 유형이라고 가정합니다 (하위 유형 지정은 일반적으로 정적 컨텍스트에 있기 때문에).
나는 대부분의 언어가 적어도 부분적으로 어렴풋이 있기 때문에 유형과 클래스의 차이점을 설명하기 위해 장난감 의사 코드를 개발할 것입니다.
유형부터 시작하겠습니다. 유형은 코드에서 표현식의 레이블입니다. 이 레이블의 값과 다른 모든 레이블 값과 일치하는지 (일부 유형 시스템 고유의 일관성에 대한 여부)는 프로그램을 실행하지 않고 외부 프로그램 (유형 검사기)에 의해 결정될 수 있습니다. 이것이 바로이 라벨이 자신의 이름을 특별하고 가치있게 만드는 이유입니다.
장난감 언어로 라벨을 만들 수 있습니다.
declare type Int
declare type String
그런 다음 다양한 값을이 유형으로 레이블링 할 수 있습니다.
0 is of type Int
1 is of type Int
-1 is of type Int
...
"" is of type String
"a" is of type String
"b" is of type String
...
이러한 문장으로 타입 체커는 이제 다음과 같은 문장을 거부 할 수 있습니다.
0 is of type String
형식 시스템의 요구 사항 중 하나가 모든 식에 고유 한 형식이 있어야한다는 것입니다.
이제 얼마나 복잡한 지, 그리고 무한한 수의 표현식 유형을 할당하는 데 문제가있는 방법은 따로 두십시오. 나중에 다시 돌아올 수 있습니다.
반면에 클래스는 함께 그룹화되는 메소드 및 필드의 모음입니다 (잠재적으로는 개인 또는 공용과 같은 액세스 수정 자와 함께).
class StringClass:
defMethod concatenate(otherString): ...
defField size: ...
이 클래스의 인스턴스는 이러한 메소드 및 필드의 기존 정의를 작성하거나 사용할 수 있습니다.
클래스의 모든 인스턴스가 해당 유형으로 자동 레이블 지정되도록 클래스를 유형과 연관시킬 수 있습니다.
associate StringClass with String
그러나 모든 유형에 관련 클래스가 필요한 것은 아닙니다.
# Hmm... Doesn't look like there's a class for Int
또한 장난감 언어에서 모든 클래스에 유형이있는 것은 아니며, 특히 모든 표현에 유형이있는 것은 아닙니다. 일부 표현식에 유형이 있고 일부는 그렇지 않은 경우 어떤 유형 시스템 일관성 규칙이 표시 될지 상상하기가 다소 까다 롭지 만 불가능하지는 않습니다.
또한 우리의 장난감 언어에서 이러한 연관성은 고유하지 않아도됩니다. 두 클래스를 같은 유형으로 연결할 수 있습니다.
associate MyCustomStringClass with String
이제 타입 체커가 표현식의 값을 추적 할 필요는 없습니다 (대부분의 경우 그렇게하지 않거나 불가능합니다). 당신이 알고있는 레이블 만 알고 있습니다. 이전에 상기 한 바와 같이 타입 체커는 0 is of type String
인위적으로 생성 된 타입 규칙으로 인해 표현식에 고유 한 유형이 있어야하고 이미 0
다른 식에 레이블을 지정 했으므로 명령문을 거부 할 수있었습니다 . 의 가치에 대한 특별한 지식이 없었습니다 0
.
서브 타이핑은 어떻습니까? 음의 하위 유형은 유형 검사에서 일반적인 규칙의 이름으로 다른 규칙을 완화합니다. 즉, A is subtype of B
모든 유형 검사기에서 라벨을 요구하는 모든 곳 B
에서 A
.
예를 들어 이전에 사용했던 숫자 대신 다음과 같은 숫자를 사용할 수 있습니다.
declare type NaturalNum
declare type Int
NaturalNum is subtype of Int
0 is of type NaturalNum
1 is of type NaturalNum
-1 is of type Int
...
서브 클래 싱은 이전에 선언 된 메소드와 필드를 재사용 할 수있는 새 클래스를 선언하기위한 축약입니다.
class ExtendedStringClass is subclass of StringClass:
# We get concatenate and size for free!
def addQuestionMark: ...
우리의 동료 인스턴스가 없습니다 ExtendedStringClass
에 String
우리가했던 것처럼 StringClass
그것은 완전히 새로운 클래스의 모든 후, 이후, 우리는 단지만큼 작성하지 않았다. 이를 통해 ExtendedStringClass
타입 String
체커의 관점에서 호환되지 않는 타입 을 제공 할 수 있습니다.
마찬가지로 우리는 완전히 새로운 클래스를 만들하기로 결정했습니다 수 NewClass
및 수행
associate NewClass with String
이제 타입 체커의 관점에서 모든 인스턴스를 StringClass
대체 할 수 있습니다 NewClass
.
이론적으로 서브 타이핑과 서브 클래 싱은 완전히 다릅니다. 그러나 내가 아는 언어에는 유형과 클래스가 실제로 이런 식으로 작동합니다. 우리의 언어를 분석하고 우리의 결정에 대한 근거를 설명합시다.
첫째, 이론상 완전히 다른 클래스에 동일한 유형이 주어 지거나 클래스에 다른 클래스의 인스턴스가 아닌 값과 동일한 유형이 주어질 수 있지만 이것은 유형 검사기의 유용성을 심각하게 저해합니다. 타입 체커는 표현식 내에서 호출하는 메소드 또는 필드가 실제로 해당 값에 있는지 여부를 확인하는 기능을 효과적으로 강탈합니다. 이는 아마도 유형 검사기. 결국, 그 String
레이블 아래에 실제로있는 값이 무엇인지 아는 사람 ; 예를 들어 concatenate
방법 이 전혀없는 것일 수 있습니다 !
자, 모든 클래스가 자동으로 해당 클래스와 동일한 이름의 새로운 유형을 생성하고 associate
해당 유형의 인스턴스를 생성하도록 규정하겠습니다 . 이를 통해 와 associate
사이의 다른 이름을 제거 할 수 있습니다 .StringClass
String
같은 이유로, 두 클래스의 유형 사이에 하위 유형 관계를 자동으로 설정하려고합니다. 하나는 다른 클래스의 하위 클래스입니다. 모든 서브 클래스는 부모 클래스가하는 모든 메소드와 필드를 갖도록 보장되지만 그 반대는 사실이 아닙니다. 따라서 서브 클래스가 상위 클래스의 유형이 필요할 때마다 전달할 수 있지만 서브 클래스의 유형이 필요한 경우 상위 클래스의 유형이 거부되어야합니다.
이것을 모든 사용자 정의 값이 클래스의 인스턴스 여야한다는 규정과 결합하면 is subclass of
이중 의무를 제거하고를 제거 할 수 있습니다 is subtype of
.
그리고 이것은 우리에게 인기있는 정적으로 유형화 된 OO 언어의 대부분이 공유하는 특성을 우리에게 알려줍니다. "원시"유형 (예를 들어 일련의 존재 int
, float
모든 클래스와 연관되지 않으며 사용자 정의하지되는 등). 그런 다음 동일한 이름의 유형을 자동으로 가지며 하위 유형을 지정하여 하위 클래스를 식별하는 모든 사용자 정의 클래스가 있습니다.
마지막으로 메모 할 내용은 값과 별도로 형식을 선언하는 어리 석음입니다. 대부분의 언어는 두 언어의 작성을 혼동하므로 형식 선언은 해당 형식으로 자동 레이블이 지정된 완전히 새로운 값을 생성하기위한 선언이기도합니다. 예를 들어, 클래스 선언은 일반적으로 형식과 해당 형식의 값을 인스턴스화하는 방법을 모두 만듭니다. 이것은 약간의 혼란을 없애고 생성자가있는 경우 한 번의 입력으로 유형이 많은 레이블을 무한대로 만들 수 있습니다.