-
Ada와 Rust 두 언어를 활용해 Advent of Code 문제를 풀며 생긴 차이점과 특징을 비교함
-
안전성과 신뢰성을 중심으로 하는 두 언어의 언어 설계와 실질적인 프로그램 작성 방식의 차이점을 분석함
- 각 언어의 표준 라이브러리, 기능 내장 여부, 성능 차이, 오류 처리 스타일 등 다양한 관점에서 차별성이 드러남
-
모듈성과 제네릭, 반복문, 에러 핸들링 등 실전 코드 예시로 실제 작성·운용 시 겪는 구체적 사례를 설명함
- 정적 타입 지정 방식, 배열 처리, 에러 처리 인터페이스 차이로 인한 개발 경험의 차별성이 두드러짐
소개 및 목적
- Advent of Code(이하 AoC) 문제 해결 과정에서 Ada만 사용하다가, 2023년부터 Rust와 Modula-2로도 해답을 작성하며 직접 비교하게 됨
- 기존 Ada-중심 솔루션을 Rust로 옮기며 두 언어의 구조적 차이와 고유한 접근법을 체감함
- 코드의 안전성, 신뢰성, 언어 설계 관점에서 실제 사용상 차이를 명확하게 하려는 목적을 가짐
비교에 사용한 언어 버전
- Ada 2022(필요에 따라 Spark 2014 일부 규칙 참조)
- Rust 2021 (주요 비교 시 Rust 1.81.0 버전 기반)
제외된 기능 및 비교 기준
- 각 언어의 대표적인 기능(=킬러 피처)은 본문 중 코멘트로 간략히 언급됨
- 개인적 경험과 솔루션별 현실적인 필요성에 따라 다루지 않은 기능도 일부 있음
- 가능 최대한 사견은 배제하고 주요 특징에 집중
저자의 배경 및 관점
- Ada, Rust 모두 비원어민 사용자로서, C/C++, Pascal, Modula-2 등의 1980년대 언어 경험이 베이스임
- 결과적으로 코드 스타일이 현대적/이디엄과 다를 수 있음
- 최적 구현이 아닐 수도 있고, 문제 상황에 따라 직관적이거나 비관례적 해법을 선택한 경우도 있음
Ada와 Rust의 포지셔닝
- 여전히 Ada는 아주 안전하고 신뢰성 높은 시스템/임베디드 개발 언어로, 코드 가독성을 중시
-
Rust는 메모리 안전성과 시스템 프로그래밍의 강점을 가져, Stack Overflow 개발자 조사에서 다년간 ‘가장 선호하는 언어’에 지명됨
- Ada는 범용 고수준 언어로, 리딩 · 유지보수에 특화한 스펙트럼 제공
- Rust는 저수준 시스템 프로그램 개발을 지향하며, 명시적 메모리 관리와 오류/옵션 타입 기반 안전 프로그래밍 문화 확립
안전성 및 구조적 특징 비교
-
Ada
- ISO 표준(엄밀한 스펙)
- 문제 특성에 맞는 타입(범위, 자릿수 등을 선언)이 쉬움
- 배열 인덱스가 숫자가 아니어도 허용
- Spark라는 더욱 엄격한 사양 존재
-
Rust
- 명세가 공식 문서(Reference)와 컴파일러 중심
- 타입 선언이 머신 타입(예: f64, u32)에 의존
- 배열 인덱싱은 수치형만 자연스러움
기능/내장 여부 테이블 주요 요약
-
배열 범위 체크, 제네릭 컨테이너, 동시성, 라벨 루프, 패턴 매칭 지원 등에 차이
- Ada는 Exception(예외) 기반 오류 처리를, Rust는 Result/Option 타입을 통한 반환 기반 처리 방식
- Rust는 매크로, 패턴 매칭, 함수형 순수성 지원 등에서 차별점 두드러짐
- Ada는 계약 기반 설계 및 DBC(Design By Contract) 컴파일 타임 검증 Spark에서 지원
-
메모리 안전성 측면에서는 Rust와 Spark가 강제, Ada는 Null 포인터 활용 허용
성능 및 실행 시간 비교
- Rust는 일반적으로 런타임이 빠르나 컴파일 속도가 느리고, Ada는 반대로 컴파일 타임이 빠르고 런타임은 검증 체크에 따라 다소 느리다는 평판
- 벤치마크 결과, Rust가 day24 문제에서 f64 타입 한계로 오버플로우 발생했으나 Ada는 digits 18과 같이 고수준 타입 지정이 가능해, 기계 타입 자동 선택 및 오버플로우 회피로 뛰어난 성능을 보임
- Rust는 안정적이지 않은 f128 또는 외부 라이브러리를 사용해야 하며, Ada는 컴파일러스펙에 적합한 타입 지정만으로 우위 확보 가능
파일 처리 및 에러 핸들링(Case Study 1)
Ada의 파일 처리
- 기본적으로 Ada.Text_IO 사용
- 명시적으로 파일 오픈, 라인별 읽기, 원하는 범위, 위치 기반 Line 처리 등 상대적으로 직관적으로 가능
- 에러 발생 시 명확한 오류 메시지보다 예외로 처리되고, 함수 서명에 에러 발생 가능성이 드러나지 않음
Rust의 파일 처리
-
std::fs::File과 BufReader 활용
- 파일 오픈 시 Result 타입으로 반환, 에러 가능성이 명확하게 드러남
- 직접적인 문자 인덱스 접근 지원 없음, 반드시 Iterator로 처리
-
map, filter, collect, sum 등 함수형·반복형 도구가 중심이며, 다양한 매크로(예: include_str!) 지원
- 반환 타입에 명시적으로 에러를 선언해 함수 수준에서 에러 전파 명확성 확보
모듈성과 제네릭(Case Study 2)
Ada의 모듈성
-
패키지(package) 기반 명확한 명세(인터페이스)와 구현 분리
- 모듈화 강화 위해 하위 패키지, use/rename 문법 조합으로 가독성 조정
- 패키지의 generic 지원: 타입/상수/하위 패키지 전체를 일반화
Rust의 모듈성
-
mod/crate 체계로 모듈 구성, 명세와 구현 구분은 문서 생성기가 자동화
-
pub/private 접근 지정, 선언적 접근 권한 부여
-
use/as로 임포트/이름 변경 조합
-
내장 테스트 지원으로 코드에 직접 테스트 모듈 선언 및 빌드, 자동 실행 가능
제네릭
- Ada는 패키지/프로시저 단위 제네릭만 지원(타입 단독 지원 불가)
- Rust는 타입 자체에 제네릭 적용 가능(템플릿 기반)
- Ada는 타입 범위 등 추가 특성을 범위 타입, 서브타입 등으로 명확히 표현 가능, Rust는 인스턴스 상수 활용
열거형 타입 비교(Case Study 3)
- Ada는 간결한 선언과 동시에 자동적으로 이산형, 순서형, 반복 루프/인덱스 활용을 지원
- Rust enum도 선언은 비슷하나, 패턴 매칭 및 반복 등 접근은 더욱 명시적 방식이 필요
결론
-
고수준 명세 타입 및 검증성, 실행 시 체크 등에서 Ada가 더 엄격한 통제력 제공
-
함수형 프로그래밍 스타일, 매크로 프로그래밍, 컴파일러 보조 에러 처리 등에서 Rust가 개발 편의성과 안전성 모두에서 우위
- 실전 문제 해결에서 Ada는 오래된 코드 호환성과 유지보수 강점을, Rust는 현대적 개발 도구생태계와 안전/병렬성 지원에 이점을 보임