7.4 Release News - Constructor Expressions


Overview

In the last two blog posts, we have talked about how inline declarations (DATA, FIELD-SYMBOL) can make our code thinner, more readable and transparent.

Today, we go ahead, and continue examining the new features of the 7.4 Release, and talk about the Constructor Expressions.

Although, all the Constructor Operators above are very useful, but today I only want to talk about the most popular ones (at least in my opinion :)):
  • ... NEW type( ... ) ...
  • ... VALUE type( ... ) ...

If you are familiar with the C# language, then you may find them very similar to the Object and Collection Initializers in C#.


Initializing Structures

First, let's talk about initializing structures! We have the following structure defined in our ABAP code, or in the ABAP Dictionary, no differences.

As you can see, besides the simple components: name, phone_number, data_of_birth, we have a complex component as well, called address. The component, address represents another structure with the following simple fields: house_number, street, city, zip_code, state, and at last country.

Before 7.4, it was a nightmare to initialize a nested structure like this! :(

...
TYPES:
  BEGIN OF customer,
    name          TYPE string,
    BEGIN OF address,
      house_number TYPE string,
      street       TYPE string,
      city         TYPE string,
      zip_code     TYPE string,
      state        TYPE string,
      country      TYPE string,
    END OF address,
    phone_number  TYPE string,
    date_of_birth TYPE d,
  END OF customer.
...

Now comes the magic! We use the VALUE constructor operator to initialize our inline declared variable, called john_mayer, that actually represents a customer.

The syntax is the following: DATA(...) = VALUE type( ... ). The system uses the type that we defined after the VALUE keyword to determine the type of our variable, john_mayer.

...
DATA(john_mayer) = VALUE customer(
  name          = 'John Mayer'
  address       = ...
  phone_number  = '+1 303 544 5464'
  date_of_birth = '19721101'
).
...

There is another form, that looks like this: we declare our variable in the classic way, and then initialize it with the VALUE operator, but in this case no need for specifying any type, since the compiler knows the type of the john_mayer variable (since we have already defined it). This is because, we use the # symbol.

If you ask me, I would say that the explicit one DATA(...) = VALUE type( ... ), it's much more readable, than the implicit one VALUE #( ... ).

...
DATA john_mayer TYPE customer.

john_mayer = VALUE #(
  name          = 'John Mayer'
  address       = ...
  phone_number  = '+1 303 544 5464'
  date_of_birth = '19721101'
).
...

Feel it? If yes, then let's make it a bit more complex! Do you remember, we have an address component in our customer nested structure? In the case of the address, we can use the implicit form VALUE #( ... ), since the compiler is aware of the data type of the address component.

...
DATA(john_mayer) = VALUE customer(
  name    = 'John Mayer'
  address = VALUE #(
    house_number = '181'
    street       = 'Round Jetty Str.'
    city         = 'Cleveland'
    zip_code     = '34221'
    state        = 'Alabama'
    country      = 'United States'
  )
  phone_number  = '+1 303 544 5464'
  date_of_birth = '19721101'
).
...


Initializing Internal Tables

Let's say, we have defined a table type also, using the data type, called customer.

...
TYPES customers TYPE STANDARD TABLE OF customer WITH DEFAULT KEY.
...

Before 7.4, we had to use the APPEND statement to fill an internal table up with rows. Now, it goes like this: we declare an internal table as inline, the us_customers that will contain our customers from United States, then using the table type from above with the VALUE operator, we define the rows between brackets (using the previously defined john_mayer and eric_dumm structures).

...
DATA(us_customers) = VALUE customers( 
  ( john_mayer )   " first row
  ( eric_dumm )    " second row
).
...

We can achieve the same results, using inline structure initializations. Here, as you can see, I declared and initialized our internal table as the same way as earlier, but now, I placed the structure initializations inside the table initialization.

To initialize the rows of an internal table, no need VALUE, NEW, # symbols, only need to place the rows between simple brackets!

...
DATA(us_customers) = VALUE customers(
  (
    name    = 'John Mayer'
    address = VALUE #(
      house_number = '181'
      street       = 'Round Jetty Str.'
      city         = 'Cleveland'
      zip_code     = '34221'
      state        = 'Alabama'
      country      = 'United States'
    )
    phone_number  = '+1 303 544 5464'
    date_of_birth = '19721101'
  ) " first row
  (
    name    = 'Eric Dumm'
    address = VALUE #(
      house_number = '233/C'
      street       = 'Hazy Pointe Str.'
      city         = 'Essex'
      zip_code     = '34221'
      state        = 'Delaware'
      country      = 'United States'
      )
    phone_number  = '+1 635 999 5881'
    date_of_birth = '19690321'
  ) " second row
).
...


Initializing Classes

In order to demonstrate you the usage of the NEW operator, I got you another example. In this example, we have a class, cl_customer_repository, that contains a few methods, and one of them is the insert().

CLASS cl_customer_repository DEFINITION.
  PUBLIC SECTION.
    METHODS insert IMPORTING customer_to_be_inserted TYPE customer.
    ...
ENDCLASS.

CLASS cl_customer_repository IMPLEMENTATION.
  METHOD insert.
    ...
  ENDMETHOD.
  ...
ENDCLASS.

In order to use the instance method, insert() first we need to instantiate an object. For this, I declare a reference variable, customer_repository, and instantiate an object of the cl_customer_repository class, using the NEW operator. As a result, we got back a reference that points to the new object, and save in our reference variable, customer_repository.

The NEW operator has the same effect as its predecessor, the CREATE OBJECT. If we want, we can pass parameters to the constructor between the brackets.

...
DATA(customer_repository) = NEW cl_customer_repository( ).
customer_repository->insert( john_mayer ).
...

When we don't need any reference variable (need to call only one method on an object, and only once), we can chain the constructor call, and the method call together, getting more compact code.

...
NEW cl_customer_repository( )->insert( eric_dumm ).
...

In some cases, we can go further and place, let's say a structure initialization inside the method call. As you can see, I used the VALUE #( ... ) implicit form, since I don't have to specify explicitly the type of the actual parameter, because the system knows it!

...
NEW cl_customer_repository( )->insert( 
  VALUE #(
    name    = 'Eric Dumm'
    address = VALUE #(
      house_number = '233/C'
      street       = 'Hazy Pointe Str.'
      city         = 'Essex'
      zip_code     = '34221'
      state        = 'Delaware'
      country      = 'United States'
    )
    phone_number  = '+1 635 999 5881'
    date_of_birth = '19690321'
  ) 
).
...


Summary

In conclusion, what I can say is, that both VALUE and NEW are great improvements of the ABAP language, feel free to apply them in your development.

Finally, let me share you my opinions:

  • I found much more readable the explicit forms, then the implicit ones with the # symbol (also it requires fewer lines of code):
    DATA(john_mayer) = VALUE customer( ... ).
    DATA(us_customers) = VALUE customers( ... ).
    DATA(customer_repository) = NEW cl_customer_repository( ).
    
  • Although, we are able to use both the NEW and VALUE operators to initialize almost any kind of object, but I mostly use the NEW operator (... TYPE REF TO ...) only to instantiate objects, and use mostly the VALUE operator (... TYPE ...) to initialize complex data types, like structures and table types.
  • Since, I often write unit and acceptance tests using ABAP Unit Framework, it was a pleasure to replace the my initializations in the fixture methods, to these new constructor expressions. Making my test code much more thinner, readable, and transparent.

Now, go and try it out! If you don't have any access to any 7.4 based SAP system, then I recommend to watch my colleague's setup guide.

Stay tuned, keep reading! If you want to get notification about the newest posts, follow me or subscribe to our newsletter!

If you liked it, please share it! Thanks!

blog comments powered by Disqus