1. 개요 및 이 글에서 얻어갈 것
ABAP 객체지향 프로그래밍을 하다 보면 메서드를 호출하는 두 가지 스타일을 마주하게 됩니다. 하나는 전통적인 CALL METHOD 구문이고, 다른 하나는 마치 수학 공식처럼 메서드를 식(expression) 위치에 그대로 끼워 넣는 함수형 메서드 호출(Functional Method Call)입니다. 후자는 단순히 코드 줄 수를 줄여주는 문법 설탕이 아니라, 인라인 선언, 조건문, 반복문, 단위 테스트 어서션 등 ABAP의 거의 모든 표현식 위치와 자연스럽게 결합되어 코드의 가독성과 유지보수성을 한 단계 끌어올리는 핵심 기법입니다.
이 글에서 우리는 다음을 다룹니다.
CALL METHOD와 함수형 호출의 문법적 차이- 함수형 호출이 성립하기 위한 RETURNING VALUE 단일 파라미터 조건
zcl_calc_demo,zcl_email_service,zif_pricing세 가지 예제로 보는 실전 패턴DATA( )인라인 선언과의 결합- ABAP Unit 테스트에서의 활용
NEW( ),CAST( ), 메서드 체이닝과의 조합
대상 릴리스는 SAP NetWeaver AS ABAP 7.40 SP08 이상(인라인 선언 지원 포함)이며, 최신 ABAP Cloud / S/4HANA 환경에서도 동일하게 적용됩니다.
2. 핵심 개념 — RETURNING VALUE 단일 파라미터와 식 위치 사용
ABAP 메서드의 파라미터는 일반적으로 IMPORTING, EXPORTING, CHANGING, RETURNING 네 가지 종류로 나뉩니다. 이 중에서 함수형 호출이 허용되는 조건은 명확합니다.
- 메서드는
RETURNING VALUE(...)파라미터를 정확히 하나만 가져야 합니다. EXPORTING또는CHANGING파라미터를 동시에 가지면 함수형 호출이 불가능합니다.IMPORTING파라미터는 자유롭게 여러 개 가질 수 있으며, 함수형 호출 시 괄호 안에 이름을 지정해 전달합니다.RAISING절을 통한 클래스 기반 예외는 함수형 호출과 함께 쓸 수 있습니다.
비유하자면 함수형 메서드는 "입력 여러 개를 받아 결과 한 덩어리를 돌려주는 수학 함수"와 같습니다. sin(x) 가 식의 어디에나 들어갈 수 있듯, RETURNING 단일 파라미터를 가진 ABAP 메서드도 변수가 들어갈 자리라면 거의 모든 위치에 직접 쓸 수 있습니다.
" 전통적 방식
DATA lv_result TYPE i.
CALL METHOD lo_calc->add
EXPORTING iv_a = 3
iv_b = 5
RECEIVING rv_sum = lv_result.
WRITE lv_result.
" 함수형 호출
WRITE lo_calc->add( iv_a = 3 iv_b = 5 ).
두 코드는 동일한 동작을 하지만 함수형 호출 쪽은 임시 변수 lv_result가 사라졌고, WRITE 라는 문장 안에서 메서드의 반환값이 그 자리에서 평가되어 사용됩니다. 이것이 함수형 호출의 본질입니다.
3. 1단계: 기본 함수형 메서드 호출 (zcl_calc_demo)
가장 단순한 계산기 클래스를 만들어 봅니다. RETURNING 파라미터의 사용 방법을 익히는 것이 목표입니다.
CLASS zcl_calc_demo DEFINITION
PUBLIC
CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
add
IMPORTING iv_a TYPE i
iv_b TYPE i
RETURNING VALUE(rv_sum) TYPE i,
multiply
IMPORTING iv_a TYPE i
iv_b TYPE i
RETURNING VALUE(rv_product) TYPE i,
square
IMPORTING iv_x TYPE i
RETURNING VALUE(rv_squared) TYPE i.
ENDCLASS.
CLASS zcl_calc_demo IMPLEMENTATION.
METHOD add.
rv_sum = iv_a + iv_b.
ENDMETHOD.
METHOD multiply.
rv_product = iv_a * iv_b.
ENDMETHOD.
METHOD square.
rv_squared = multiply( iv_a = iv_x iv_b = iv_x ).
ENDMETHOD.
ENDCLASS.
주목할 점은 square 메서드 내부에서 multiply( ... ) 를 식 위치에서 직접 호출했다는 것입니다. 임시 변수 없이 반환값이 곧바로 rv_squared 에 대입됩니다.
호출부도 살펴봅니다.
DATA(lo_calc) = NEW zcl_calc_demo( ).
" 식 위치에서 직접 사용
WRITE: / lo_calc->add( iv_a = 10 iv_b = 20 ),
/ lo_calc->square( iv_x = 7 ).
" 산술식 안에 끼워 넣기
DATA(lv_total) = lo_calc->add( iv_a = 1 iv_b = 2 )
+ lo_calc->multiply( iv_a = 3 iv_b = 4 ).
전통적 CALL METHOD 였다면 임시 변수 두 개를 선언하고 결과를 받아 더해야 했을 코드가, 함수형 호출 덕분에 한 줄로 정리됩니다.
4. 2단계: 인라인 선언 DATA( )와 결합
ABAP 7.40부터 도입된 DATA( ) 인라인 선언은 함수형 메서드 호출과 환상의 짝꿍입니다. 메서드의 RETURNING 타입을 컴파일러가 추론해주기 때문에 변수의 타입 선언을 생략할 수 있습니다.
실용 예제로 이메일 처리 서비스 zcl_email_service 를 봅니다.
CLASS zcl_email_service DEFINITION
PUBLIC
CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
normalize_address
IMPORTING iv_raw_email TYPE string
RETURNING VALUE(rv_normalized) TYPE string,
is_corporate_domain
IMPORTING iv_email TYPE string
RETURNING VALUE(rv_is_corp) TYPE abap_bool,
extract_domain
IMPORTING iv_email TYPE string
RETURNING VALUE(rv_domain) TYPE string.
ENDCLASS.
CLASS zcl_email_service IMPLEMENTATION.
METHOD normalize_address.
rv_normalized = to_lower( condense( val = iv_raw_email del = ` ` ) ).
ENDMETHOD.
METHOD extract_domain.
DATA(lv_at_pos) = find( val = iv_email sub = '@' ).
IF lv_at_pos >= 0.
rv_domain = substring( val = iv_email off = lv_at_pos + 1 ).
ENDIF.
ENDMETHOD.
METHOD is_corporate_domain.
" 함수형 호출 체이닝: normalize -> extract
DATA(lv_domain) = extract_domain(
iv_email = normalize_address( iv_raw_email = iv_email ) ).
rv_is_corp = COND #( WHEN lv_domain CP '*.com' OR lv_domain CP '*.co.kr'
THEN abap_true ELSE abap_false ).
ENDMETHOD.
ENDCLASS.
호출 코드에서 인라인 선언과 결합한 모습은 다음과 같습니다.
DATA(lo_email) = NEW zcl_email_service( ).
" 한 줄로 정규화된 주소 얻기
DATA(lv_clean) = lo_email->normalize_address(
iv_raw_email = ' John.DOE@Acme.COM ' ).
" IF 조건 안에서 직접 평가
IF lo_email->is_corporate_domain( iv_email = lv_clean ) = abap_true.
WRITE / |기업 도메인입니다: { lo_email->extract_domain( iv_email = lv_clean ) }|.
ENDIF.
DATA(lv_clean) 는 컴파일러가 string 타입으로 추론합니다. IF 절 안에서는 비교 대상으로 함수형 호출 결과가 그대로 사용되며, 메시지 문자열 템플릿 | ... | 안에서도 메서드 호출이 자연스럽게 임베드됩니다.
5. 3단계: 조건문/반복문 안에서 바로 호출
인터페이스를 반환하는 RETURNING 파라미터의 활용을 살펴봅니다. 가격 책정 서비스 인터페이스 zif_pricing 을 정의하고, 팩토리 메서드가 인터페이스 참조를 함수형으로 반환하도록 만듭니다.
INTERFACE zif_pricing
PUBLIC.
METHODS:
calculate_net
IMPORTING iv_quantity TYPE i
iv_unit_price TYPE p
RETURNING VALUE(rv_net) TYPE p.
ENDINTERFACE.
CLASS zcl_pricing_factory DEFINITION
PUBLIC
CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS:
get_strategy
IMPORTING iv_country TYPE land1
RETURNING VALUE(ro_pricing) TYPE REF TO zif_pricing.
ENDCLASS.
호출부에서는 RETURNING 타입이 REF TO zif_pricing 이라는 점을 활용해 메서드 체이닝을 구사합니다.
DATA: lt_orders TYPE TABLE OF ty_order.
" 반복문 안에서 두 번의 함수형 호출이 연쇄로 평가됨
LOOP AT lt_orders INTO DATA(ls_order).
DATA(lv_net) = zcl_pricing_factory=>get_strategy(
iv_country = ls_order-country
)->calculate_net(
iv_quantity = ls_order-qty
iv_unit_price = ls_order-price ).
WRITE: / ls_order-id, lv_net.
ENDLOOP.
" CASE 식 안에서도 함수형 호출이 가능
DATA(lv_label) = SWITCH string(
zcl_pricing_factory=>get_strategy( iv_country = 'KR'
)->calculate_net( iv_quantity = 10 iv_unit_price = '1500.00' )
WHEN 0 THEN '무료'
ELSE '유료' ).
get_strategy( ... )->calculate_net( ... ) 처럼 점이 아닌 -> 연산자로 이어 쓰는 것이 ABAP 식 체이닝의 핵심입니다. 첫 번째 호출이 인터페이스 참조를 반환하면 그 참조의 메서드를 곧장 다시 함수형으로 호출할 수 있습니다.
6. 4단계: ABAP Unit에서의 함수형 호출 활용
ABAP Unit 테스트 코드는 함수형 호출이 가장 빛을 발하는 영역입니다. cl_abap_unit_assert 의 어서션 메서드는 IMPORTING 파라미터로 기대값과 실제값을 받는데, 실제값 자리에 메서드 호출을 그대로 끼워 넣을 수 있기 때문에 테스트 의도가 명확해집니다.
CLASS ltc_calc_demo DEFINITION FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zcl_calc_demo.
METHODS:
setup,
add_returns_sum FOR TESTING,
square_uses_mult FOR TESTING.
ENDCLASS.
CLASS ltc_calc_demo IMPLEMENTATION.
METHOD setup.
mo_cut = NEW #( ).
ENDMETHOD.
METHOD add_returns_sum.
" 실제값 자리에 함수형 호출을 직접 임베드
cl_abap_unit_assert=>assert_equals(
exp = 15
act = mo_cut->add( iv_a = 7 iv_b = 8 ) ).
ENDMETHOD.
METHOD square_uses_mult.
cl_abap_unit_assert=>assert_equals(
exp = 49
act = mo_cut->square( iv_x = 7 ) ).
cl_abap_unit_assert=>assert_equals(
exp = 0
act = mo_cut->square( iv_x = 0 ) ).
ENDMETHOD.
ENDCLASS.
이 패턴의 장점은 테스트 코드에서 임시 변수가 사라지면서 "무엇을 검증하는가"가 한 줄로 드러난다는 점입니다. CALL METHOD 스타일이었다면 매 테스트마다 변수 선언 1줄, CALL METHOD 4줄, assert_equals 4줄로 비대해졌을 것입니다.
7. 자주 겪는 함정과 FAQ
Q1. EXPORTING 파라미터를 추가했는데 함수형 호출이 컴파일 에러를 냅니다.
A. 함수형 호출은 RETURNING 단일 파라미터 메서드에만 허용됩니다. EXPORTING 이나 CHANGING 파라미터가 하나라도 있으면 즉시 자격을 잃습니다. 부득이하게 여러 값을 반환해야 한다면 구조체 타입을 RETURNING 으로 묶거나, RETURNING 을 포기하고 전통적 CALL METHOD 로 돌아가야 합니다. 일반적으로 "값을 여러 개 돌려주고 싶다"는 욕구는 구조체나 테이블 타입으로 묶는 편이 설계상 더 깔끔합니다.
Q2. CHANGING 파라미터를 받는 메서드도 함수형으로 부르고 싶습니다.
A. 불가능합니다. CHANGING 의 본질은 호출자의 변수를 직접 수정한다는 것인데, 함수형 호출은 식 위치에서 평가되므로 수정할 변수가 명확하지 않습니다. CHANGING 이 필요하면 그 메서드는 함수형 후보가 아니라 일반적인 "절차형 메서드"로 설계되어야 합니다.
Q3. RAISING 으로 예외를 선언한 메서드도 함수형으로 호출 가능한가요?
A. 가능합니다. 다만 호출하는 식이 평가될 때 예외가 발생하면 그 자리에서 던져지므로, TRY ... CATCH 블록으로 호출문을 감싸야 합니다. 자주 실수하는 부분은 인라인 선언 변수의 스코프입니다. TRY 안쪽에서 DATA(lv_x) = obj->m( ) 으로 선언한 변수를 CATCH 블록에서 참조하면 초기값일 수 있다는 점에 주의하세요.
Q4. IMPORTING 파라미터가 하나뿐인 경우 이름을 생략해도 되나요?
A. 네. obj->m( 42 ) 처럼 위치 기반 전달이 허용됩니다. 그러나 의도를 명확히 하려면 obj->m( iv_x = 42 ) 처럼 키워드를 붙이는 편이 일반적으로 권장됩니다. 특히 파라미터가 두 개 이상이 되었을 때 키워드를 빠뜨리면 컴파일러가 사정없이 거절합니다.
Q5. WRITE 같은 문장에서 함수형 호출 결과를 바로 출력할 때 타입이 안 맞는다는 메시지가 납니다.
A. RETURNING 타입이 구조체나 객체 참조처럼 출력 가능한 단일 값이 아닐 때 발생합니다. WRITE 는 기본형(i, p, string 등)만 직접 받습니다. 객체나 구조체 필드를 출력하고 싶다면 WRITE / obj->get_struct( )-component 처럼 컴포넌트 접근을 추가하세요.
8. 응용 패턴 — 메서드 체이닝, NEW( ), CAST( ) 와 조합
함수형 호출의 진가는 다른 ABAP 7.40+ 표현식과 조합될 때 드러납니다. 대표적인 세 가지 조합을 정리합니다.
- NEW( ) 인스턴스 생성자 + 즉시 메서드 호출: 인스턴스를 임시 변수에 받지 않고 곧장 메서드를 호출합니다.
- CAST( ) 다운캐스트 + 함수형 호출: 인터페이스 참조를 구체 클래스로 캐스팅한 직후 특정 메서드를 부릅니다.
- 메서드 체이닝: RETURNING 이 객체/인터페이스 참조일 때
->로 연쇄 호출합니다.
" NEW( ) + 함수형 호출
DATA(lv_sum) = NEW zcl_calc_demo( )->add( iv_a = 1 iv_b = 2 ).
" 팩토리 + 체이닝
DATA(lv_net) = zcl_pricing_factory=>get_strategy( iv_country = 'KR'
)->calculate_net( iv_quantity = 5
iv_unit_price = '1000.00' ).
" CAST 조합 (인터페이스 -> 구현 클래스)
DATA(lo_iface) = zcl_pricing_factory=>get_strategy( iv_country = 'DE' ).
DATA(lv_special) = CAST zcl_pricing_de( lo_iface )->vat_amount( iv_base = 1000 ).
이러한 조합이 가능한 이유는 단순합니다. NEW, CAST, 함수형 호출 모두 ABAP에서 식(expression)으로 분류되며, 식은 다른 식의 피연산자가 될 수 있기 때문입니다. 결과적으로 우리는 명령형 ABAP을 더 선언적이고 함수형에 가까운 스타일로 표현할 수 있습니다.
한 가지 주의할 점은 가독성과 디버깅입니다. 체이닝이 너무 길어지면 어느 단계에서 예외가 발생했는지 디버거에서 추적하기 어렵습니다. 일반적으로 두 단계 정도까지는 한 줄 체이닝이 가독성에 도움이 되지만, 세 단계 이상이 된다면 중간 결과를 DATA( ) 로 받아 두는 편이 디버깅과 코드 리뷰 모두에 유리합니다.
요약하면, ABAP 함수형 메서드 호출은 RETURNING VALUE 단일 파라미터라는 작은 규칙 하나에서 출발해, 인라인 선언과 표현식 위치 사용을 통해 ABAP 코드의 표현력을 크게 확장합니다. 새 코드를 작성할 때는 "이 메서드는 결과 하나만 돌려주면 충분한가?"를 먼저 자문해 보세요. 답이 "그렇다"라면 RETURNING 으로 설계하고 함수형 호출의 모든 이점을 누리는 것이 일반적으로 권장됩니다.
댓글 0
아직 댓글이 없습니다.