haileyjpark

[JavaScript] script언어와 Type언어란? 본문

JavaScript

[JavaScript] script언어와 Type언어란?

개발하는 헤일리 2022. 5. 15. 22:53
반응형

Script언어란?

스크립트 언어는 연극 용어 script에서 따온 말이다.

프로그래밍의 스크립트 언어는 인터프리터 방식에 사용하기 위해 나온 것으로, 기존에 이미 존재하는 소프트웨어를 제어하기 위한 용도로 쓰이는 언어이다.

연극에서의 스크립트가 극 안의 상황에서 배우가 어떻게 행동할 것인지 지시해놓은 것처럼, 스크립트 언어도 소프트웨어를 어떻게 실행할 지 제어한다. (새로운 프로그램을 만들기보다는 기존의 프로그램을 제어하기 위해 쓰인다)

일반적으로 스크립트 언어는 매우 빠르게 작성된 코드를 실행하기 위해 고안되었으며, 상대적으로 단순한 구문과 의미를 내포한다.

컴파일 언어? 인터프리터 언어? - Build 방식에 따른 분류

개발자가 만든 소스코드를 기계어(machine code)로 번역하여 실행 가능한 파일로 만드는 과정을 빌드라고 한다.

이러한 실행파일은 exe,exec 등 여러 종류가 있고 CPU가 읽을 수 있는 이진코드로 이루어져 있다.

빌드 과정은 크게 컴파일 방식, 인터프리터 방식, 하이브리드 방식의 3가지 방식으로 분류할 수 있다.

  • 컴파일 방식 : 소스코드 전체를 기계어로 번역함
  • 인터프리터 방식 : 소스코드를 한 줄씩 번역하면서 실행함
  • 하이브리드 방식 : 소스코드 전체를 중간코드 (바이트 코드)로 번역한 뒤 VM에서 한 줄씩 실행함

컴파일 방식

컴파일 언어의 장점

  • 빌드가 완료된 실행 가능한 파일은 실행 속도가 빠르다
  • 매번 번역할 필요 없이 실행 파일만 실행하면 되기 때문에 전체적인 시간 면에서 효율적이다

컴파일 언어의 단점

  • 프로그램을 수정해야 할 경우 처음부터 빌드 과정을 다시 거쳐야하기 때문에 대규모 프로그램에서는 생산성이 떨어진다.
  • 플랫폼에 의존적이다 (윈도우 실행파일을 맥os에서 실행하지 못함. C언어의 경우 자료형 타입이 각 운영체제마다 크기가 다르다)

인터프리터 방식

컴파일 언어와 인터프리터 언어의 가장 큰 차이점 : 목적 파일을 생성하지 않고 바로 실행한다. (실행 파일이 없는 것이 아니라 소스코드 그 자체가 실행가능한 파일이 되는 것)

소스코드의 한 명령 세트마다 기계어로 번역하면서 바로바로 실행해준다. → 번역해주는 프로그램(또는 환경)을 Interpreter 라고 함.

 

인터프리터 언어의 장점

  • 컴파일 과정 없이 바로 실행하기 때문에 수정, 디버깅에 유리하다. → 개발 속도에 유리
  • 각 플랫폼에 지원하는 인터프리터만 있다면 실행 가능하기 때문에 플랫폼에 독립적이다. (각 운영체제에 맞는 해당 언어의 인터프리터만 설치한다면 어느 운영체제에서든 해당 언어를 사용하더라도 동일한 결과를 얻을 수 있음)

인터프리터 언어의 단점

  • 빌드 되어있는 컴파일 언어 프로그램보다 실행시간이 느리다. (매번 부분씩 번역해야하기 때문에)
  • 코드를 열면 다 보이기 때문에 보안에 좋지는 않다.

하이브리드 방식

컴파일 방식과 인터프리트 방식의 단점을 상호 보완하여 만들어진 방식. 흔히 ‘바이트 코드 언어(Byte Code Language)’라고 한다. 대표적인 언어로 Java가 있다.

 

하이브리드 언어의 장점

  • 각 플랫폼에 지원하는 가상머신이 있다면 실행 가능하기 때문에 플랫폼에 독립적이다

하이브리드 언어의 단점

  • 컴파일 언어처럼 하드웨어를 직접 제어하는 작업은 불가능하다

스크립트 언어가 아닌 컴파일 언어를 사용해야 할 때

  1. 리소스에 민감한 작업들, 특히 속도가 중요한 요소일 때(정렬, 해쉬 등)
  2. 강력한 산술 연산 작업들, 특히 임의의 정밀도 연산
  3. 플랫폼 간 이식성이 필요할 때
  4. 구조적 프로그래밍이 필요한 복잡한 애플리케이션(변수의 타입 체크나 함수 프로토 타입 등이 필요할 때)
  5. 업무에 아주 중요하거나 회사의 미래가 걸렸다는 확신이 드는 애플리케이션
  6. 보안 상 중요해서 시스템 무결성을 보장하기 위해 외부의 침입이나 크래킹, 파괴 등을 막아야 할 필요가 있을 때
  7. 서로 의존적인 관계에 있는 여러 컴포넌트로 이루어진 프로젝트
  8. 과도한 파일 연산이 필요할 때
  9. 다차원 배열이 필요할 때
  10. 링크드 리스트나 트리 같은 데이터 구조가 필요할 때
  11. 그래픽이나 GUI를 만들고 변경하는 등의 작업이 필요할 때
  12. 시스템 하드웨어에 직접 접근해야 할 때
  13. 포트나 소켓 I/O가 필요할 때
  14. 예전에 쓰던 코드를 사용하는 라이브러리나 인터페이스를 써야 할 필요가 있을 때
  15. 독점적이고 소스공개를 안 하는 애플리케이션을 만들어야 할 때(오픈소스 스크립트 언어의 경우)

Type 언어란?

정적 타입 언어? 동적 타입 언어? - 타입이 결정되는 시점에 따른 분류

  • 동적타입(Dynamic Typed) 언어: 타입을 런타임 시에 확인
    • 장점: 사용하기 위해 지켜야 할 규칙이 적기 때문에 상대적으로 코드가 짧고 러닝커브가 낮다.
  • 정적타입(Static Typed) 언어: 타입을 컴파일 시에 확인
    • 장점: 컴파일 시에 타입을 미리 확인하기 때문에 타입 관련한 런타임 오류를 방지할 수 있다. 타입이 명시적으로 지정되어 있기 때문에 동적타입 언어에 비해 가독성이 좋다.
  • 점진적 타이핑
    • 동적 타입 검사만을 수행하던 언어에 정적 타입 검사를 도입하고자 하는 시도가 늘어남에 따라, 프로그램 전체가 아닌 프로그래머가 명시한 일부 부분만 정적 타입 검사를 거치게 하고 나머지 부분은 그대로 동적타입 검사가 이루어지도록 하여, 점진적인 개선을 가능케하는 점진적 타이핑(gradual typing)을 지원하고자 함.
    • 점진적 타이핑이 가능한 대표적 동적 타입 언어 : Closure, TypeScript, Hack 등
    • C#의 경우 정적 타입 검사 언어로 시작했으나 후에 dynamic 키워드로 동적 타입 검사를 거칠 부분을 지정하는 것을 허용함으로써 점진적 타이핑을 도입

 

형변환 (type conversion)

암시적 형변환(implicit type conversion)

암시적 형변환은 프로그래머의 명시적 선언 없이 컴파일러 또는 인터프리터를 통해 자동으로 일어난다.

어떤 연산이 허용하지 않는 타입에 대해 이루어질 때, 타입 에러를 내는 대신 컴파일러 혹은 인터프리터가 하나 이상의 피연산자를 ‘말이 되는’ 타입으로 자동 변경 후 작업을 진행한다. → ‘말이 되는' 변환이란 언어마다 다르다. 어떤 언어는 모든 프로그램을 어떻게든 타입 에러 없이 실행시키기도 한다.

  • 약타입 언어 : 자료형이 맞지 않을 시에 암묵적으로 타입을 변환하는 언어
  • 강타입 언어 : 자료형이 맞지 않을 시에 에러 발생, 암묵적 변환을 지원하지 않음
  • ex) 1 + "1"을 계산하면 약타입 언어인 자바스크립트에서는 "11"로 타입을 변환하여 계산되지만 Python 의 경우에는 TypeError 가 발생

자바스크립트의 암시적 형변환 예시

/* Javascript, the good parts */
console.log(1 + 1)          // 1
console.log(1 + 3.1)        // 4.1
console.log(1 + 3.14)       // 4.140000000000001 (IEEE 754)

/* Javascript, some parts of it... at least */
console.log(1 + []);        // '1'
console.log(1 - []);        // 1
console.log(1 + {});        // '1[object Object]'
console.log(1 - {});        // NaN
console.log([] + []);       // ''
console.log({} + []);       // 0
console.log({} + {});       // NaN

 

명시적 형변환(explicit type conversion)

프로그래머가 값을 다른 타입으로 해석하겠다는 의도를 명확히 밝힘에 따라 일어나는 형변환을 명시적 형변환이라고 부른다. 언어에 따라 타입 캐스팅 연산자(type casting operator, 타입 변환 함수(type conversion function) 등을 이용해 일어난다.

명시적 형변환 예시

// C
double a = 3.3;
int b = (int) a;

// Python
a = 3.3;
b = int(a)

// Haskell
a = 3.3
b = round a

TypeScript

인터프리터 언어인 자바스크립트와는 다르게 컴파일 언어인데, 전통적인 C계열의 컴파일 언어와는 차이가 있어 브라우저에서 이해할 수 있도록 JavaScript 코드로 변환하는 트랜스파일 언어라고도 부른다.

동작방식: TS → 컴파일(트랜스 파일) → JS → 실행

TS가 JS로 변환될 때 helper 코드가 위아래로 추가된다.

//자바스크립트
function sum(a, b) {
  return a + b;
}
let foo = "hello"

//타입스크립트
function sum(a: number, b: number) {
  return a + b;
}
let foo: string = "hello"

 

Typing에서의 Java와 TypeScript의 차이 - Structural Typing & Nominal Typing

Nominal Typing (명칭적 타이핑) - Java

  • 특정 키워드를 통해 서로 호환 가능하다고 명시적으로 표현된 타입 간의 할당을 허용하는 방식

Structural Typing (구조적 타이핑) - TypeScript

  • 클래스명과 같은 명칭보다는 각 클래스 혹은 변수가 가지고 있는 데이터, 객체의 구조가 유사하다면 타입 간의 할당을 허용한다 - Duck Typing과 거의 동일한 방식

<자바 코드 예시>

class A {
	public void hello() {}
}

class B {
	public void hello() {}
}

A a = new B(); // 컴파일 에러

<TypeScript 코드 예시>

interface A {
	name: string;
}

class B {
	name: string;
}

const a: A = new B(); // 컴파일 에러 미발생

 

TypeScript가 정적 타입 언어이면서 구조적 타이핑 방식을 선택한 이유: 타입에 있어 다소 유연한 문법을 허용하는 JS의 슈퍼셋 개념이기 때문.

 

<TypeScript 공식 문서 내용>

TypeScript의 구조적 타입 시스템은 JavaScript 코드의 일반적인 작성 방식에 따라서 설계되었습니다.
JavaScript는 함수 표현식이나 객체 리터럴 같은 익명 객체를 광범위하게 사용하기 때문에
JavaScript에서 발견되는 관계의 타입을 명목적 타입 시스템보다는 구조적 타입 시스템을 이용하여
표현하는 것이 훨씬 더 자연스럽습니다



마치며


빌드의 방식이나 타입 결정 시점에 따른 프로그래밍 언어의 분류에 대해 알아보고, 장단점과 차이점에 대해 알 수 있었고, 어떤 언어가 더 좋은 언어라고 할 수는 없지만 어떤 상황에서는 어떤 언어가 더 유용할 것이라고 할 수는 있을 것 같다.

이런 차이점들을 보면서 C나 Java같은 컴파일/하이브리드 언어들도 경험해보고 싶어졌다.

컴파일 언어와 인터프리터 언어의 차이 / 정적 타입 언어와 동적 타입 언어의 차이 / 언어별 차이 같은 부분들은 그 언어를 직접 사용해보고 배포까지의 과정을 한 사이클 경험해보아야 확실히 체감할 수 있을 것 같기 때문이다.

사실 자료들을 보면서 Java와 TypeScript에 대한 비교들에 대해서도 Typing이라는 관점 외에 더 많은 부분을 이해하고 싶었지만, OOP를 완벽하게 이해하지 못한 상태에서는 찝찝함을 남기는 얕은 이해로 끝낼 수 밖에 없었다. CS 기초 지식들에 대한 촘촘한 이해의 필요성을 또 한번 느꼈다. 찝찝함을 없애는 그날까지....즐겁게 공부! 🌟

 

참고자료