Skip to Content
2

Can you explain the ABAP doc for class constructor

Aug 06, 2017 at 08:08 AM

392

avatar image

Hello guys,

In the ABAP doc of "Constructors of classes", it is said that "static methods may be executed before the static constructor was ended". I don't understand, because IMHO it's essential that the static constructor is completely executed before the other static methods of the class. So, I don't understand at all what it means.

Any idea?

Thanks. Sandra.

10 |10000 characters needed characters left characters exceeded
* Please Login or Register to Answer, Follow or Comment.

3 Answers

Best Answer
Fabian Lupa Aug 06, 2017 at 08:55 AM
3

I can think of the scenario where you want to do lots of stuff in class_constructor, so that you split up the initialization process into several static methods that are called from class_constructor. When those methods are called, the class constructor has not finished execution yet.

When accessing static methods from outside of class_constructor I agree the class_constructor should always have finished execution. Unless maybe the compiler is smart enough to know which static methods do not have side effects / are pure / do not access static members (but I'd prefer if it didn't).

Show 5 Share
10 |10000 characters needed characters left characters exceeded

Thanks Fabian. I can't imagine it can be as simple as what you say. If you call a static method from within the class constructor, then it's obvious how it works, and I don't understand why it's mentioned in the doc. The paragraph of the ABAP documentation starts with the enigmatic sentence "The point at which the static constructor is called is not fixed". I think that your last assumption ("the compiler is smart enough...") is more close to what the ABAP documentation says, but I would be very surprised it could be so smart.

0

I thought maybe it is mentioned explicitly because in the "normal" instance constructor there are quite a few special rules regarding what can be done in what order if inheritance is used. For example you can access and modify static attributes before calling the base class constructor, you can however not access instance attributes.

But let's see if someone has a more confident answer on this.

0

In fact, I'm starting to think now that your first answer is the right one; the sentence just means that one may call static methods from within the class constructor, and that's all. This fact was so obvious to me, the sentence was a little weird (from my point of view), and I just worried too much.

0

Yep. it's just that simple. I'll rephrase that note in the documentation of an upcoming release:

"A static construktor can call static methods of its class. Such a method must be implemented accordingly and must not rely on the completion of the static constructor of course."

0

Thanks Horst for the confirmation.

Thanks, Fabian & Mike too, for pointing to the evidence, and for the interesting comments too.

0
Fabian Lupa Aug 06, 2017 at 11:49 AM
1

I thought of how you could "overtake" the class constructor so that is started but execution continues before it is finished. Kind of like how shared objects area constructors work. So I tried out parallel processing but of course each task that runs in parallel has its own internal mode and therefore each of them executes the class constructor individually... Mike's subclass class_constructor approach might be the solution.

Anyways for reference :)

REPORT z_fl_class_constructor_test.

CLASS lcl_test DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      class_constructor,
      static_method.
    CLASS-DATA:
      gt_output TYPE stringtab READ-ONLY.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CLASS-DATA:
      gv_id TYPE ssi_session_key.
ENDCLASS.

CLASS lcl_test IMPLEMENTATION.
  METHOD class_constructor.
    DATA: lv_time TYPE timestampl.
    gv_id = NEW cl_session_info( )->get_session_key( ).

    GET TIME STAMP FIELD lv_time.
    APPEND |{ lv_time } { gv_id }: Class constructor started| TO gt_output.

    CALL FUNCTION 'RZL_SLEEP'.

    GET TIME STAMP FIELD lv_time.
    APPEND |{ lv_time } { gv_id }: Class constructor finished| TO gt_output.
  ENDMETHOD.

  METHOD static_method.
    DATA: lv_time TYPE timestampl.
    GET TIME STAMP FIELD lv_time.
    APPEND |{ lv_time } { gv_id }: Static method called| TO gt_output.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_parallel DEFINITION INHERITING FROM cl_abap_parallel.
  PUBLIC SECTION.
    METHODS:
      do REDEFINITION.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS lcl_parallel IMPLEMENTATION.
  METHOD do.
    lcl_test=>static_method( ).
    EXPORT result = lcl_test=>gt_output TO DATA BUFFER p_out.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA: gt_result TYPE stringtab.

  DATA(go_parallel) = NEW lcl_parallel( p_num_processes = 3  ).
  go_parallel->run( EXPORTING p_in_tab  = VALUE #( ( ) ( ) ( ) ( ) ( ) ( ) )
                    IMPORTING p_out_tab = DATA(gt_out) ).

  LOOP AT gt_out ASSIGNING FIELD-SYMBOL(<gs_out>).
    WRITE: / |{ <gs_out>-index } { <gs_out>-message } { <gs_out>-time }|.
    IMPORT result = gt_result FROM DATA BUFFER <gs_out>-result.
    LOOP AT gt_result ASSIGNING FIELD-SYMBOL(<gv_line>).
      WRITE: / <gv_line>.
    ENDLOOP.
    CLEAR gt_result.
  ENDLOOP.
Share
10 |10000 characters needed characters left characters exceeded
Mike Pokraka Aug 06, 2017 at 11:19 AM
1

Interesting question. To my understanding it works as Fabian described, but it wouldn't need a smart compiler to handle this.

In fact, I had a lengthy dive in to the behaviour of static subclasses which supports the dumb compiler theory, static methods really behave more like 'named bits of code'. See Determine class name used for calling a static method, example at Oct 24. To recap the relevant bit:

class lcl_super definition. 
    class-methods foo returning value(result) type i. 
endclass.

class lcl_sub definition inheriting from lcl_super.
  class-methods class_constructor.
endclass. 

...
data(r1) = lcl_sub=>foo( ).    " <<<< lcl_sub class constructor will NOT be executed.

Because statics are not inherited in ABAP, the compiler ignores the subclass completely in this case.

From this I would infer that the compiler's logic is something like:

some code calls static method foo_static in class cl_bar.
if class_is_not_loaded( cl_bar ). 
  load cl_bar.
  execute cl_bar=>class_constructor.
endif.
execute method foo_static.

So once the class constructor starts executing it is treated as an already loaded class requiring no further class constructors. But it is only once the class-constructor is finished that the class-external calls get executed.

But that's just my deductions, I may be wrong.

Show 6 Share
10 |10000 characters needed characters left characters exceeded

Thanks Mike. Nice information I wasn't aware of. After thinking, it seems logic that only the needed class constructor is called (and I understand why you mentioned that point in the context of the mentioned thread).

Maybe the current sentence "For this reason, static methods may be executed before the static constructor was ended." just means "Class methods may be called from within the class constructor", and the current sentence just tries to explain why it's technically possible, and I just worried too much about the words used.

1

"After thinking, it seems logic that only the needed class constructor is called"

I would still call this an ABAP peculiarity. Java and other languages do inheritance of static components. So you can redefine a static method in a subclass, which makes a call to the subclass is executed in the context of the subclass. In ABAP the compiler just hardcode-translates the subclass call to the class which defined the method.

The fact that static is fixed and not inherited or redefinable was just a decision the ABAP designers made, or something similar was the explanation Horst gave at some point (I think). Personally I find the Java-like behaviour more intuitive.

0

At least in Java you cannot override static methods afaik. You can overshadow them by defining a static method with the same signature as the one in the base class but I would call that rather hacky and not a feature of the language (i. e. @Override doesn't work, refactoring tools won't find it etc.).

0

Uff, google seems to throw up plenty of flame wars on exactly those terms :-)

The consensus seems to be Java does redefinition.

If we really think about it, inheritance poses little difference to what you just described. REDEFINITION in ABAP also means a "method with the same signature as the one in the base class", because it's a new code base with access to the same stuff that a completely new method would have. The only additional feature is to be able to call 'super'.

At some level it becomes a matter of semantics, and the basis for some fun discussions.

0

Like this one :P

I just think there are other languages that support it in a native way by design and in Java it's more or a less there by accident and not to be actually used (because there is no compile time safety). When I last researched the topic I came to the conclusion to rather use an annotation based approach for my problem instead of using shadowing because that seemed more maintainable and readable to me. Also defining static methods in interfaces works quite well too in some cases.

0

...then again the ABAP-specific recommendation is to use instance methods unless otherwise required.

https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abenstatic_class_singleton_guidl.htm

1