자료형(Data Types)
- 데이터 타입은 동일한 유형의 값(value)과 조작할 값에 적용할 수 있는 연산자(operation) 집합이다.
- 동종(homogeneous) : 같거나 유사한 종류(↔ 이종).
- 값 + 연산자 : 데이터 타입은 값에 관한 것뿐만 아니라 연산도 포함된다.
- 예) 정수, 문자열, 배열에 대해 서로 다른 연산이 필요하다.
타입 시스템(Type System)
- 프로그래밍 언어에는 데이터 유형을 관리하기 위한 자체 타입 시스템(정보 및 규칙)이 있다.
- 타입 시스템은 일반적으로 다음으로 구성된다.
- 미리 정의된 타입의 세트
- 새로운 타입의 정의를 지원하는 메커니즘
- 동등성 규칙(equivalence rules), 호환성 규칙(compatibility), 타입 추론(type inference)과 같은 타입을 제어하는 메커니즘.
표시 가능(Denotable), 표현 가능(Expressible), 저장 가능(Storable)
- 표시 가능(Denotable) : 우리가 이름을 붙일 수 있는 경우
- 변수(이름), 함수(이름)
- 표현 가능(Expressible) : 복잡한 표현식에서 얻을 수 있는 경우
- 숫자, 문자열, 심지어 C의 메모리 위치까지 표현식에 나타날 수 있다.
- 저장 가능(Storable) : 변수에 저장할 수 있는 경우
- 변수 vs 함수 : 함수의 코드 조각이 디스크에 저장되어 있지만 프로그램에서 업데이트할 수는 없다.
정적 및 동적 타입 검사
- 동적 타입 검사 : 런타임 중에 타입 제약 조건을 검사
- 정적 타입 검사 : 컴파일 시간에 타입 제약 조건을 검사
- 런타임 타입 검사가 없다. : 실행이 더 효율적이다.
- 정적 타입 검사 설계는 더 복잡하고 컴파일 시간도 더 오래 걸린다.
- 그러나 컴파일은 몇 번만 발생하는 반면 실행은 자주 발생한다.
- 정적 타입 검사에는 보수적인 타입 제약 조건이 필요히다.
- 런타임 시 발생하지 않는 일부 오류를 보고한다.
- 예) 예제 코드에서 x = "PL"은 타입 제약 조건을 위반한다.
- 그러나 이 코드는 런타임 중에 실행되지 않는다.
- 프로그램이 타입 오류를 발생시키는지 여부를 결정하는 것은 결정할 수 없기 때문이다.
int x = 0;
if(x > 0)
x = "PL";
x = 1+2;
타입 검사 조합의 필요성
- 거의 모든 고급 프로그래밍 언어는 정적 및 동적 타입 검사를 모두 수행한다.
- 언어는 정적 타입 검사를 사용하지만 경우에 따라 동적 검사가 필요하다.
- 예) 배열 인덱스 바운드 검사
- 배열의 크기가 동적으로 결정되는 경우 해당 인덱스 경계에 대한 확인도 동적이어야 한다.
스칼라 및 복합 타입
- 스칼라 타입 : 서로 다른 값을 집계하지 않는다.
- 부울, 문자, 정수, 실수.
- 열거(Enumerations)
- type days = { Mon,Tue,Wed,Thu,Fri,Sat,Sun }
- 간격 : 1~10
- 복합 타입 : 비스칼라 타입
- 레코드(또는 구조), 배열(또는 벡터), 세트, 포인터, 함수, 재귀 타입 등
- 이러한 타입에는 다른 작업이 있을 수 있다.
타입 동등성(Type Equivalence)
- 이름 동등성(Name Equivalence) : 이름이 동일하면 두 타입이 동일하다.
- 구조 동등성(Structural Equivalence) : 구조가 동일하면 두 타입이 동일하다.
- 선언 동등성(Declaration Equivalence) : 함께 선언되면 두 타입이 동일하다.
- 참조 투명성 : 프로그램의 의미를 변경하지 않고 어떤 상황에서든 두 개의 동등한 타입을 서로 대체할 수 있다.
- 현대 언어에서는 예외를 제외하고 규칙 중 하나를 사용하는 경우가 많다.
이름 동등성
- 타입 정의를 위해 의사 언어(pseudo)를 사용
type <type_name> = <expression>;
type Type1 = int;
type Type2 = int;
type Type3 = 1..100;
type Type4 = 1..100;
- 이름 동등성은 매우 제한적인 규칙이다.
- 위의 모든 타입이 다르다.
- Java, C++는 대부분의 타입에 대해 이름 동등성을 사용한다.
구조 동등성
- 두 타입이 동일한 구조를 갖는 경우 동일하다.
- 더 느슨한 제약 조건
type Type1 = int;
type Type2 = int;
type Type3 = 1..100;
type Type4 = 1..100;
- Type1/Type2는 동일하고 Type3/Type4는 동일하다.
- Java 배열, C 배열, typedef.
- 모호한 경우가 있다.
- 다른 필드 이름
type Type1 = struct {
int a;
int b;
}
type Type2 = struct {
int n;
int m;
}
- Type1/Type2가 동일한가?
- 언어에 따라 다르지만 다른 필드 이름은 다른 것으로 간주된다.
- 재귀 타입
type Type1 = struct {
int a;
Type2 b;
}
type Type2 = struct {
int a;
Type1 b;
}
- Type1/Type2는 동일한가?
- 타입 검사는 이러한 상호 재귀를 해결할 수 없으므로 다른 것으로 간주된다.
선언 동등성
- 이름과 구조적 동등성의 중간에 있다.
- 약한 이름 동등성 : 고려 타입은 간단한 이름 바꾸기 또는 함께 선언된 경우(예: Pascal)와 동일하다.
type Type1 = int;
type Type2 = Type1;
type Type3 = 1..100;
type Type4 = 1..100;
- Type1/Type2는 동일하지만 Type3/Type4는 여전히 다르다.
타입 호환성(Type Compatibility)
- 타입 T의 값이 타입 S의 값이 사용되는 모든 컨텍스트에서 사용될 수 있는 경우 타입 T는 타입 S와 호환된다.
- 보다 구체적으로, 타입 T와 S는 다음과 같은 경우에 호환된다.
- T형과 S형은 동일하다.
- 참조 투명성
- 참조 투명성
- T의 값은 S의 값의 하위 집합이다.
- 간격 1..10, 1..100.
- 간격 1..10, 1..100.
- S의 모든 연산은 T에 적용될 수 있다.
- type S = struct { int a; }
- type T = struct { int a; char b; }
- S의 가능한 작업은 필드 a에 액세스하는 것뿐이다.
- T⊄S, 그러나 T의 a만을 취해 S의 연산을 적용할 수 있다.
- T의 값은 정식 방식으로 S의 값에 대응된다.
- T : 정수
- S : 부동 소수점
- T는 S의 하위 집합이 아니지만 float에 int를 사용할 수 있습니다(예: 2.0의 경우 2).
- T의 값은 변환을 통해 S의 값으로 변환될 수 있다.
- float는 반올림(예: C에서 반올림)을 통해 int로 변환될 수 있다.
타입형 변환(Type Conversion)
- 암시적 변환(강제) (Implicit Conversion(coercion))
- 강제 변환이라고도 한다. 타입 변환은 컴파일러에 의해 수행된다.
- T와 S 유형이 호환되면 프로그래머가 지정하지 않은 경우에도 자동으로 변환이 수행된다.
- 명시적 변환(캐스트) (Explicit Conversion (cast))
- 프로그래머는 타입 변환을 명시적으로 나타낸다.
- S s = (S) t;
업 캐스팅 vs. 다운 캐스팅
- 상속된 클래스 간의 캐스팅이 가능할 수 있다.
- 업 캐스팅(Upcasting) : 자식을 부모로 변환
- 암시적 변환이 가능하다.
- 예) Parent p = new Child();
- 다운 캐스팅(Downcasting) : 부모를 자식으로 변환
- 명시적인 변환이 필요히다.
- 예) Child c = (Child) p;
타입 확인 및 추론
- 타입 검사(Type Checking) : E라는 표현식과 T 타입이 주어졌을 때 E가 T 타입인지 확인
- int f(int a) { return a+1; }
- a+1은 정수여야 한다.
- 타입 추론(Type Inference) : E라는 표현식만 주어지면 E의 타입을 파생시킨다.
- def f(a): return a+1
- 1은 int이고 +는 두 개의 정수를 취하므로 a는 int여야 하며 함수 f()는 int->int입니다.
타입 안전성(Type Safety)
- 이러한 모든 타입 검사 및 추론은 언어의 타입 안전성을 확보하기 위한 것이다.
- 타입 시스템(또는 언어)은 어떤 프로그램도 언어에 정의된 타입 구별을 위반할 수 없을 때 타입이 안전하다.
- 이론적으로 타입 안전성은 생각보다 더 제한적이다.
- 안전하지 않은 언어 : C, C++와 같이 메모리에 직접 액세스하기 위한 포인터가 있는 언어(메모리 안전 문제)
- 지역적으로 안전한 언어 : 일부 언어(예: Pascal)에는 안전하지 않은 부분이 포함되어 있다.
- 안전한 언어 : 이론적으로 이러한 언어는 숨겨진 유형 오류(예: Scheme, ML, Java)를 생성하지 않는다.
'프로그래밍언어론' 카테고리의 다른 글
[프로그래밍언어론] 29. 스크립팅 언어(Scripting Languages) (0) | 2023.11.06 |
---|---|
[프로그래밍언어론] 28. 프로그래밍 언어 패러다임(PL Paradigm) (0) | 2023.11.06 |
[프로그래밍언어론] 26. 바인딩 정책(Binding Policy) (1) | 2023.10.17 |
[프로그래밍언어론] 25. 매개변수 전달(Parameter Passing) (1) | 2023.10.17 |
[프로그래밍언어론] 24. 컨트롤 추상화(Control Abstraction) (0) | 2023.10.17 |