Skip to Content

Archived discussions are read-only. Learn more about SAP Q&A

Issue with changing attribute of a singleton

Hi folks!

I ran into a weird behaviour of a class implementing a singleton pattern.

So, what have we got:

there is a class, say,  zcl_my_fi_log. It's main usage is collecting messages during the documents processing. I believe that a singleton is a pretty nice candidate for that role - whatever place there is an error (or whatever) message, it collects them all.

Here's how it looks like (after removing unnecessary stuff):

CLASS zcl_my_fi_log DEFINITION
   FINAL
   CREATE PRIVATE.

   PUBLIC SECTION.

     DATA mt_log TYPE bapirettab.

     CLASS-METHODS factory
       RETURNING
         VALUE(ro_obj) TYPE REF TO zcl_my_fi_log .

     METHODS add_sy_message .

     METHODS display .

     CLASS-DATA mo_log TYPE REF TO zcl_my_fi_log .
ENDCLASS.

CLASS zcl_my_fi_log IMPLEMENTATION.

   METHOD factory.

     IF NOT mo_log IS BOUND.
       CREATE OBJECT mo_log.
     ENDIF.

     ro_obj = mo_log.

   ENDMETHOD.

   METHOD add_sy_message.

     DATA ls_return TYPE bapiret2.

     CALL FUNCTION 'BALW_BAPIRETURN_GET2'
       EXPORTING
         type   = sy-msgty
         cl     = sy-msgid
         number = sy-msgno
         par1   = sy-msgv1
         par2   = sy-msgv2
         par3   = sy-msgv3
         par4   = sy-msgv4
       IMPORTING
         return = ls_return.

       APPEND ls_return TO mt_log.

   ENDMETHOD.

   METHOD display.

     CALL FUNCTION 'SUSR_DISPLAY_LOG'
       EXPORTING
         display_in_popup = abap_true
       TABLES
         it_log_bapiret2  = mt_log.

   ENDMETHOD.

ENDCLASS.

It behaves as a singleton is supposed to, e.g. if I code something like this

   DATA lo_my_fi_log1 TYPE REF TO zcl_my_fi_log.
   DATA lo_my_fi_log2 TYPE REF TO zcl_my_fi_log.

   MESSAGE s000(zfi) WITH 'lalala'.
   zcl_my_fi_log=>factory( )->add_sy_message( ).

   lo_my_fi_log1 = zcl_my_fi_log=>factory( ).

   lo_my_fi_log1->mt_log[ 1 ]-type = 'E'.

   lo_my_fi_log2 = zcl_my_fi_log=>factory( ).

   lo_my_fi_log2->mt_log[ 1 ]-type = 'W'.

   zcl_my_fi_log=>factory( )->display( ).

we'll see that message type of the instance held by zcl_my_fi_log is changed (as far as the message type of local classes). Of course, direct changing of class attributes is a bad practice, but I prefer less code to demonstrate the problem, let's live without getter/setter methods in this example


As far as I have a method returning the instance of the class how about removing my local variables like this


MESSAGE s000(zfi) WITH 'lalala'.
zcl_my_fi_log=>factory( )->add_sy_message( ).
 
LOOP AT zcl_my_fi_log=>factory( )->mt_log ASSIGNING FIELD-SYMBOL(<ls_log>)
   WHERE type = 'S'.

   <ls_log>-type = 'E'.
ENDLOOP.

LOOP AT zcl_my_fi_log=>factory( )->mt_log ASSIGNING <ls_log>
   WHERE type = 'S'.
   " Shouldn't be here! But check it out in debugger...
   <ls_log>-type = 'E'.
ENDLOOP.

zcl_my_fi_log=>factory( )->display( ).


And finally we see message type 'S' as if we haven't changed it earlier.


Guys, do you have any ideas of what happens? Isn't my class a singleton? What is the problem eliminated by explicit instantiation?


P.S. I'm playing with ABAP 7.40 SP9.

Tags:
Former Member
replied

Hello Nikolay,

Finally something to tingle the greycells

I think i have an answer, let me try to break it down for you -

    1. You are using the functional method call in the LOOP construct: zcl_my_fi_log=>factory( )->mt_log
    2. You are trying to modify the contents of the int. table mt_log in the LOOP.

Now let us see what ABAP documentation has to say about it -

  1. Call of a functional method in a suitable reader position, where the return value of the method is used as an operand. ABAP Keyword Documentation
  2. Reader position: Operand position in which the operand is read-only. ABAP Keyword Documentation

The int. table mt_log is never modified during the loop execution. You should have checked it in the debugger.

Workaround: Declare the singleton (instance) of the class as public/read-only and use it directly. (Similar to the AGENT attribute of the agent classes for persistence classes)

LOOP AT zcl_my_fi_log=>mo_log->mt_log ASSIGNING <ls_log> WHERE type = 'S'.

    <ls_log>-type = 'E'.

  ENDLOOP.

BR,

Suhas

PS - I see it is an ABAP trapdoor, maybe you should blog about it

Message was edited by: Suhas Saha

2 View this answer in context
Not what you were looking for? View more on this topic or Ask a question