Subroutines in SAP ABAP

Local Data in the Subroutine Locate the document in its SAP Library structure

Data declarations in procedures create local data types and objects that are only visible within that procedure. There are two kinds of data types and objects – dynamic and static. Dynamic data objects only exist while the subroutine is running, while static objects still exist after the subroutine has finished running, and retain their values until the next time the subroutine is called. Field symbols can be declared locally. You can also use a special kind of data object for subroutines – copies of global data on a local data stack. You define and address them using field symbols.

Dynamic Local Data Types and Objects

Local data types and objects declared in subroutines using the TYPES and DATA statements are deleted when the subroutine ends, and recreated each time the routine is called.

Every subroutine has its own local naming space. If you declare a local data type or object with the same name as a global data type or object, the global type or object cannot be addressed from within the subroutine. Local data types or data objects hide identically named global data types or objects. This means that if you use the name of a data type or object in the subroutine, you always address a locally declared object – if this exists – and otherwise a globally declared one. To avoid this, you must assign other names to local types and objects. For example, you might name all of your local data starting with ‘L_’.

Example

REPORT demo_mod_tech_data_types .

TYPES word(10) TYPE c.
DATA  text TYPE word.

text = '1234567890'. WRITE / text.

PERFORM datatest.

WRITE / text.

FORM datatest.
  TYPES word(5) TYPE c.
  DATA  text TYPE word.
  text = 'ABCDEFGHJK'. WRITE / text.
ENDFORM.

When you run the program, the following is displayed:

1234567890

ABCDE

1234567890

In this example, a data type WORD and a data object TEXT with type WORD are declared globally in the main program. After assigning a value to TEXT and writing it to the list, the internal subroutine DATATEST is called. Inside the subroutine, a data type WORD and a data object TEXT with type WORD are declared locally. They hide the global type and object. Only after exiting the subroutine the global definitions are valid again.

Static Local Data Objects

If you want to keep the value of a local data object after exiting the subroutine, you must use the STATICS statement to declare it instead of the DATA statement. With STATICS you declare a data object that is globally defined, but only locally visible from the subroutine in which it is defined.

Example

REPORT demo_mod_tech_statics.

PERFORM datatest1.
PERFORM datatest1.

SKIP.

PERFORM datatest2.
PERFORM datatest2.

FORM datatest1.
  TYPES f_word(5) TYPE c.
  DATA  f_text TYPE f_word VALUE 'INIT'.
  WRITE f_text.
  f_text = '12345'.
  WRITE f_text.
ENDFORM.

FORM datatest2.
  TYPES    f_word(5) TYPE c.
  STATICS  f_text TYPE f_word VALUE 'INIT'.
  WRITE f_text.
  f_text = 'ABCDE'.
  WRITE f_text.
ENDFORM.

When you run the program, the following is displayed:

INIT 12345 INIT 12345

INIT ABCDE ABCDE ABCDE

In this example, two similar subroutines DATATEST1 and DATATEST2 are defined. In DATATEST2, the STATICS statement is used instead of the DATA statement to declare the data object F_TEXT. During each call of DATATEST1, F_TEXT is initialized again, but it keeps its value for DATATEST2. The VALUE option of the STATICS statement functions only during the first call of DATATEST2.
Global Data from the Main Program Locate the document in its SAP Library structure

Subroutines can access all of the global data in the program in which they are defined (main program). You therefore do not need to define a parameter interface if you do not want to change any data in the subroutine, or if very little data is involved.

Example

FORM HEADER.

   WRITE: / 'Program started by', SY-UNAME,
/ 'on host', SY-HOST,
'date:', SY-DATUM, 'time:', SY-UZEIT.
   ULINE.

ENDFORM.

This example creates a subroutine called HEADER, which, like the example of an include program, displays a list header.

However, if you want subroutines to perform complex operations on data without affecting the global data in the program, you should define a parameter interface through which you can pass exactly the data you need. In the interests of good programming style and encapsulation, you should always use a parameter interface, at least when the subroutine changes data.

Protecting Global Data Objects Against Changes

To prevent the value of a global data object from being changed inside a subroutine, use the following statement:

LOCAL <f>.

This statement may only occur between the FORM and ENDFORM statements. With LOCAL, you can preserve the values of global data objects which cannot be hidden by a data declaration inside the subroutine.

For example, you cannot declare a table work area that is defined by the TABLES statement with another TABLES statement inside a subroutine. If you want to use the table work area locally, but preserve its contents outside the subroutine, you must use the LOCAL statement.

Example

PROGRAM FORM_TEST.

TABLES SFLIGHT.

PERFORM TABTEST1.
WRITE: / SFLIGHT-PLANETYPE, SFLIGHT-PRICE.

PERFORM TABTEST2.
WRITE: / SFLIGHT-PLANETYPE, SFLIGHT-PRICE.

FORM TABTEST1.
   SFLIGHT-PLANETYPE = 'A310'.
   SFLIGHT-PRICE = '150.00'.
   WRITE: / SFLIGHT-PLANETYPE, SFLIGHT-PRICE.
ENDFORM.

FORM TABTEST2.
   LOCAL SFLIGHT.
   SFLIGHT-PLANETYPE = 'B747'.
   SFLIGHT-PRICE = '500.00'.
   WRITE: / SFLIGHT-PLANETYPE, SFLIGHT-PRICE.
ENDFORM.

When you run the program, the following is displayed:

A310 150.00

A310 150.00

B747 500.00

A310 150.00

The program creates a table work area SFLIGHT for the database table SFLIGHT. Different values are assigned to the table work area SFLIGHT in TABTEST1 and TABTEST2. While the values assigned in TABTEST1 are valid globally, the values assigned in TABTEST2 are only valid locally.

Defining Subroutines Locate the document in its SAP Library structure

A subroutine is a block of code introduced by FORM and concluded by ENDFORM.

FORM <subr> [USING   ... [VALUE(]<pi>[)] [TYPE <t>|LIKE <f>]... ]
            [CHANGING... [VALUE(]<pi>[)] [TYPE <t>|LIKE <f>]... ].

 ...

ENDFORM.

<subr> is the name of the subroutine. The optional additions USING and CHANGING define the parameter interface. Like any other processing block, subroutines cannot be nested. You should therefore place your subroutine definitions at the end of the program, especially for executable programs (type 1). In this way, you eliminate the risk of accidentally ending an event block in the wrong place by inserting a FORM...ENDFORM block.

Data Handling in Subroutines

Global Data from the Main Program

Local Data in the Subroutine

The Parameter Interface

Examples of Subroutines Locate the document in its SAP Library structure

Example of Passing Parameters by Reference

 Example

PROGRAM FORM_TEST.

DATA: NUM1 TYPE I,
NUM2 TYPE I,
SUM TYPE I.

NUM1 = 2. NUM2 = 4.
PERFORM ADDIT USING NUM1 NUM2 CHANGING SUM.

NUM1 = 7. NUM2 = 11.
PERFORM ADDIT USING NUM1 NUM2 CHANGING SUM.

FORM ADDIT
       USING ADD_NUM1
             ADD_NUM2
       CHANGING ADD_SUM.

  ADD_SUM = ADD_NUM1 + ADD_NUM2.
  PERFORM OUT USING ADD_NUM1 ADD_NUM2 ADD_SUM.

ENDFORM.

FORM OUT
       USING OUT_NUM1
             OUT_NUM2
             OUT_SUM.

  WRITE: / 'Sum of', OUT_NUM1, 'and', OUT_NUM2, 'is', OUT_SUM.

ENDFORM.

The produces the following output:

Sum of 2 and 4 is 6

Sum of 7 and 11 is 18

In this example, the actual parameters NUM1, NUM2, and SUM are passed by reference to the formal parameters of the subroutine ADDIT. After changing ADD_SUM, the latter parameters are then passed to the formal parameters OUT_NUM1, OUT_NUM2, and OUT_SUM of the subroutine OUT.

Input parameters which are changed in the subroutine are also changed in the calling program. To prevent this, you must pass the parameter by value in a USING addition.

Example of passing parameters by reference

Example

PROGRAM FORM_TEST.

DATA: NUM TYPE I VALUE 5,
FAC TYPE I VALUE 0.

PERFORM FACT USING NUM CHANGING FAC.

WRITE: / 'Factorial of', NUM, 'is', FAC.

FORM FACT
       USING VALUE(F_NUM)
       CHANGING F_FACT.

  F_FACT = 1.
  WHILE F_NUM GE 1.
    F_FACT = F_FACT * F_NUM.
    F_NUM = F_NUM - 1.
  ENDWHILE.

ENDFORM.

The produces the following output:

Factorial of 5 is 120

To ensure that an input parameter is not changed in the calling program, even if it is changed in the subroutine, you can pass data to a subroutine by value. In this example, the factorial of a number NUM is calculated. The input parameter NUM is passed to the formal parameter F_NUM of the subroutine. Although F_NUM is changed in the subroutine, the actual parameter NUM keeps its old value. The output parameter FAC is passed by reference.

Example of output parameters

Example

PROGRAM FORM_TEST.

DATA: OP1 TYPE I,
OP2 TYPE I,
RES TYPE I.

OP1 = 3.
OP2 = 4.

PERFORM MULTIP
          USING OP1 OP2
          CHANGING RES.

WRITE: / 'After subroutine:',
/ 'RES=' UNDER 'RES=', RES.

FORM MULTIP
       USING VALUE(O1)
             VALUE(O2)
     CHANGING VALUE(R).

    R = O1 * O2.
    WRITE: / 'Inside subroutine:',
/ 'R=', R, 'RES=', RES.

ENDFORM.

The produces the following output:

Inside subroutine:

R= 12 RES= 0

After subroutine:

              RES= 12

To return a changed formal parameter once the subroutine has finished successfully, you can use a CHANGING parameter and pass the parameter by reference. In this example, the actual parameters OP1 and OP2 are passed by value in the USING addition to the formal parameters O1 and O2. The actual parameter RES is passed by value to the formal parameter R using CHANGING. By writing R and RES onto the screen from within the subroutine, it is demonstrated that RES has not changed its contents before the ENDFORM statement. After returning from the subroutine, its contents have changed.

Example of passing structures

Example

PROGRAM FORM_TEST.

TYPES: BEGIN OF LINE,
         NAME(10)   TYPE C,
         AGE(2)     TYPE N,
         COUNTRY(3) TYPE C,
       END OF LINE.

DATA WHO TYPE LINE.

WHO-NAME = 'Karl'. WHO-AGE = '10'. WHO-COUNTRY = 'D'.

PERFORM COMPONENTS CHANGING WHO.

WRITE: / WHO-NAME, WHO-AGE, WHO-COUNTRY.

FORM COMPONENTS
       CHANGING VALUE(PERSON) TYPE LINE.

  WRITE: / PERSON-NAME, PERSON-AGE, PERSON-COUNTRY.
  PERSON-NAME = 'Mickey'.
  PERSON-AGE = '60'.
  PERSON-COUNTRY = 'USA'.

ENDFORM.

The produces the following output:

Karl       10 D

MICKEY 60 USA

The actual parameter WHO with the user-defined, structured data type LINE is passed to the formal parameter PERSON. The formal parameter PERSON is typed with TYPE LINE. Since LINE is a user-defined data type, the type of PERSON is completely specified. The subroutine accesses and changes the components of PERSON. They are then returned to the components of WHO in the calling program.

Example of passing internal tables

Example

PROGRAM FORM_TEST.

DATA: BEGIN OF LINE,
COL1 TYPE I,
COL2 TYPE I,
END OF LINE.

DATA ITAB LIKE STANDARD TABLE OF LINE.

PERFORM FILL CHANGING ITAB.

PERFORM OUT USING ITAB.

FORM FILL CHANGING F_ITAB LIKE ITAB.

  DATA F_LINE LIKE LINE OF F_ITAB.

  DO 3 TIMES.
    F_LINE-COL1 = SY-INDEX.
    F_LINE-COL2 = SY-INDEX ** 2.
    APPEND F_LINE TO F_ITAB.
  ENDDO.

ENDFORM.

FORM OUT USING VALUE(F_ITAB) LIKE ITAB.

  DATA F_LINE LIKE LINE OF F_ITAB.

  LOOP AT F_ITAB INTO F_LINE.
    WRITE: / F_LINE-COL1, F_LINE-COL2.
  ENDLOOP.

ENDFORM.

The produces the following output:

         1          1

         2          4

         3          9

You can define the types of the formal parameters of the parameter interfaces of procedures as internal tables. In the example, the subroutines FILL and OUT each have one formal parameter defined as an internal table. An internal table without header line is passed to the subroutines. Each subroutine declares a work area F_LINE as a local data object. Were ITAB a table with a header line, you would have to replace ITAB with ITAB[] in the PERFORM and FORM statements.

Example of the TABLES parameter

This example is provided for completeness. The TABLES parameter is only supported for the sake of compatibility and should not be used.

Example

PROGRAM FORM_TEST.

TYPES: BEGIN OF LINE,
COL1 TYPE I,
COL2 TYPE I,
END OF LINE.

DATA: ITAB TYPE STANDARD TABLE OF LINE WITH HEADER LINE,
      JTAB TYPE STANDARD TABLE OF LINE.

PERFORM FILL TABLES ITAB.

MOVE ITAB[] TO JTAB.

PERFORM OUT TABLES JTAB.

FORM FILL TABLES F_ITAB LIKE ITAB[].

  DO 3 TIMES.
    F_ITAB-COL1 = SY-INDEX.
    F_ITAB-COL2 = SY-INDEX ** 2.
    APPEND F_ITAB.
  ENDDO.

ENDFORM.

FORM OUT TABLES F_ITAB LIKE JTAB.

  LOOP AT F_ITAB.
    WRITE: / F_ITAB-COL1, F_ITAB-COL2.
  ENDLOOP.

ENDFORM.

The produces the following output:

         1          1

         2          4

         3          9

In this example, an internal table ITAB is declared with a header line and an internal table JTAB is declared without a header line. The actual parameter ITAB is passed to the formal parameter F_ITAB of the subroutine FILL in the TABLES addition. The header line is passed with it. After the body of the table has been copied from ITAB to JTAB, the actual parameter is passed to the formal parameter F_ITAB of the subroutine OUT using the TABLES addition. The header line F_ITAB, which is not passed, is generated automatically in the subroutine.



Passing Parameters to Subroutines Locate the document in its SAP Library structure

If a subroutine has a parameter interface, you must supply values to all of the formal parameters in its interface when you call it. You list the actual parameters after the USING or CHANGING addition in the PERFORM statement.

When you pass the values, the sequence of the actual parameters in the PERFORM statement is crucial. The value of the first actual parameter in the list is passed to the first formal parameter, the second to the second, and so on. The additions USING and CHANGING have exactly the same meaning. You only need to use one or the other. However, for documentary reasons, it is a good idea to divide the parameters in the same way in which they occur in the interface definition.

Actual parameters can be any data objects or field symbols of the calling program whose technical attributes are compatible with the type specified for the corresponding formal parameter. When you specify the actual parameters, note that any that you pass by reference to a formal parameter, and any that you pass by value to an output parameter, can be changed by the subroutine. You should therefore ensure that only data objects that you want to be changed appear in the corresponding position of the actual parameter list.

If a subroutine contains TABLES parameters in its interface, you must specify them in a TABLES addition of the PERFORM statement before the USING and CHANGING parameters. TABLES parameters are only supported to ensure compatibility with earlier releases, and should no longer be used.

You can use offset addressing for actual parameters in the same way as offset addressing for field symbols. That is, you can select memory areas that lie outside the boundaries of the specified actual parameter.

Example

PROGRAM form_test.

DATA: a1 TYPE p DECIMALS 3,
      a2 TYPE i,
      a3 TYPE d,
      a4 TYPE spfli-carrid,
      a5(1) TYPE c.

...

PERFORM subr USING a1 a2 a3 a4 a5.

...

PERFORM subr CHANGING a1 a2 a3 a4 a5.

...

PERFORM subr USING a1 a2 a3
             CHANGING a4 a5.

...

FORM subr USING
            value(f1) TYPE p
            value(f2) TYPE i
            f3        LIKE a3
          CHANGING
            value(f4) TYPE spfli-carrid
            f5.
...
ENDFORM.

This example defines a subroutine SUBR with a parameter interface consisting of five formal parameters, F1 to F5. The subroutine is called internally three times. The actual parameters are the data objects A1 to A5. The three subroutine calls are all equally valid. There are further PERFORM statements that are also equally valid, so long as the sequence of the actual parameters remains unchanged. In each call, A1 is passed to F1, A2 to F2, and so on. When the subroutine ends, A3, A4, and A5 receive the values of F3, F4, and F5 respectively. The third of the subroutine calls documents in the program what the parameter interface of the subroutine shows, namely that only A4 and A5 are changed. Whether A3 is changed depends on the way in which the subroutine is programmed.

The following example shows how generically-typed formal parameters inherit their technical attributes from their corresponding actual parameters.

Example

REPORT demo_mod_tech_describe.

DATA:
  date1      TYPE d,             date2      TYPE t,
  string1(6) TYPE c,             string2(8) TYPE c,
  number1    TYPE p DECIMALS 2,  number2    TYPE p DECIMALS 0,
  count1     TYPE i,             count2     TYPE i.

PERFORM typetest USING date1 string1 number1 count1.
SKIP.
PERFORM typetest USING date2 string2 number2 count2.

FORM typetest USING now
                    txt TYPE c
                    value(num) TYPE p
                    int TYPE i.
  DATA: t(1) TYPE c.
  DESCRIBE FIELD now TYPE t.
  WRITE: / 'Type of NOW is', t.
  DESCRIBE FIELD txt LENGTH t IN CHARACTER MODE.
  WRITE: / 'Length of TXT is', t.
  DESCRIBE FIELD num DECIMALS t.
  WRITE: / 'Decimals of NUM are', t.
  DESCRIBE FIELD int TYPE t.
  WRITE: / 'Type of INT is', t.
ENDFORM.

This produces the following output:

Type of NOW is D
Length of TXT is 6
Decimals of NUM are 2
Type of INT is I

Type of NOW is T
Length of TXT is 8
Decimals of NUM are 0
Type of INT is I

An internal subroutine TYPETEST is called twice with different actual parameters. All actual and formal parameters are compatible and no error message occurs during the syntax check. Had you declared COUNT2 with type F instead of type I, the syntax check would have returned an error, since the formal parameter INT is specified with type I. The formal parameters with generic types adopt different technical attributes depending on their corresponding technical attributes.


Popular posts from this blog

How to create Interactive Report in SAP ABAP

How to create ALV Interactive Report in SAP ABAP

BDC Call Transaction Method Program