AoC 문제 해결을 통한 Ada와 Rust 비교

1 month ago 13

  • AdaRust 두 언어를 활용해 Advent of Code 문제를 풀며 생긴 차이점과 특징을 비교함
  • 안전성과 신뢰성을 중심으로 하는 두 언어의 언어 설계와 실질적인 프로그램 작성 방식의 차이점을 분석함
  • 각 언어의 표준 라이브러리, 기능 내장 여부, 성능 차이, 오류 처리 스타일 등 다양한 관점에서 차별성이 드러남
  • 모듈성과 제네릭, 반복문, 에러 핸들링 등 실전 코드 예시로 실제 작성·운용 시 겪는 구체적 사례를 설명함
  • 정적 타입 지정 방식, 배열 처리, 에러 처리 인터페이스 차이로 인한 개발 경험의 차별성이 두드러짐

소개 및 목적

  • Advent of Code(이하 AoC) 문제 해결 과정에서 Ada만 사용하다가, 2023년부터 RustModula-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::FileBufReader 활용
  • 파일 오픈 시 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는 현대적 개발 도구생태계와 안전/병렬성 지원에 이점을 보임

Read Entire Article