Friday, October 31, 2008

Objects instead of references

The ABAP syntax for working with tables is really good. But the syntax for working with references is crap.

Many times, for the sake of efficiency, I need to mix references and tables. And I never found an easy way to do that in ABAP.

For example, I want to have a table with thousands of city names and for each city I want to have a table of dozens of places. Then, for a given city I want to get the list of places and do some actions on that data (sorting, removing, changing, etc). Notice that it is not a good idea to have just one table with both cities and places because each sublist operation would have a big penalty because of the big size of the full table.

In python it is so easy:


cities = {'Porto':['Casa da Musica','Serralves','Torre dos Clerigos'],
'New York': ['Empire State Building','Central Park'] }

#print the sorted list of places in Porto
cities['Porto'].sort()
print cities['Porto']


In ABAP I find myself using objects because the resulting syntax is cleaner. It looks something like this:


TYPES:
BEGIN OF t_place,
place TYPE char30,
END OF t_place.

TYPES:
t_tab_places TYPE TABLE OF t_place.

CLASS place_obj DEFINITION.
PUBLIC SECTION.
DATA places_table TYPE t_tab_places.
METHODS add_place IMPORTING place_name TYPE char30.
PRIVATE SECTION.
ENDCLASS. "place DEFINITION

CLASS place_obj IMPLEMENTATION.
METHOD add_place.
DATA ls_place TYPE t_place.
ls_place-place = place_name.
APPEND ls_place TO places_table.
ENDMETHOD.
ENDCLASS.

TYPES:
BEGIN OF t_city,
city_name TYPE char20,
places_ref TYPE REF TO place_obj,
END OF t_city.

DATA:
gt_city TYPE HASHED TABLE OF t_city WITH UNIQUE KEY city_name,
gs_city TYPE t_city,
gs_place TYPE t_place.

DATA oref TYPE REF TO place_obj.

START-OF-SELECTION.
gs_city-city_name = 'Porto'.
CREATE OBJECT oref.
gs_city-places_ref = oref.
CALL METHOD oref->add_place( 'Torre dos Clerigos' ).
CALL METHOD oref->add_place( 'Casa da Musica' ).
CALL METHOD oref->add_place( 'Serralves' ).
INSERT gs_city INTO TABLE gt_city.

gs_city-city_name = 'New York'.
CREATE OBJECT oref.
gs_city-places_ref = oref.
CALL METHOD oref->add_place( 'Empire State Building' ).
CALL METHOD oref->add_place( 'Central Park' ).
INSERT gs_city INTO TABLE gt_city.

READ TABLE gt_city INTO gs_city WITH KEY city_name = 'Porto'.
IF sy-subrc = 0.
oref = gs_city-places_ref.
SORT oref->places_table BY place.
LOOP AT oref->places_table INTO gs_place.
WRITE: / gs_city-city_name, gs_place-place.
ENDLOOP.


But it's still far from perfect. Dear lazy web, is there a better way?