Day 17

Modularization: Events and Subroutines


After you have completed this chapter, you will be able to

Modularization Units in ABAP/4

A modularization unit is a like a shell into which you can put code. It allows you to segregate a group of lines of code from the rest, and then execute them at a specific time. The lines of code within a modularization unit act very much like a mini-program that can be called from another program.

ABAP/4 offers three types of modularization units:

This chapter explains events and subroutines. The next chapter explains function modules.

Use modularization units to eliminate redundant code within your program and to make your program easier to read. For example, suppose you have a series of statements that format a mailing address, and you need to format mailing addresses at several different places in your program. Instead of duplicating the code within your program, it's a good idea to place that code into a modularization unit and call it whenever you need to format an address.

Events

Contrary to first appearances, ABAP/4 programs are event-driven. A good understanding of events are the key to a good understanding of ABAP/4.

Defining Events

An event is a tag that identifies a section of code. The section of code associated with an event begins with an event name and ends when the next event name is encountered. In Listing 17.1, the event names are initialization, start-of-selection, and end-of-selection. Event names are reserved words. You cannot create new events-you can only use existing ones.


Listing 17.1  Three Basic Events

1  report ztx1701.
2  initialization.
3    write / '1'.
4
5  start-of-selection.
6    write / '2'.
7
8  end-of-selection.
9    write / '3'.

The code in Listing 17.1 produces the following output:

  1
  2
  3

A driver program is one program that controls another (driven) program. SAP supplies driver programs with the R/3 system. You supply the driven program. When you start your program, a driver program always starts first, and then it calls the events in your program. To reiterate, a driver program starts first and then controls when your program gets control. This has always been the case for all of the programs you have written so far; you just have not been aware of it until now. Please be sure you read this paragraph carefully. To repeat once more, when you start your program, a driver program starts first and controls your program by calling events within it.

The code associated with an event is triggered by a statement in a driver program. Events are triggered by the driver program in a predefined and predictable sequence. Figure 17.1 illustrates this point.

Figure 17.1 : The driver program and the events it can trigger.

Figure 17.1 has pseudocode within the driver program. The code shown in the program on the right is actual code. When program ztx1701 is executed, the driver on the left starts first. The program then follows this sequence of steps:

The order of execution for events is determined by the driver program, not by your program. Therefore, you can code the events in any order and the execution order will still be the same. The order of events in your program doesn't matter; they will always be triggered in the same sequence by the driver program. Listing 17.2 illustrates this point.


Listing 17.2  Events Triggered in the Order Dictated by the Driver Program

1  report ztx1702.
2  data f1 type i value 1.
3 
4  end-of-selection.
5    write: / '3.  f1 =', f1.
6 
7  start-of-selection.
8    write: / '2.  f1 =', f1.
9    f1 = 99.
10
11 initialization.
12   write: / '1.  f1 =', f1.
13   add 1 to f1.

The code in Listing 17.2 produces the following output:

1.  f1 =          1 
2.  f1 =          2 
3.  f1 =         99

This example illustrates that you can put the events in a different order, but the execution sequence is not changed. The execution sequence is always initialization, start-of-selection, end-of-selection. There are other events as well; some occur after initialization and some occur between start-of-selection and end-of-selection.

Programmers usually position events in the order in which they are triggered to make their programs easier to understand.

There are eleven different events in ABAP/4, categorized in Table 17.1 according to how they are triggered.

Table 17.1  ABAP/4 Events
Category
Events
Driverinitialization
at selection-screen
start-of-selection
get
end-of-selection
Userat line-selection
at pfn
at user-command
Programtop-of-page
end-of-page

Driver events are triggered by the driver program. User events are triggered by the user via the user interface. Program events are those triggered from within your program. This chapter details the use of initialization, start-of-selection, and end-of-selection. Note that some of these events occur between start-of-selection and end-of-selection.

In the previous chapter, "Formatting Techniques, Part 2," you learned about the top-of-page and bottom-of-page events. The information in this chapter also applies to them, but these are triggered by statements inside your program, not from the driver.

Special Considerations When Using write Within Events

Events have two unusual affects on the write statement:

Triggering top-of-page

This section describes when top-of-page is triggered in relation to driver program events. If your program doesn't have a selection screen, the first write statement executed triggers top-of-page. If your program does have a selection screen, is it possible for top-of-page to be triggered twice:

Only if you are doing something unusual in top-of-page, like opening files or initializing data, do you have to be wary of the double-trigger effect.

If top-of-page is triggered twice, you will only see the output from write statements within it the second time it is triggered. The output created by write statements during the first time it is triggered is discarded. This double-triggering doesn't usually cause any problems with your program or with your output because

NOTE
The write to variation of the write statement doesn't trigger top-of-page.

Defaulting to start-of-selection

If the first executable statement in your program is not preceded by an event name, at runtime the system automatically inserts start-of-selection before the first line of executable code. Therefore, if you haven't coded any events, or you have put code at the top of the program without naming an event, start-of-selection is assumed. Listing 17.3 provides an example of this, in a program containing both a selection screen and events. It also contains a program-driven event-top-of-page.


Listing 17.3  start-of-selection Automatically Inserted Before the First Line of Code

1  report ztx1703 no standard page heading.
2  parameters p1(8).
3
4  write: / 'p1 =', p1.
5
6  initialization.
7    p1 = 'Init'.
8
9  end-of-selection.
10   write: /(14) sy-uline,
11          / 'End of program'.
12
13 top-of-page.
14   write: / 'This is My Title'.
15   skip.

The code in Listing 17.3 produces the following output:

This is My Title
p1 = INIT      
--------------
End of program

You cannot put a condition around an event or enclose an event in a loop. To do so will cause a syntax error. For example, the code in Listing 17.4 causes a syntax error.


Listing 17.4  Don't Enclose an Event Within a Condition or a Loop

1  report ztx1704.
2  data f1.
3 
4  start-of-selection.
5    f1 = 'A'.
6 
7  if f1 = 'A'.
8    end-of-selection.
9    write: / f1.
10   endif.

The code in Listing 17.4 produces this syntax error: Incorrect nesting: before the statement "END-OF-SELECTION", the structure introduced by "IF" must be concluded by "ENDIF".

Event names have higher priority than other ABAP/4 statements. The if statement on line 7 belongs to the start-of-selection event. The endif statement on line 10 belongs to the end-of-selection event. You close all open conditions and loops within the event to which they belong. Therefore, this program must have an endif before the end-of-selection event. Because there is also an endif within end-of-selection on line 10, that endif would have to be removed before the program would run.

You should not put data definitions within events. Although this doesn't cause a syntax error, it is poor programming style. All data definitions should be done at the top of the program.

Each event has a specific purpose and is needed to accomplish a specific programming task. As the need arises, I will refer to them in the material that follows. If you don't see any events in a program, always remember that one still exists-start-of-selection.

Leaving an Event

You can exit out of an event at any time using the following statements:

At this time, please review the function of the check statement (presented in Chapter 10, "Common Control Statements").

The following paragraphs describe the effect of check and exit when they are coded outside a loop. The effect of stop is the same regardless of whether is it coded within a loop or not.

NOTE
Although at this point only three events have been presented in detail, this section is written in a general sense so that it will apply equally well after you have learned to use all events.

In all events

In events that occur before start-of-selection

In start-of-selection and events that occur after it

CAUTION
Don't use stop in the following events: initialization, at selection-screen output, top-of-page, and end-of-page. Technically, stop can work with top-of-page and end-of-page if you refrain from issuing write statements within end-of-selection afterward. In the case of top-of-page a write, can cause a short dump; in the case of end-of-page, you can lose output. It is safer to avoid it altogether within these events.

check, exit, and stop do not set the value of sy-subrc. If you want to set it, you can assign a numeric value to it before leaving.

The report shown in Listing 17.5 allows you to try the effects of these statements within various events. Copy it and remove comments one at a time to experiment with the possible variations.


Listing 17.5  Effects of exit, check, and stop Within Events

1  report ztx1705 no standard page heading line-count 6(2).
2  *in events before start-of-selection:
3  *   - exit and check have the same behavior. They both leave the event
4  *     and processing continues with the next event or action.
5  *   - stop goes directly to the end-of-selection event
6  *     (don't use stop in initialization or at selection-screen output)
7
8  *in start-of-selection and subsequent events:
9  *   - exit terminates the report and shows the output list
10 *     exception: top-of-page: exit leaves the event
11 *   - check leaves the event and processing continues with the next one.
12 *   - stop goes directly to the end-of-selection event
13
14                                            "execute an:
15 parameters: exit_sos radiobutton group g1, "exit in start-of-selection
16             exit_eos radiobutton group g1, "exit in end-of-selection
17             chck_sos radiobutton group g1, "check in start-of-selection
18             chck_eos radiobutton group g1, "check in end of selection
19             stop_sos radiobutton group g1, "stop in start-of-selection
20             stop_eos radiobutton group g1, "stop in end-of-selection
21             none     radiobutton group g1. "no stop, exit or check
22
23 initialization.
24 *   exit.                          "exits event
25 *   check 1 = 2.                   "exits event
26 *   stop.                          "don't do this
27     chck_sos = 'X'.
28
29 at selection-screen output.
30 *   exit.                          "exits event
31 *   check 1 = 2.                   "exits event
32 *   stop.                          "don't do this
33     message s789(zk) with 'at selection-screen output'.
34
35 at selection-screen on radiobutton group g1.
36 *   exit.                          "exits event
37 *   check 1 = 2.                   "exits event
38 *   stop.                          "goes to end-of-selection
39     message i789(zk) with 'at selection-screen on rbg'.
40
41 at selection-screen.
42 *   exit.                          "exits event
43 *   check 1 = 2.                   "exits event
44 *   stop.                          "goes to end-of-selection
45     message i789(zk) with 'at selection-screen'.
46
47 start-of-selection.
48     write: / 'Top of SOS'.
49     if      exit_sos = 'X'.
50         exit.                      "exits report
51     elseif  chck_sos = 'X'.
52         check 1 = 2.               "exits event
53     elseif  stop_sos = 'X'.
54         stop.                      "goes to end-of-selection
55         endif.
56     write: / 'Bottom of SOS'.
57
58 end-of-selection.
59     write: / 'Top of EOS'.
60     if      exit_eos = 'X'.
61         exit.                      "exits report
62     elseif  chck_eos = 'X'.
63         check 1 = 2.               "exits report
64     elseif  stop_eos = 'X'.
65         stop.                      "exits report
66         endif.
67     write: / 'Bottom of EOS'.
68     write: / '1',
69            / '2',
70            / '3'.
71
72 top-of-page.
73     write: / 'Title'.
74 *   exit.                  "exits event and returns to write statement
75 *   check 'X' = 'Y'.       "exits event and returns to write statement
76 *   stop.                  "goto end-of-selection - don't write after it
77     uline.
78
79 end-of-page.
80     uline.
81 *   exit.                  "exits report
82 *   check 'X' = 'Y'.       "exits event and returns to write statement
83 *   stop.                  "goto end-of-selection - don't write after it
84     write: / 'Footer'.

Returning from the List

Let's look more closely at events in the context of a report that has a selection screen. (Recall that the parameters statement generates a selection screen.)

When the user executes the report, the driver triggers initialization and then shows the selection screen. After pressing the Execute button, the driver triggers the remaining events, the program ends and the user sees the list. The user presses the Back button to return. The driver then restarts processing beginning at the top of the event list. It triggers the initialization event, and then all subsequent events follow again in their normal sequence. The result is that the user sees the selection screen after pressing the Back button. There is, however, a difference in processing when a restart occurs.

The selection screen has its own copy of all variables that are displayed on it. The first time the report runs and the driver program regains control after the initialization event has finished, it copies values from program variables to the corresponding selection screen variables and displays them. The user can modify the input fields. When the user presses the Execute button, the driver stores the values from the selection screen into two data areas: one belonging to the selection screen and then into your program's variables.

However, this dual action only occurs the first time you run the program. When the user presses Back from the list, initialization is triggered again. When control returns to the driver, it doesn't copy your program variables into the screen data area. Instead, it shows the existing values from the screen data area; it still contains the values the user entered. The result is that the user sees the values that he last entered regardless of what has changed in your program. Then, after the user presses the Execute button, the values onscreen are copied to the screen's data area and then to your program, overwriting any differences. For example, if you set up values during initialization, those values will be seen on the selection screen when you start the program. When you press the Back button on the selection screen, initialization will execute but values set within it won't be shown. The user will instead see the values that he entered.

Subroutines

A subroutine is a reusable section of code. It is like a mini-program that can be called from another point in your program. Within it you can define variables, execute statements, compute results, and write output. To define a subroutine, use the form statement to indicate the start of a subroutine, and use endform to indicate the end of the subroutine. The name of a subroutine cannot exceed 30 characters.

To call a subroutine, use the perform statement.

Listing 17.6 provides a sample program that defines and calls a subroutine.


Listing 17.6  Defining and Calling a Subroutine

1  report ztx1706.
2
3  write: / 'Before call 1'.
4  perform sub1.
5  write: / 'Before call 2'.
6  perform sub1.
7  write: / 'After calls'.
8
9  form sub1.
10    write: / 'Inside sub1'.
11    endform.

The code in Listing 17.6 produces the following output:

Before call 1
Inside sub1
Before call 2
Inside sub1
After calls

There are two types of subroutines:

Listing 17.6 illustrated a call to an internal subroutine.

Defining and Calling Internal Subroutines

Subroutine definitions are usually placed at the end of the program, after all events. The form statement defines the end of the preceding event, and the beginning of a subroutine. Subroutines cannot be nested inside of events.

Syntax for the form Statement

form s [tables t1 t2 ...]
       [using u1 value(u2) ...]
       [changing c1 value(c2) ...].
    ---
    endform.

where:

The following points apply:

Syntax for the perform Statement

perform a) s
        b) n of s1 s2 s3 ...
                                 [tables t1 t2 ...]
                                 [using u1 u2 ...]
                                 [changing c1 c2 ...].

where:

Using syntax b) you can specify that one of a list of subroutines be performed. The nth subroutine in the list of subroutine names following of is performed. For example, if n is 2, the second subroutine in the list will be performed. Listing 17.7 illustrates this syntax.


Listing 17.7  Calling a Series of Subroutines

1  report ztx1707.
2  do 3 times.
3      perform sy-index of s1 s2 s3.
4      enddo.
5
6  form s1.
7      write: / 'Hi from s1'.
8      endform.
9
10 form s2.
11     write: / 'Hi from s2'.
12     endform.
13
14 form s3.
15     write: / 'Hi from s3'.
16     endform.

The code in Listing 17.7 produces the following output:

Hi from s1
Hi from s2
Hi from s3

Leaving a Subroutine

You can exit out of a subroutine at any time using the following statements:

The following paragraphs describe the effect of check and exit when they are coded within a subroutine but outside of a loop. The effect of stop within a subroutine is the same, regardless of whether is it coded within a loop.

In subroutines

check, exit, and stop do not set the value of sy-subrc. If you want to set it, assign a numeric value to it before leaving.

Listing 17.8 illustrates the effects of these statements within subroutines.


Listing 17.8  Effects of exit, check, and stop Within a Subroutine

1  report ztx1708.
2  data f1 value 'X'.
3
4  clear sy-subrc.
5  perform s1. write: / 'sy-subrc =', sy-subrc.
6  perform s2. write: / 'sy-subrc =', sy-subrc.
7  perform s3. write: / 'sy-subrc =', sy-subrc.
8  perform s4. write: / 'sy-subrc =', sy-subrc.
9
10 end-of-selection.
11     write:  'Stopped, sy-subrc =', sy-subrc.
12     if sy-subrc = 7.
13         stop.
14         endif.
15     write: / 'After Stop'.
16
17 form s1.
18     do 4 times.
19         exit.
20         enddo.
21     write / 'In s1'.
22     exit.
23     write / 'After Exit'.
24     endform.
25
26 form s2.
27     do 4 times.
28         check f1 = 'Y'.
29         write / sy-index.
30         enddo.
31     write / 'In s2'.
32     check f1 = 'Y'.
33     write / 'After Check'.
34     endform.
35
36 form s3.
37     do 4 times.
38         sy-subrc = 7.
39         stop.
40         write / sy-index.
41         enddo.
42     endform.
43
44 form s4.
45     write: / 'In s4'.
46     endform.

The code in Listing 17.8 produces the following output:

In s1
sy-subrc =     0
In s2
sy-subrc =     0

Stopped, sy-subrc =     7

Defining Global and Local Variables

A global variable is one that is defined outside of a subroutine by using the tables or data statement. It can be accessed from any point in the program, be it inside an event or inside a subroutine. It is good programming practice to place global variable definitions at the top of the program, somewhere before the first line of executable code.

A local variable is a variable that is defined inside a subroutine using the local, data, or statics statement. It is said to be local to the subroutine. Variables defined by using local are accessible from outside the subroutine; variables defined by using data or statics are not. Thus if the subroutine calls another subroutine, variables defined by using local are visible from within the called subroutine-variables defined by using data or statics are not.

For local variables defined by using local or data, memory is allocated each time the subroutine is called. That memory is freed when the subroutine ends, and so the values within it are lost. For statics, the memory is retained. These characteristics will be described in depth in this chapter.

Defining a tables Work Area

Variables defined by using the tables statement are always global. Placing the tables statement at the top of a program defines a global field string. Placing the same statement inside a subroutine also defines a global field string of that name. Therefore, you should not use the tables statement inside a subroutine since the definition is always global; global definitions should be placed at the top of your program.

To define a local table work area inside a subroutine, use local instead of the tables statement. The syntax is the same as tables, but it defines a local field string instead of a global one. The variables defined by using local are visible from within the subroutine and all subroutines it calls.

NOTE
To be precise, a variable is only known within a program after the point at which it is defined. For example, if you define a variable on line 10, you would be able to access it on lines 11 and later, but not on lines before line 10. In the case of a local definition, you can access the global version of the variable at any point before the local definition.

Listing 17.9 illustrates the local statement.


Listing 17.9  The local Statement

1  report ztx1709.
2  tables ztxlfa1.
3
4  select single * from ztxlfa1 where lifnr = 'V9'.
5  write: / '*-----', ztxlfa1-lifnr.
6  perform s1.
7  write: / '*S1---', ztxlfa1-lifnr.
8  perform s2.
9  write: / '*S2---', ztxlfa1-lifnr.
10
11 form s1.
12     write: / ' S1-A', ztxlfa1-lifnr.
13     local ztxlfa1.
14     select single * from ztxlfa1 where lifnr = 'V1'.
15     write: / ' S1-B', ztxlfa1-lifnr.
16     perform s2.
17     write: / ' S1-C', ztxlfa1-lifnr.
18     endform.
19
20 form s2.
21     write: / '  S2-A', ztxlfa1-lifnr.
22     select single * from ztxlfa1 where lifnr = 'V2'.
23     write: / '  S2-B', ztxlfa1-lifnr.
24     endform.

The code in Listing 17.9 produces the following output:

* - - - - -V9
 S1-A V9
 S1-B V1
  S2-A V1
  S2-B V2
 S1-C V2
*S1 - - -V9
  S2-A V9
  S2-B V2
*S2 - - -V2

If you define a local variable having the same name as a global variable, the local variable will take precedence inside the subroutine. Consequently, you will not be able to access the global variable of the same name within that subroutine. All references will refer to the local variable.

Defining Data

Variables defined by the data statement at the top of the program are global. data definitions within a subroutine are local to the subroutine. Memory is allocated for these variables when the subroutine is called, and freed when it returns. Like variables defined by using local, the values in data variables will be lost when the subroutine returns.

Use the statics statement to create local variables that are not freed when the subroutine ends. The syntax for statics is the same as the syntax for the data statement. The memory for a static variable is allocated the first time the subroutine is called, and retained when the subroutine ends. However, a static variable is only visible from within the subroutine itself, not within subroutines that it calls. The next time the subroutine is called, the memory for that variable becomes visible again. The value within it will be what it was when you last returned from that subroutine.

The memory of a static variable belongs to the subroutine that allocated it; that variable is not visible from other subroutines. If you allocate a static variable of the same name in multiple subroutines, these are separate variables with their own memory and values.

Listing 17.10 illustrates variables defined by using data and statics.


Listing 17.10  data and statics

1  report ztx1710.
2  data: f1 type i value 8,
3        f2 type i value 9.
4
5  write: / 'before s1:', f1, f2.
6  do 3 times.
7      perform s1.
8      enddo.
9  write: / 'after  s1:', f1, f2.
10
11 form s1.
12     data    f1 type i value 1.
13     statics f2 type i value 1.
14     write: / 'inside s1:', f1, f2.
15     perform s2.
16     f1 = f2 = f2 * 2.
17     endform.
18
19 form s2.
20     write: ' S2-', f1, f2.
21     endform.

The code in Listing 17.10 produces the following output:

before s1:          8           9
inside s1:          1           1   S2-          8           9
inside s1:          1           2   S2-          8           9
inside s1:          1           4   S2-          8           9
after  s1:          8           9

Summary

Q&A

Q
What happens if I have two events of the same name within the same program?
A
If you have coded two statements of the same name within the same program, when the event is triggered the system executes them both in the order in which they appear in your program.
Q
How can I tell the difference between an event name and a statement?
A
If you see a single word followed by a period, that is usually an event. Beyond that, events don't have any identifiable characteristics other than their names. They are simply reserved words and to recognize one you must memorize their names, just as you memorize the keywords in statements.
Q
Can I see the driver program? Can I choose the driver? Can I create a driver? What are the differences between the driver programs available?
A

The driver program is called a logical database. You can choose the driver program by filling in the logical database fields in the program attributes screen. If you don't specify one, a default is automatically assigned. The only time you would want to choose the driver is when you want it to read data from the database and supply it to your program automatically. The default logical databases do not read from the database-they only trigger events. Regardless of the driver you choose, the events are always triggered in the same relative order. Even if you create your own logical database program, you cannot change the relative sequence of events or their names, nor can you create new ones. To see a driver program, start from within the source code editor. Choose the menu path Utilities->Help On. Choose the Logical Database radio button and type a logical database id (KDF, for example). You will then see the structure of the logical database. Choose the menu path Goto->Database Program to see the driver program. Remember, the code shown within the driver in this chapter was pseudocode, so you won't see statements like trigger initialization in there. Logical databases are a complex topic and require many chapters to fully describe.

Q
If I put a write statement in an event that comes before start-of-selection, it works but only when there isn't a selection screen. If there is a selection screen, I don't see the output. Why?
A
R/3 uses something called a screen context to accept input and to display output to you. You can think of the screen context as one screen. Each screen context is processed in two phases: the dialog phase and the list phase. The dialog phase always occurs first, followed by the list. The dialog phase is used to display input fields to the user, such as those generated by a parameters statement. The list phase is used to display the output of write statement to the user. Both phases use the same screen context, so they overwrite each other. The dialog phase, however, pauses for user input and so allows itself to be shown before the list is shown. So if you issue a write statement in the initialization event and if the selection screen is shown, the selection screen overwrites the output from the write and that output is lost. You then choose Execute on the selection screen, and, if write statements are then issued, the list overwrites the selection screen and you see the output. However, if you don't have a selection screen, the writes that occur in initialization can still be seen.

Workshop

The Workshop provides you two ways for you to affirm what you've learned in this chapter. The Quiz section poses questions to help you solidify your understanding of the material covered and the Exercise section provides you with experience in using what you have learned. You can find answers to the quiz questions and exercises in Appendix B, "Answers to Quiz Questions and Exercises."

Quiz

  1. Does the write to variation of the write statement trigger top-of-page?
  2. Which events should you not use stop in?
  3. At what point is a variable known within a program?

Exercise 1

Create a report that accepts an input parameter named p_land1. Define it like ztxlfa1-land1. Fill this field with the default value US at runtime by using the Initialization event. Your main program should have a single statement to call a subroutine that selects records from ztxlfa1 where the land1 field equals the p_land1 parameter. Inside the select, call another subroutine to write the record out. Use the top-of-page event to create the report title. Write the value of the p_land1 field in the title.