Interrupción condicional en ABAP: La sentencia CHECK en LOOP, DO y FORM explicada

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

La sentencia CHECK es una sentencia de control en ABAP. Su propósito principal es controlar condicionalmente el flujo del programa, específicamente en los siguientes contextos:

  1. Dentro de bucles (DO, WHILE, LOOP AT): CHECK evalúa una condición. Si la condición es falsa, la iteración actual del bucle se interrumpe inmediatamente, y el programa salta a la siguiente iteración (similar a CONTINUE). Si la condición es verdadera, el procesamiento continúa normalmente después del CHECK.
  2. Dentro de subrutinas (FORM ... ENDFORM): CHECK evalúa una condición. Si la condición es falsa, se sale inmediatamente de toda la subrutina (FORM), y el control regresa a la parte del programa que la llamó (similar a EXIT dentro de un FORM). Si la condición es verdadera, el procesamiento en la subrutina continúa normalmente después del CHECK.

Importante: El uso de CHECK fuera de estos dos contextos (bucles y FORMs) generalmente no está previsto, produce errores de sintaxis o es parte de prácticas obsoletas. En métodos modernos (METHOD...ENDMETHOD), CHECK no se usa para salir del método (para eso se usa RETURN); sin embargo, dentro de un método, CHECK funciona normalmente si está dentro de un bucle.

Sintaxis

La sintaxis es muy simple:

CHECK <expresion_logica>.
  • <expresion_logica>: Esta es cualquier expresión que pueda evaluarse a un valor de verdad (abap_true o abap_false). Ejemplos son comparaciones (a = b, c > 10), verificaciones de valores iniciales (my_var IS NOT INITIAL), llamadas a funciones con valor de retorno booleano o simplemente una variable booleana.

Funcionamiento en detalle

La lógica central de CHECK es: Solo si la condición es verdadera, se continúa.

CHECK <condicion>. es funcionalmente equivalente a:

IF NOT <condicion>.
" Dentro de un bucle:
CONTINUE.
" Dentro de un FORM:
EXIT.
ENDIF.
" El código aquí solo se ejecuta si <condicion> era verdadera.

Esta lógica de “continuar si es verdadero” a veces puede percibirse como inversa a la sentencia IF, donde a menudo se maneja primero el “caso de error” (IF <condicion_error> THEN ... ENDIF).

Ejemplos

1. CHECK dentro de un bucle LOOP AT

Procesar solo ciertas entradas de una tabla:

TYPES: BEGIN OF ty_order,
order_id TYPE i,
status TYPE c LENGTH 1, " N=New, P=Processed, E=Error
END OF ty_order.
DATA: lt_orders TYPE STANDARD TABLE OF ty_order,
ls_order TYPE ty_order.
APPEND VALUE #( order_id = 1 status = 'N' ) TO lt_orders.
APPEND VALUE #( order_id = 2 status = 'P' ) TO lt_orders.
APPEND VALUE #( order_id = 3 status = 'N' ) TO lt_orders.
APPEND VALUE #( order_id = 4 status = 'E' ) TO lt_orders.
WRITE: / 'Procesando pedidos nuevos:'.
LOOP AT lt_orders INTO ls_order.
CHECK ls_order-status = 'N'. " Solo continuar si estado es 'N' (Nuevo)
" El siguiente código solo se ejecuta para pedidos 1 y 3
WRITE: / ' -> Procesando pedido:', ls_order-order_id.
" ... procesamiento adicional ...
ls_order-status = 'P'. " Cambiar estado (ejemplo)
MODIFY lt_orders FROM ls_order INDEX sy-tabix.
ENDLOOP.
WRITE: / 'Procesamiento completado.'.

Salida:

Procesando pedidos nuevos:
-> Procesando pedido: 1
-> Procesando pedido: 3
Procesamiento completado.

2. CHECK dentro de un bucle DO

Saltar ciertas iteraciones:

DO 5 TIMES.
WRITE: / 'Bucle DO, iteración:', sy-index.
CHECK sy-index MOD 2 = 1. " Solo continuar para iteraciones impares (1, 3, 5)
WRITE: ' -> Iteración impar fue procesada.'.
ENDDO.

Salida:

Bucle DO, iteración: 1
-> Iteración impar fue procesada.
Bucle DO, iteración: 2
Bucle DO, iteración: 3
-> Iteración impar fue procesada.
Bucle DO, iteración: 4
Bucle DO, iteración: 5
-> Iteración impar fue procesada.

3. CHECK dentro de una subrutina FORM

Salir prematuramente de la subrutina con parámetros inválidos:

START-OF-SELECTION.
PERFORM calculate_discount USING iv_amount = 100 iv_cust_type = 'A'.
PERFORM calculate_discount USING iv_amount = 200 iv_cust_type = 'X'. " Tipo inválido
PERFORM calculate_discount USING iv_amount = -50 iv_cust_type = 'B'. " Importe inválido
FORM calculate_discount USING iv_amount TYPE p DECIMALS 2
iv_cust_type TYPE c LENGTH 1.
WRITE: / 'FORM llamado con importe:', iv_amount, 'Tipo:', iv_cust_type.
" Validaciones de entrada
CHECK iv_amount > 0. " Salir si importe no es positivo
CHECK iv_cust_type = 'A' OR
iv_cust_type = 'B'. " Salir si tipo de cliente es inválido
" --- Solo continuar aquí si todos los CHECKs fueron exitosos ---
DATA lv_discount TYPE p DECIMALS 2.
IF iv_cust_type = 'A'.
lv_discount = iv_amount * '0.1'. " 10%
ELSE. " Debe ser 'B'
lv_discount = iv_amount * '0.05'. " 5%
ENDIF.
WRITE: ' -> Descuento calculado:', lv_discount.
ENDFORM.

Salida:

FORM llamado con importe: 100.00 Tipo: A
-> Descuento calculado: 10.00
FORM llamado con importe: 200.00 Tipo: X
FORM llamado con importe: -50.00 Tipo: B

(Se puede ver que en las llamadas 2 y 3 el procesamiento después del CHECK fallido ya no ocurre).

Diferencia con CONTINUE, EXIT, RETURN

  • CONTINUE (en bucles): Salta siempre a la siguiente iteración del bucle.
  • EXIT (en bucles/FORMs): Sale siempre de todo el bucle o FORM.
  • RETURN (en métodos/módulos de funciones): Sale siempre del método/módulo de funciones.
  • CHECK <condicion>.: Es condicional. Solo si la condición es falsa, se ejecuta un CONTINUE implícito (en bucles) o EXIT (en FORMs).

Notas importantes / Mejores prácticas

  • Aunque CHECK es funcionalmente correcto, muchos desarrolladores ABAP hoy prefieren construcciones IF explícitas con CONTINUE, EXIT o RETURN.
    " En lugar de: CHECK <condicion>.
    IF NOT <condicion>.
    CONTINUE. " o EXIT / RETURN
    ENDIF.
    Esto a menudo se considera más legible y expresa la intención más claramente, ya que la lógica IF NOT puede ser más directa.
  • Comprender CHECK es importante para el mantenimiento y análisis de código existente, especialmente código más antiguo que usa rutinas FORM.