PL 타입시스템(4)
강한/약한 타입 언어, 정적/동적 타입 언어의 특징과 차이점, 대표적인 언어 예시(Java, C, Python, JavaScript), 안전한 타입 시스템의 개념, 그리고 언어 S의 타입 시스템 구현에 대해 설명합니다.
서론
데이터 타입 = 값의 집합 + 연산의 집합
타입 규칙 : 언어 설계 때 프로그램 구성요소의 타입 사용 규칙도 정함. 엄격성에 따라 분류.
타입 오류 : 프로그램 실행 중 수식, 문장, 함수 등이 타입에 맞지 않게 잘못 사용되어 발생하는 오류
-
문법에 맞지만(생성규칙으로
유도 가능인지로 문법 확인
) 제대로 실행될 수 없는 프로그램 -
데이터 타입이 잘못 사용되는 것(타입에러)
타입 검사 : 타입 정보를 이용해 실행 중에 발생 가능한 타입 오류를 미리 검사하는 것
- C의 포인터는 프로그램 안전성에 좋지않다. 예로 int 포인터 변수에 주소 +100 한다면 그 메모리 주소가 만약 bool타입 인데 int형 값 저장하면 타입 에러가 발생하고 프로세스가 kill해버려 갑자기 죽는 프로그램이 될 수 있다.
- 타입 검사 안 함(어셈블리어)
강한, 약한 타입
타입오류를 얼마나 검출 하느냐에 따라 강한, 약한 타입검사로 또 나눌 수 있다.
많이 검출하면 강한, 적으면 약한으로 나눈다.
강한 타입 언어 : 엄격한 타입 규칙을 적용하여 (모든) 타입 오류를 찾아 낼 수 있는 언어
- Java, C#, Python
약한 타입 언어 : 느슨한 타입 규칙을 적용한 언어. 타입 검사를 통과한 프로그램이 실행 중에 타입 오류가 발생가능.
- C/C++, PHP, Perl, JavaScript
- C는 포인터를 생각해보면 다른 메모리 주소를 사용시 타입이 다를 수 있음.
- 그러나 C는 약한 규칙이라서 오류가 아닌것
정적, 동적 타입
타입검사를 언제하느냐에 따라 정적, 동적 타입검사로 나눌 수 있다.
- 실행 전(정적)
- 실행 후(동적)
정적 타입 언어 : 변수의 타입이 컴파일 시간에 결정되어 고정되는 언어. 보통 컴파일 시간
에 타입 검사
- Java, C, C++, FORTRAN, Pascal, Scala
- 장점 : 타입오류가 있는걸 실행하지않고 걸러냄.
- 단점 : 동적과 반대로 타입제한이 있고, 여러 타입을 바꿔가며 사용 불가.
동적 타입 언어 : 변수의 타입이 저장되는 값에 따라 실행 중에 바뀔 수 있는 언어. 보통 실행 시간
에 타입 검사
- Perl, Python, Scheme, JavaScript
- 장점 : 타입제한이 없고 여러 타입을 바꿔가며 사용가능.
- 단점 : 정적과 반대로 실행전에 타입오류를 못 걸러냄.
대표적인 언어 예시
-
자바 : 강한 정적 타입 언어
-
C : 약한 정적 타입 언어
-
Python : 강한 동적 타입 언어
-
JavaScript : 약한 동적 타입 언어
타입 시스템
안전한 타입 시스템 : 이 시스템 통과시 타입 오류 발생하지 않을 것이 보장됨.
타입 시스템 : 타입 규칙으로 구성된 시스템
- 앞에선
변수 값
을 저장하는환경(state)
이였고, 여기선타입
을 저장하는타입 환경
을 사용
언어 S의 타입 시스템
언어S의 생김새 -> 언어S는 임의로 만든 언어
타입 환경 : 각 지점에서 유효한 변수들의 타입 정보를 유지
타입 검사기 구현 – 입력 프로그램의 AST를 순회하면서 Stmt와 Expr을 만날 때마다 구현
타입검사 규칙들
- 사칙연산 : 사용타입 INT => 반환타입 INT
- 관계연산 : 사용타입 동일 => 반환타입 BOOL
- 대입문 : 사용타입 동일 => 반환타입 VOID
- 조건문 : BOOL(expr 조건문), 동일(stmt1,2 몸체)
- if, else라서 stmt1,2 => 반환타입 stmt
- 반복문 : BOOL(expr), VOID(stmt) => 반환타입 VOID
- let문 : 선언문 타입, 본문(stmt)타입 사용 => 반환타입 stmt
참고
자바
배열 선언은 정적이고, 배열 크기가 동적이며 힙에 할당한다.
따라서 선언은 컴파일러, 크기는 인터프리터의 역할이다.
- 인터프리터는 실행때 동작하니까 크기를 알 수 있는것!
- 정해진 크기도 동적으로 더 키우고 줄이는 ArrayList를 제공
- 그리고 new로 생성하니까 힙에 동적으로 할당
예시
int size = 50;
int arr[] = new int[size]; // 가능(실행때 크기지정하니까 size로 선언 가능)
arr = new int[50]; // 가능(새로운 배열임)
arr[60] = 3; // 이건 에러. 하지만 ArrayList는?
ArrayList<Integer> arr = new ArrayList<Integer>(); // 크기 0으로 생성
arr.add(3); // 크기 0이였는데 동적으로 삽입
arr.get(0); // 값 출력 잘 나옴
C언어
배열 선언은 정적이고, 배열 크기도 정적이다.
컴파일 시간에 타입검사를 하는데 값은 알 수 없다고 앞에서 설명했었다.
자바처럼 ArrayList 같은 동적 배열도 없다.
물론, malloc 처럼 동적 할당으로 유사하게 만들 수는 있다.
예시
int size = 50;
int arr[size]; // 에러(컴파일때 size 타입만 알고있음)
int arr[30]; // 가능
arr[31] = 3; // 에러(동적으로 크기 못 키움)
댓글남기기