SAP BOX

'26/10/19 UPDATE

ABAP / FIELD NOTES

LOOP 안의 EXIT와 CHECK는 왜 메서드를 끝내지 않을까

루프 안에서 EXIT는 루프만, CHECK는 그 회차만 끝냅니다. 그래서 '잘못된 행이 있으면 그만'이라고 쓴 검증 루프 뒤의 전기 호출이 그대로 실행됩니다. 가상 예로 자리에 따른 두 동작, RETURN으로 고치는 법, 첫머리 CHECK가 허용되는 이유, START-OF-SELECTION에서 EXIT와 CHECK가 갈리는 지점을 봅니다.

가상의 메서드 post_items는 전기할 항목을 받아, 먼저 루프를 돌며 금액이 0 이하인 행이 있는지 확인하고, 문제가 없으면 post_document로 전기합니다. 확인 루프 안에는 IF ls_item-amount <= 0. EXIT. ENDIF.가 있습니다. 쓴 사람의 의도는 '잘못된 행이 하나라도 있으면 여기서 그만'이었습니다. 그런데 금액이 0인 행이 들어온 날에도 전기는 그대로 호출됩니다. EXIT 대신 CHECK ls_item-amount > 0.으로 바꿔도 마찬가지입니다. 이 글을 읽고 나면 CHECK와 EXIT가 놓인 자리에 따라 무엇을 끝내는지 구분하고, 메서드를 끝내야 하는 자리에 어떤 문장을 써야 하는지, 보고서 이벤트 블록에서는 무엇이 더 달라지는지 고를 수 있습니다.

예시의 클래스 ZCL_DEMO_POSTING, 메서드, 필드와 행 번호는 모두 지어낸 것이고, 코드는 실제 시스템에서 실행하지 않았습니다. 글의 흐름은 ABAP 키워드 문서의 CHECK(루프), EXIT(루프), RETURN 페이지와 프로시저 종료 지침(7.58판, CHECK·EXIT는 7.50판과 대조)의 규칙을 적용해 따진 것이며, 문서는 영어입니다.

CHECK와 EXIT는 자리에 따라 두 가지 문장이다

키워드 문서에는 CHECK와 EXIT가 각각 두 번 나옵니다. 한 번은 '루프를 빠져나가는 문장', 한 번은 '처리 블록을 빠져나가는 문장'입니다. 여기서 루프는 LOOP ... ENDLOOP뿐 아니라 DO, WHILE, SELECT ... ENDSELECT도 포함합니다.

루프 안에서 CHECK의 조건이 거짓이면 이번 회차만 끝내고 다음 회차로 넘어갑니다. 문서는 이것이 IF NOT 조건. CONTINUE. ENDIF.와 같다고 적습니다. 루프 안의 EXIT는 루프 전체를 끝내고, 프로그램은 그 루프의 닫는 문장 다음 줄부터 계속됩니다. 어느 쪽도 메서드를 끝내지 않습니다. 반대로 루프 밖에 놓이면 두 문장 모두 현재 처리 블록을 끝냅니다. 메서드, 함수 모듈, 서브루틴 같은 프로시저 안이라면 RETURN과 같은 효과입니다. RETURN은 이와 달리 어떤 제어 구조 안에 있든 처리 블록을 끝냅니다.

SAP 노트

같은 문장, 놓인 자리에 따라 다른 끝

루프 = LOOP, DO, WHILE, SELECT ... ENDSELECT

  • 루프 안의 CHECK

    CHECK ls_item-amount > 0.

    • 조건이 거짓이면 이번 회차만 끝낸다
    • 다음 회차로 넘어간다
    • IF NOT ... CONTINUE와 같다
  • 루프 안의 EXIT

    EXIT. " -> after ENDLOOP

    • 그 루프 전체를 끝낸다
    • 닫는 문장 다음 줄부터 계속한다
    • 메서드는 끝나지 않는다
  • 루프 밖의 CHECK·EXIT

    RETURN.

    • 현재 처리 블록을 끝낸다
    • 메서드라면 RETURN과 같은 효과
    • RETURN은 어디서나 블록을 끝낸다

ABAP 키워드 문서 CHECK·EXIT(loop, processing_block), CONTINUE, RETURN 페이지 7.58판과 7.50판 기준입니다.

CHECK와 EXIT는 루프 안에서는 루프만 다루고, 루프 밖에서야 처리 블록을 끝냅니다. 루프 안에서도 메서드를 끝내는 문장은 RETURN입니다.

프로그래밍 지침은 이 차이를 직접 문제로 꼽습니다. EXIT와 CHECK는 맥락에 따라 루프를 끝내기도 하고 프로시저를 끝내기도 해서 코드를 읽기 어렵게 만들고, 루프 안에서 프로시저를 끝낼 수 있는 것은 RETURN뿐이라는 것입니다. 그래서 지침은 EXIT와 CHECK는 루프를 끝낼 때만, 프로시저를 끝낼 때는 RETURN만 쓰라고 권합니다. 루프 안과 밖의 동작을 적은 CHECK·EXIT 페이지의 설명은 7.50판과 7.58판이 같으니, 최근 릴리스에서 바뀐 규칙이 아닙니다.

금액 0인 행 하나로 따라가 보기

가상 예의 it_items에 10, 20, 30행이 있고 20행의 금액이 0이라고 해 봅시다. IF ... EXIT로 쓴 경우, 10행을 지나 20행에서 루프를 빠져나갑니다. 30행은 검사조차 하지 않고, 실행은 ENDLOOP 다음 줄로 이어져 post_document( it_items )가 호출됩니다. 빠져나간 곳이 메서드가 아니라 루프였기 때문입니다.

CHECK ls_item-amount > 0.으로 쓴 경우는 조금 다르게 틀립니다. 20행에서는 그 회차의 나머지 문장만 건너뛰고 30행을 계속 검사합니다. 검사 결과를 따로 모으지 않았다면 루프가 끝난 뒤의 전기는 역시 그대로 호출됩니다. 두 경우 모두 오류나 경고 없이 정상적으로 흘러간다는 점이 이 실수를 찾기 어렵게 만듭니다.

SAP 노트

금액 0인 행을 만났을 때

가상 예: 10·20·30행 중 20행 amount = 0, 루프 뒤에 post_document( it_items )

  • IF ... EXIT

    10 -> 20 -> ENDLOOP -> post

    • 20행에서 루프를 빠져나간다
    • 30행은 검사하지 않는다
    • post_document는 그대로 호출된다
  • CHECK amount > 0

    10 -> 20 skip -> 30 -> post

    • 20행의 나머지 문장만 건너뛴다
    • 30행은 검사한다
    • post_document는 그대로 호출된다
  • IF ... RETURN

    10 -> 20 -> end of method

    • 20행에서 메서드를 끝낸다
    • 루프 뒤의 문장은 실행되지 않는다
    • post_document는 호출되지 않는다

메서드·테이블·행 번호는 가상이고 코드는 실행하지 않았습니다. 흐름은 문서의 CHECK·EXIT·RETURN 규칙으로 따진 것입니다.

'잘못된 행이 하나라도 있으면 전기하지 않는다'는 의도라면 EXIT도 CHECK도 루프만 다루므로 전기 호출까지 갑니다. 메서드를 끝내려면 RETURN을 써야 합니다.

의도대로 고치려면 20행에서 메서드를 끝내야 하고, 그 문장은 RETURN입니다. 루프 안에서 실행되어도 메서드를 끝내므로 post_document는 호출되지 않습니다. 실제 코드라면 그냥 조용히 끝내기보다 예외를 발생시키거나 메시지를 남기는 편이 호출한 쪽에 더 친절할 수 있습니다. 어떤 방법을 고르든 '루프를 끝낼 것인가, 메서드를 끝낼 것인가'를 먼저 정하는 것이 출발점입니다.

중첩된 루프에서도 같은 원리입니다. 안쪽 루프의 EXIT는 그 안쪽 루프의 닫는 문장 다음으로 갈 뿐이고, 그 자리는 여전히 바깥 루프 안이므로 바깥 루프는 다음 회차를 계속 돕니다. 두 겹을 모두 끝내려면 바깥 루프에서 따로 판단하거나, 메서드 전체를 끝낼 생각이라면 RETURN을 씁니다.

루프 밖의 CHECK: 첫머리에서는 허용되는 쓰임

그렇다면 루프 밖의 CHECK는 쓰면 안 될까요. 지침은 한 가지 예외를 둡니다. 프로시저의 맨 앞에서 실행 전제 조건을 확인하는 CHECK는 읽기에 방해가 되지 않으므로 허용합니다. 예를 들어 메서드 첫 줄의 CHECK it_items IS NOT INITIAL.은 '받은 항목이 없으면 할 일이 없다'는 뜻으로 바로 읽힙니다. 다만 이 예외는 첫머리에만 해당하고, 프로시저 중간의 루프 밖 CHECK에는 적용되지 않습니다. 지침의 나쁜 예처럼 CHECK is_finished = abap_false.를 중간에 두면 이중 부정을 머릿속에서 풀어야 하니, IF is_finished = abap_true. RETURN. ENDIF.로 쓰는 편이 낫다는 것입니다.

프로시저를 CHECK, EXIT, RETURN으로 끝내는 것은 모두 정상 종료입니다. 값 전달로 정의된 출력 매개변수도 호출한 쪽의 실제 매개변수로 넘어갑니다. 반대로 예외가 발생하거나 메시지를 보내 프로시저가 끝나면 값 전달 매개변수는 넘어가지 않습니다. '중간에 빠져나갔으니 결과도 안 넘어갔겠지'라고 기대하면 안 되는 이유입니다.

아래 편집기 예시는 지금까지의 내용을 한 화면에 모은 것입니다. ①은 첫머리의 허용되는 CHECK, ②는 루프만 빠져나가는 EXIT, ③은 그래서 호출되는 post_document, ④는 같은 자리를 RETURN으로 고친 줄입니다.

SAP GUI 클래스 빌더 화면의 코드에 번호 네 개가 있다. 1은 메서드 첫머리의 CHECK it_items IS NOT INITIAL., 2는 IF ls_item-amount <= 0 안의 EXIT와 LOOP만 빠져나간다는 주석, 3은 ENDLOOP 뒤의 post_document( it_items ), 4는 고친 메서드에서 같은 자리의 RETURN과 메서드를 빠져나간다는 주석이다.
같은 검증 루프를 EXIT와 RETURN으로 쓴 두 메서드를 나란히 놓은 예시. ZCL_DEMO_POSTING과 메서드, 필드는 가상이고 코드는 실행하지 않았으며, 흐름은 문서의 규칙으로 따진 것이다.

보고서 이벤트 블록에서는 결과가 갈린다

실행형 프로그램(보고서)의 이벤트 블록을 끝낼 때는 문장마다 뒤따르는 일이 다릅니다. 문서에 따르면 START-OF-SELECTION을 EXIT나 RETURN으로 끝내면 런타임은 더 이상 보고서 이벤트를 발생시키지 않고 곧바로 리스트 처리기를 불러 기본 리스트를 보여 줍니다. 그러니 그 뒤의 END-OF-SELECTION 블록은 실행되지 않습니다. 반면 CHECK의 처리 블록 페이지는 정상 종료와 다르게 동작하는 경우로 LOAD-OF-PROGRAM과 GET만 꼽습니다. 이 규칙대로라면 START-OF-SELECTION을 CHECK로 끝냈을 때는 정상 종료처럼 END-OF-SELECTION이 이어집니다. STOP은 아예 END-OF-SELECTION으로 보내는 문장입니다.

LOAD-OF-PROGRAM은 CHECK, EXIT, RETURN 중 어느 것으로도 끝낼 수 없습니다. STOP은 메서드에서 쓸 수 없고, LOAD-OF-PROGRAM 중이나 SUBMIT으로 호출되지 않은 프로그램에서 실행되면 잡을 수 없는 예외가 납니다. 7.58판 문서는 END-OF-SELECTION을 논리 데이터베이스용의 폐기된 문장으로 분류하고, 논리 데이터베이스 없는 프로그램에서는 이 블록을 구현할 필요가 없다고 적습니다. 오래된 보고서를 고칠 때 이 차이를 만나기 쉬운 이유입니다.

SAP 노트

루프 밖에서는 블록 종류가 결과를 바꾼다

CHECK·EXIT·RETURN으로 처리 블록을 끝낸 뒤 일어나는 일

  • 메서드·함수 모듈·서브루틴

    CHECK / EXIT / RETURN

    • 정상 종료로 처리된다
    • 출력 매개변수가 실제 매개변수로 넘어간다
    • 예외·메시지로 끝나면 값 전달 출력은 안 넘어간다
  • START-OF-SELECTION

    END-OF-SELECTION

    • EXIT·RETURN: 다음 보고서 이벤트 없음
    • 바로 기본 리스트를 표시한다
    • CHECK·STOP: END-OF-SELECTION은 온다
  • LOAD-OF-PROGRAM

    STOP: uncatchable exception

    • CHECK·EXIT·RETURN으로 끝낼 수 없다
    • STOP은 잡을 수 없는 예외가 난다
    • STOP은 메서드에서 쓸 수 없다

ABAP 키워드 문서 7.58(Exiting Processing Blocks, RETURN, STOP, END-OF-SELECTION)과 7.50 CHECK·EXIT 페이지 기준입니다. GET 이벤트는 다루지 않았습니다.

절차 안에서는 세 문장 모두 정상 종료지만, 보고서 이벤트 블록에서는 결과가 갈립니다. START-OF-SELECTION을 EXIT로 끝내면 END-OF-SELECTION이 오지 않고, CHECK로 끝내면 옵니다.

기억할 것은 하나입니다. 루프 안에서 EXIT와 CHECK는 루프만 다룹니다. '여기서 메서드를 그만둔다'는 뜻이라면 루프 안이든 밖이든 RETURN으로 쓰고, CHECK는 루프 안이나 메서드 첫머리의 전제 조건 확인에만 남겨 두세요.

끝 · END OF NOTE
RSS 구독목록으로
COMMENTS BOX

이 기록에 대화를 더해 주세요.

궁금한 점, 다른 접근, 직접 해 본 결과를 나눠 주세요.

최신순

로그인 상태 확인 중…

댓글을 불러오는 중…