Ada, 그 설계와 언어를 만든 언어
4 hours ago
1
- 1970년대 미국 국방부의 소프트웨어 혼란 속에서 탄생한 Ada는 강한 정적 타입과 명세-구현 분리를 핵심으로 한 언어임
- 패키지 구조와 표현적 은닉을 통해 완전한 캡슐화를 구현하며, 이후 Java·C#·Go 등 현대 언어의 모듈 시스템에 영향을 줌
- 의미적 제약 타입, 제네릭, 동시성(task), 계약 기반 설계 등은 Ada가 수십 년 앞서 제시한 개념으로, Haskell·Rust·Swift 등이 이를 계승함
- SPARK Ada는 정형 검증을 통해 데이터 경합과 논리 오류까지 제거하며, 항공·철도·방위 시스템 등 고신뢰 분야에서 사용됨
- Ada는 대중적 언어는 아니지만, “조용히 올바르게 작동하는 언어” 로서 현대 프로그래밍 언어 설계의 근본 원칙을 제시한 기반임
Ada의 탄생 배경과 설계 철학
- 1970년대 초 미국 국방부(DoD) 는 무기·물류·통신 시스템에 450개 이상의 언어와 방언이 혼재된 상황을 조사함
- 각 시스템은 상호 운용 불가, 유지보수 불가능, 원 저자 부재 등의 문제를 가짐
- 이로 인해 소프트웨어 조달 위기가 발생
- DoD는 기존 언어(COBOL, Fortran, PL/1 등)를 채택하지 않고, 5년간의 요구사항 정의 과정을 거침
- Strawman → Woodenman → Tinman → Ironman → Steelman 문서로 발전
- Steelman(1978)은 명시적 인터페이스 분리, 강한 정적 타입, 내장 동시성, 일관된 예외 처리, 기계 독립성, 가독성, 검증 가능성을 요구
- 1979년 4개 팀(Green, Red, Blue, Yellow) 간 경쟁에서 Jean Ichbiah가 이끄는 Green 팀이 선정되어 Ada로 명명됨
- 이름은 Ada Lovelace를 기려 붙여졌으며, 언어의 의도를 상징
패키지 구조와 캡슐화
- Ada의 중심 구조는 패키지(package) 로, 명세(specification)와 본체(body)가 물리적으로 분리됨
- 명세는 외부에 공개되는 계약, 본체는 구현이며, 컴파일러가 두 관계를 강제
- 클라이언트 코드는 명세에 없는 요소에 접근 불가
- 이 구조는 모듈 시스템의 원형으로, 이후 언어들이 이를 부분적으로 모방
- Java, Python, JavaScript, C, Go, Rust 모두 Ada의 완전한 구조적 분리를 구현하지 못함
- private 타입은 이름만 노출되고 내부 표현은 완전히 불투명함
- 클라이언트는 타입의 내부 구조를 알 수 없으며, 허용된 연산만 사용 가능
- 이는 Java의 private 접근제어보다 강력한 표현적 은닉(representational invisibility)
- Java와 C#은 수십 년에 걸쳐 점진적으로 Ada 수준의 캡슐화를 향해 발전
타입 시스템과 의미적 제약
- Ada는 타입과 서브타입의 구분을 수학적 의미로 정의
- 예: type Age is range 0 .. 150은 범위 제약을 가진 별도 타입 생성
- 잘못된 타입 간 전달은 컴파일 타임 오류로 검출
- 1983년 당시 Ada의 타입 시스템은 C, Fortran, Pascal보다 훨씬 표현력이 높았음
- 판별 레코드(discriminated record) 는 값에 따라 다른 필드를 갖는 구조
- 이는 현대 언어의 합타입(sum type) 또는 대수적 데이터 타입(ADT) 과 동일
- Haskell, Rust, Swift, Kotlin, TypeScript 등이 수십 년 후 동일 개념을 도입
제네릭과 다형성
- Ada의 제네릭(generic) 은 타입·값·서브프로그램·패키지를 매개변수로 받는 단위
- 컴파일 시 타입 검증을 수행하는 정적 다형성(parametric polymorphism) 구현
- C++(1990), Java(2004), C#(2005), Go(2022) 등은 Ada 이후 수십 년에 걸쳐 유사 기능을 도입
- Java는 타입 소거(type erasure) 로 런타임 타입 정보 손실
- Ada는 런타임 타입 보존 및 패키지 매개변수화까지 지원
- Ada의 제네릭은 고차 다형성(higher-kinded polymorphism) 수준의 표현력 제공
- Haskell의 타입 클래스, Rust의 트레이트, C++20의 concepts와 유사한 개념
동시성 모델과 안전성
- Ada는 1983년부터 언어 수준의 동시성(task) 을 내장
- task 선언과 rendezvous 통신 모델을 통해 공유 상태 없는 메시지 전달 구현
- Go의 channel은 동일한 CSP(Communicating Sequential Processes) 계열의 개념
- Ada 95는 protected object를 도입
- 데이터 접근을 보호하며, procedure, function, entry로 구분
- 자동 배리어 조건과 락 없는 동기화 제공
- SPARK Ada는 정형 검증을 통해 데이터 경합, 예외, 범위 오류, 사전·사후조건 위반이 없음을 수학적으로 증명
- Rust의 borrow checker는 메모리 안전성만 보장하는 반면, SPARK는 논리적 정합성까지 증명
계약 기반 설계와 null 안전성
- Ada 2012는 계약(contracts) 을 언어에 통합
- 전제조건(precondition), 사후조건(postcondition), 타입 불변식(invariant) 을 명시
- SPARK 도구 체인은 이를 정적 증명에 활용
- Eiffel(1986)의 Design by Contract 개념을 언어 차원에서 정식화
- C++, Java, Python, Rust 등은 부분적 또는 라이브러리 수준 구현에 머무름
- Ada 2005는 not null 타입을 도입해 컴파일 타임 null 배제 지원
- 기본은 런타임 예외(Constraint_Error) 발생으로 안전한 실패 보장
- C# 8.0의 nullable reference와 유사한 접근
예외 처리 구조
- Ada 83은 최초로 구조적 예외 처리(structured exception handling) 를 도입
- 예외는 선언 후 사용, 스코프 단위로 처리, 전파 규칙 명확
- Java의 checked exception은 Ada보다 발전된 형태로, 호출자가 예외를 명시해야 함
- Rust는 예외를 제거하고 Result 타입 기반 오류 처리를 채택
- Ada의 기여는 예외 전파를 구조화하고 예측 가능하게 만든 점
Annex와 표준화 구조
- Ada 표준은 Annex라는 선택적 확장 구조를 가짐
- Annex C~H는 시스템, 실시간, 분산, 수치, 고신뢰 분야별 기능 정의
- 컴파일러는 Annex별 독립 인증을 받아야 함
- ACAA의 ACATS 테스트를 통해 표준 적합성 검증
- DO-178C 항공 소프트웨어 인증에 Ada의 표준 구조가 직접 활용 가능
- C/C++도 동일 인증 가능하지만, Ada는 구조적으로 더 적합
Ada의 영향과 인식의 불균형
- Ada는 정부 주도 언어로, 실리콘밸리 문화권에서 주목받지 못함
- Ada의 성공 사례(항공, 철도, 방위 시스템)는 실패가 없기에 가시성이 낮음
- 신뢰성 높은 시스템은 논의나 사건을 생성하지 않음
- 현대 언어의 발전 방향은 Ada가 이미 제시한 원칙으로 수렴
- 명세-구현 분리, 정적 타입 검증, 언어 수준 동시성, 계약 기반 안전성 등
- Ada는 여전히 항공기, 철도, 우주선 등 고신뢰 시스템에서 운용 중이며,
“조용히 올바르게 작동하는 언어” 로 남아 있음
-
Homepage
-
Tech blog
- Ada, 그 설계와 언어를 만든 언어