예외
예외 (Exceptions)
Ada는 오류 처리를 위해 예외(exception) 를 사용해요. 다른 많은 언어와 달리, Ada는 예외를 던진다(throwing) 고 하지 않고 발생시킨다(raising) 고 하며, 잡는다(catching) 고 하지 않고 처리한다(handling) 고 말해요.
출처: 예외 문서
본문
예외 선언 (Exception declaration)
Ada의 예외는 타입이 아니라 객체(object) 예요. Java나 Python의 예외 방식에 익숙하다면 조금 낯설 수 있어요. 예외를 선언하는 방법은 다음과 같아요:
package Exceptions is
My_Except : exception;
-- 객체처럼 다뤄요. *타입이 아님*!
end Exceptions;
객체이긴 하지만, 선언한 각 예외 객체를 일종의 "종류(kind)" 또는 "계열(family)" 로 사용해요. Ada는 서브프로그램이 발생시킬 수 있는 모든 예외를 선언하도록 요구하지 않아요.
예외 발생시키기 (Raising an exception)
새로 선언한 예외 종류를 발생시키려면 다음과 같이 해요:
with Exceptions; use Exceptions;
procedure Main is
begin
raise My_Except;
-- 현재 제어 흐름의 실행이 중단되고,
-- "My_Except" 종류의 예외가
-- 잡힐 때까지 전파(bubble up)돼요.
end Main;
여기서 My_Except 예외가 발생해요. 메시지도 함께 지정할 수 있어요:
with Exceptions; use Exceptions;
procedure Main is
begin
raise My_Except with "My exception message";
-- 현재 제어 흐름의 실행이 중단되고,
-- 문자열이 연결된 "My_Except" 종류의
-- 예외가 잡힐 때까지 전파돼요.
end Main;
이 경우 예외가 표시될 때 추가 메시지가 함께 보여요.
예외 처리하기 (Handling an exception)
우리나 호출한 라이브러리가 발생시킨 예외를 처리하는 방법을 다뤄볼게요. Ada의 멋진 점은 어떤 문장 블록에도 예외 핸들러를 추가할 수 있다는 것이에요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
procedure Open_File is
File : File_Type;
begin
-- 블록 (일련의 문장들)
begin
Open (File, In_File, "input.txt");
exception
when E : Name_Error =>
-- ^ 처리할 예외
Put ("Cannot open input file : ");
Put_Line (Exception_Message (E));
raise;
-- 현재 발생한 예외를 다시 발생
end;
end Open_File;
위 예시에서는 Ada.Exceptions 패키지의 Exception_Message 함수를 사용해요. 이 함수는 예외와 연결된 메시지를 문자열로 반환해요.
예외를 처리하려고 별도 블록을 만들 필요는 없어요. 현재 서브프로그램의 문장 블록에 바로 추가할 수 있어요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
procedure Open_File is
File : File_Type;
begin
Open (File, In_File, "input.txt");
-- 예외 블록은 어떤 블록에도 추가 가능
exception
when Name_Error =>
Put ("Cannot open input file");
end Open_File;
주의 (Attention) 예외 핸들러에는 반드시 알아둬야 할 중요한 제약이 있어요: 선언부(declarative section)에서 발생한 예외는 그 블록의 핸들러가 잡지 못해요. 예를 들어 다음 코드에서 예외는 잡히지 않아요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
procedure Be_Careful is
function Dangerous return Integer is
begin
raise Constraint_Error;
return 42;
end Dangerous;
begin
declare
A : Integer := Dangerous;
begin
Put_Line (Integer'Image (A));
exception
when Constraint_Error =>
Put_Line ("error!");
end;
end Be_Careful;
이는 현재 서브프로그램에 속한 최상위 예외 블록의 경우에도 마찬가지예요.
미리 정의된 예외 (Predefined exceptions)
Ada에는 미리 정의된 예외의 수가 아주 적어요:
Constraint_Error— 가장 많이 보게 될 주요 예외예요. 다음 경우에 발생해요:- 경계(range)가 맞지 않거나 일반적으로 어떤 제약을 위반한 경우
- 오버플로(overflow)가 발생한 경우
- 널 참조(null dereference)가 발생한 경우
- 0으로 나눈 경우
Program_Error— 등장할 수 있지만 비교적 드물어요. 정교화(elaboration) 순서 문제나 일부 감지 가능한 잘못된 실행과 같은 난해한 상황에서 발생해요.Storage_Error— 메모리 문제로 발생해요:- 메모리(할당자)가 부족한 경우
- 스택이 부족한 경우
Tasking_Error— 태스크 관련 오류로 발생해요. 예를 들어 태스크 활성화(activation) 중 발생하는 모든 오류가 여기에 해당해요.
미리 정의된 예외를 재사용하면 안 돼요. 그렇게 하면 예외가 발생했을 때 내장 언어 연산에서 문제가 생긴 것인지 구분하기 어려워져요.