Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Determine class name used for calling a static method

pokrakam
Active Contributor
0 Kudos

Hi all,

I know static methods cannot be redefined, but they can be called using a subclass as the 'calling class name'. Is it possible to determine the object type used for calling a static method?

For example, I have ZCL_SUPER with a static method HELLO and a subclass ZCL_SUB.

I can use ZCL_SUPER=>HELLO( ) or I can use ZCL_SUB=>HELLO( ).

Both will execute the same code (correct), but is it possible to tell the difference inside the HELLO method? SY-REPID will always show the superclass (also correct).

I've found some similar threads but none with a clear answer.

Any input appreciated,

Mike

1 ACCEPTED SOLUTION

horst_keller
Product and Topic Expert
Product and Topic Expert

I guess there is no simple solution. I expect that the compiler interprets the symbolic names ZCL_SUPER=> and ZCL_SUB=> in order to point to the method and forgets about it. Why should it keep the information? In fact I have a similar problem: Is there a simple way to find out the name of an actual parameter passed to a formal parameter inside a method? It isn't! I ended up in interpreting the call stack and parsing the calling code!

41 REPLIES 41

nomssi
Active Contributor
0 Kudos

Hi Mike,

I have no solution either, what if the caller is not an object?

You can always evaluate the ABAP call stack (function module SYSTEM_CALLSTACK).

regards,

JNN

pokrakam
Active Contributor
0 Kudos

Hi Jacques,

Thanks for the input. Call stack won't help because it never shows inheritance, always the implementing class of a method. You can see this in the debugger. I also doublechecked with system debugging on, same result.

The only option there is to also go and parse the code of the calling program which adds more complexity than I'm trying to solve.

It doesn't really matter whether the caller is an object or a report, I want to know whether the line of code that invoked my static method used ZCL_SUPER=> or ZCL_SUB=>

Thanks,

Mike

0 Kudos

Is it possible to use instance method, or add parameter ZCL=>HELLO( "id_of_call" )?

Or it has to be static method without parameters?

-- Tomas --

pokrakam
Active Contributor
0 Kudos

Thanks, but no then I'm stuck with the original problem of making every call explicit, or I might as well create statics in each subclass which call the superclass with the appropriate information.

Both of which are exactly what I'm trying to avoid - the developer should be able to call my method in a subclass they create and not worry about the rest.

rosenberg_eitan
Active Contributor
0 Kudos

Hi,

Just a thought....

If there was an ABAP equivalent to Java :

this.getClass().getName();

we can pass it as parameter .

Regards.

0 Kudos

There is equivalent reference "me" in ABAP and also cl_abap_classdescr. Problem is, that static method has no reference to "me".

-- Tomas --

0 Kudos

Thanks.

I see there GET_CLASS_NAME

I did not test it.

Regards.

0 Kudos

cl_abap_classdescr=>get_class_name( me ) returns this:


\PROGRAM=ZTEST3\CLASS=ZCL_SUPER

or better to use longer call, but shorter result :

lref = cl_abap_classdescr=>describe_by_object_ref( me ).

lref->get_relative_name( ) which returns:


ZCL_SUPER

-- Tomas --

Tomas_Buryanek
Active Contributor
0 Kudos

I do not think it is possible. At least not with ABAP Objects "logic".

There is no reference to caller object ("me" does not exist in static method).

Maybe it is possible with some workaround. But for example SYSTEM_CALLSTACK would not help much with this problem, if you use local classes. I did not tried with global classes.

-- Tomas --

former_member205488
Active Participant
0 Kudos

Hello!

It's impossible to implement polymorphism using static methods in ABAP Objects.  So, there is no difference between ZCL_SUPER=>HELLO( ) and ZCL_SUB=>HELLO( ) because you call exactly the same method in both cases

naimesh_patel
Active Contributor
0 Kudos

Hi Mike,

Can I ask you why you want to know who called this method or by using what class name?

You can also call the static method with an instance of the class. If you pass this instance to this method, you can use the object descriptor to know the type of the object. Generally if that is the object you are working on, you are more likely to use that object reference to call the static method.

*
CLASS lcl_super DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: hello IMPORTING io_obj TYPE REF TO lcl_super.
ENDCLASS.                    "lcl_super DEFINITION
*
CLASS lcl_sub DEFINITION INHERITING FROM lcl_super.
ENDCLASS.                    "lcl_sub DEFINITION

START-OF-SELECTION.
"lcl_sub=>hello( ).
DATA: lo_obj TYPE REF TO lcl_super.
CREATE OBJECT lo_obj.
lo_obj
->hello( lo_obj ).
CREATE OBJECT lo_obj TYPE lcl_sub.
lo_obj
->hello( lo_obj ).

lcl_super
=>hello( lo_obj ).

*
CLASS lcl_super  IMPLEMENTATION.
METHOD hello.
WRITE: / 'Im called'.

DATA: lo_objdesc TYPE REF TO cl_abap_objectdescr.
DATA: lv_name TYPE string.
lo_objdesc ?= cl_abap_objectdescr
=>describe_by_object_ref( io_obj ).
lv_name
= lo_objdesc->get_relative_name( ).
WRITElv_name.


ENDMETHOD.                    "hello
ENDCLASS.                    "lcl_super IMPLEMENTATION



Regards,

Naimesh Patel

0 Kudos

Hi Naimesh,

Thanks for the input. Background is that this method is part of an abstract superclass, and it should manage how/what subclasses may be instantiated. So at the time of the call no instance of any sort is known to the caller.

The ideal 'OO way' would be a factory class returning an interface reference, but there's a long-winded reason for implementing the same idea in an inheritance tree with a static method at the top.

I did tinker around with having the top level class as a singleton instance, not too dissimilar form your idea. But that added more complexity for the caller so no joy there.

My current best approach is to use a standalone factory class with a separate method for each subclass in my tree that takes the input and adds the class name to the call to the static method in question.

Anyone who creates a subclass would have to create a corresponding factory method. Clunky but workable:

ZCL_OBJ_FACTORY=>GET_SUB1( somedata )

looks better than the really clunky:

ZCL_SUB1=>GET_INSTANCE( i_class = 'ZCL_SUB1'  i_somedata = somedata ).

(which is now hidden in each factory method...)

I'll leave this open for ideas.

Thanks,

Mike

0 Kudos

Hey Mike,


Anyone who creates a subclass would have to create a corresponding factory method.

For FACTORY method, you should keep one method which gives the necessary object and hides the object creation complexity from the caller. Also, it should be out of your class hierarchy and into its own separate final class

  • This makes sure, there is only single-responsibility of the class
  • No confusion of how static method is called, as the class is final and there will not be any subclass for this class

My current best approach is to use a standalone factory class with a separate method for each subclass in my tree that takes the input and adds the class name to the call to the static method in question.

I think you should hide the class name from the caller - to decouple it. Instead, you should have a key which determines the class name. This key to class relationship could be defined

  • Using certain naming standards - e.g. ZCL_DOSOMETHING_ZK01 where ZK01 is my key
  • Using hardcoding the key and class relation in the method FACTORY
  • Using a table where you have the key and class relation

My preference is last option.

Using this option of the factory, the caller can easily obtain different objects for different keys without worrying about which specific method to be called to get which specific object.

Regards,

Naimesh Patel

0 Kudos

Hi Naimesh,

Agree, as I explained, a standalone factory class is exactly what my current best-but-not-perfect approach is. Anyone who creates a subclass of main superclass also has to add a corresponding method to the factory class. The method name itself thus becomes the key, and inside it they need to pass the class name to the superclass.

If I add a further key into the equation then I'm back to where I might as well require all implementers of the class hierarchy to pass their subclass name in:

ZCL_SUB7=>GET_INSTANCE( i_class = 'ZCL_SUB7' i_otherstuff = stuff ).

I don't specifically want to hide the class name either. This is part of a larger framework where several developers will be creating subclasses, and these will be instantiated in various application scenarios. But in all cases the dev will know what they're trying to use.

This is exactly the type of reason interfaces are preferable to inheritance, but in this case I'm stuck with it.

Thanks,

Mike

markus_lanz3
Explorer
0 Kudos

Hi Mike

This is exactly one of the reasons why our team no longer works with static methods. Use an instance method instead, even if the coding is not (yet) object specific. This enables you also to use the runtime descriptor for classes to determine the actual name [cl_abap_classdescr=>get_class_name( me )]

Regards

Markus

Check this example:

class ZCL_SUPER definition
  public
  create public .
public section.
  methods HELLO
    returning
      value(RV_NAME) type STRING .
protected section.
private section.
ENDCLASS.

CLASS ZCL_SUPER IMPLEMENTATION.
METHOD hello.
  rv_name = cl_abap_classdescr=>get_class_name( me ).
ENDMETHOD.
ENDCLASS.

class ZCL_SUB definition
  public
  inheriting from ZCL_SUPER
  create public .
public section.
protected section.
private section.
ENDCLASS.

CLASS ZCL_SUB IMPLEMENTATION.
ENDCLASS.

Program:

DATA: lo_obj TYPE REF TO zcl_sub.
DATA: lv_name TYPE string.

CREATE OBJECT lo_obj.

lv_name = lo_obj->hello( ).

WRITE lv_name.

0 Kudos

Hi Markus,

Thanks for the input. Interesting idea of not using statics as a matter of policy.

I did play around with a couple of instance scenarios, but all those scenarios added even more complexity than the awkwardness I'm trying to eliminate. My problem (and the main reason for this setup) is to manage the instantiation - in some cases I will even get a different object back.

Some scenarios:

- Developer may want to evaluate which subclass to use.

- Developer may not care about the exact type and get a subclass of what s/he is requesting (polymorphic instantiation).

So completely without statics I would end up with stuff like:

DATA: myobj TYPE REF TO zcl_sub.

DATA: value TYPE i.

CREATE OBJECT myobj type zcl_sub_low. "pick the most likely sub-subtype to start with

value = myobj->my_static_check( somedata ).

if value < zcl_super=>threshold.

  "Good, we got lucky

else.

  "need different subclass

  clear myobj.

  create object myobj type zcl_sub_high.

endif.

or:

CREATE OBJECT myobj type zcl_sub_low.

classname = myobj->get_appropriate_class( ).

if classname <> myobj->get_classname( ).

  clear myobj.

  create myobj type (classname).

endif.

This is way too complex to do for every single instantiation of all the subclasses (there will be many!). So I'm trying to hide this type of logic in superclass statics and ideally have the developer just do:

if zcl_sub=>static_check( somedata ) <> abap_true.

  "decide on which class to use

or:

myobj ?= zcl_sub=>get_instance( somedata ). "could return various subclasses of zcl_sub

Both very simple to do with a static method of zcl_sub, but I would like to implement it in zcl_super. This would be so simple if a static would know as which class it is being called...

Thanks,

Mike

nomssi
Active Contributor
0 Kudos

Hello Mike,

this looks like Abstract Factory to me, where you create a hierarchy of constructor classes in addition to your product hierarchy to have a stable object creation code:

lo_factory = lcl_factories=>get_instance( somedata ).  " generates the appropriate factory object

lo_obj = lo_factory->new( somedata ).                        " generates the correct product

this could now be isolated in a static class if you use interfaces.

The price to pay is to to subclass lcl_factories and update its get_instance( ) method each time you add a product subclass.

best regards,

JNN

0 Kudos

Hi Jacques,

That is indeed the best 'proper OO' solution to the scenario, although in my case I will end up with several factory classes.

In practice sadly it's too much work... I'm trying to create a framework which even junior developers want to use - a 3-lines-of-code job, which would ave been possible if a static method new it's calling mechanism.

I like the abstract factory idea but I'm not going to sell this one to the masses who still think a class is a new-fangled replacement for a function group.

To all who replied: I have been pleasantly surprised and impressed by the overall level of good quality input on this thread, thanks to for much food for thought.

Regards,

Mike

Richa_Gupta
Contributor
0 Kudos

Hi Mike,

As fas as I know, static method cannot be redefined in a subclass.

Now, if super class is an abstract class, then that means that static method also is an abstract method. This implies that super class should not call this method at all as there is no implementation of this method inside super class.

So, in a nutshell, if it is a usual super class, as the static methods cannot be redefined, so static method will always be called from super class only.

If it is an abstract super class, then as you cannot redefine the static method inside sub class, so what is the use of having it in super class.

Hope this helps!!!

Regards,

Richa

0 Kudos

Hello Richa,

Thanks for the input, but I think you misunderstood the problem.


Now, if super class is an abstract class, then that means that static method also is an abstract method.

Not correct. You can have code and define ordinary methods in an abstract class.


So, in a nutshell, if it is a usual super class, as the static methods cannot be redefined, so static method will always be called from super class only.

No, it can be called from outside the class, by other classes, reports, Web Dynpro apps. And that is precisely where my issue is. If I have ZCL_SUPER=>STATIC( ), I can also call ZCL_SUB=>STATIC( ) within my app.


If it is an abstract super class, then as you cannot redefine the static method inside sub class, so what is the use of having it in super class.

To provide a function that will be available to all subclasses.

Regards,

Mike

oscar_delama
Explorer
0 Kudos

Hi Mike,

This is a little bit old thread, but the question is interesting and also I am facing a similar problem.

I am using a static attribute (class-data) named THIS_CLASS_NAME to hold the name of the current class/subclass. This static attribute is updated in the CLASS_CONSTRUCTOR of each subclass, like this:


CLASS ZCL_SUB ...


METHOD class_constructor.

  TYPES dummy    TYPE REF TO ZCL_SUB.

  this_class_name    = 'ZCL_SUB'.

ENDMETHOD.

As the class name assigned to the this_class_name attribute is a hardcoded text, if the subclass is renamed this text won't match the real subclass name. To reduce that chance, the TYPES clause will throw a syntax error when the subclass is renamed. Unluckily, it doesn't save us if the subclass is rename to ZCL_OTHER while there is now other class named ZCL_SUB.

Now I can have generic constructors in the super class using the this_class_name attribute when required, as in:


CLASS-METHODS build_this_way ...

...

CREATE OBJECT result TYPE (this_class_name).

...

or use it as argument invoking methods in specialized factory classes.

Best regards,

OdL

0 Kudos

Hi Oscar,

I see one other issue with your approach:

As you're using a static, two instances will overwrite it. So if I want an instance of SUB1 and SUB2 in the same piece of code, SUB2 will write 'ZCL_SUB2' into the same static that is also used by SUB1.

For what it's worth, my end solution was simple factory pattern. For each family of subclasses I created a factory class with methods for each subclass.

ZCL_FOO_FACTORY=>GET_FOO1( key ).

ZCL_FOO_FACTORY=>GET_FOO2( key ).

ZCL_BAR_FACTORY=>GET_BAR1( key ).

...and so on.

Inside each of these, the appropriate class name (ZCL_FOO1 etc.) is passed into the new object. It's not perfect in the OO sense, but for my purposes a better balance between abstraction, simplicity and readability.

Regards,

Mike

0 Kudos

Ooops! Yes, you are totally right. I can't believe I didn't realize that!!...

I am working with a hierarchy of exception classes, but there is not a common root, because a branch is dynamic and the other isn't it. Besides that, the exception constructors are not editable...

My goal is make them the easiest to construct and raise. e.g. without temporal variables (ABAP 7.00): Just one factory call and raise the exception. However, in this context -to avoid to repeat myself- I am forced to hardcode exception class names as strings, which are passed to more generic constructor routines. I whish there would be a way to pass a type as parameter, or a kind of 'me' variable referring somehow (maybe just by name) to the class where a static routine is running.

Thank you.

horst_keller
Product and Topic Expert
Product and Topic Expert

I guess there is no simple solution. I expect that the compiler interprets the symbolic names ZCL_SUPER=> and ZCL_SUB=> in order to point to the method and forgets about it. Why should it keep the information? In fact I have a similar problem: Is there a simple way to find out the name of an actual parameter passed to a formal parameter inside a method? It isn't! I ended up in interpreting the call stack and parsing the calling code!

0 Kudos

Interesting, parsing was also one of my earlier ideas but I didn't have time to pursue it.  So as I understand it, from the compiler's perspective a static method is really just an standalone piece of code, the link to the class is purely semantic for the developer to group it somewhere.

Another theoretical possibility that I haven't explored is to throw and catch an exception and see if the exception object is of any use. But I suspect that won't be much better than parsing.

horst_keller
Product and Topic Expert
Product and Topic Expert
0 Kudos

Let me generalize from compiler to "ABAP runtime" because this also includes dynamic calls.

To say it a bit more educated: Procdeures (not only static methods) run in their own context having their own (stack) data. They know nothing about their caller or how they were called. They know only those things that are passed directly or are accessible from shared ressources. It is not interesting for a procedure how it was called. You can replace your ZCL_SUPER=> and ZCL_SUB=> with  dynamic class specifications, but for the execution of the method this should make no difference. And yes, a procedure implementation is always a standalone piece of code, even for instance methods. At runtime this piece of code works with its individual stack memory.

That's my understanding. Tell me if I'm wrong,

0 Kudos

Hi Horst,


Thanks, makes technical sense and is getting more interesting the more I look at it. I did a little experiment and now understand that the ABAP runtime silently substitutes the subclass reference with the class that implements the method. I don't think this is right, doesn't make semantic sense from a pure OO point of view, because it even bypasses the class constructor.

Example:

REPORT zhello.

CLASS lcl_super DEFINITION.

  PUBLIC SECTION.

    CLASS-METHODS say_hello.

    CLASS-METHODS class_constructor.

  PROTECTED SECTION.

    CLASS-DATA hello TYPE string.

ENDCLASS.

CLASS lcl_super IMPLEMENTATION.

  METHOD class_constructor.

    hello = `Hello`.

  ENDMETHOD.

  METHOD say_hello.

    WRITE hello.

  ENDMETHOD.

ENDCLASS.

CLASS lcl_sub DEFINITION INHERITING FROM lcl_super.

  PUBLIC SECTION.

    CLASS-METHODS class_constructor.

    CLASS-METHODS say_hello_2.

ENDCLASS.

CLASS lcl_sub IMPLEMENTATION.

  METHOD class_constructor.

    lcl_sub=>hello = `World`.

  ENDMETHOD.

  METHOD say_hello_2.

    WRITE lcl_sub=>hello.

  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

  lcl_sub=>say_hello( ).     "Hello <-- lcl_sub class constructor not accessed!

  lcl_super=>say_hello( ).   "Hello

  lcl_sub=>say_hello_2( ).   "World <-- class constructor executed

  lcl_super=>say_hello( ).   "World (correct)

According to the SAP Help: "The first time you address a subclass in a program, its static constructor is executed."

The subclass is explicitly addressed by the code above, no static constructor is executed.


I get it that the compiler somehow remaps my reference to LCL_SUB to the class where it is defined (at least it seems like this is a compile-time thing). It explains why there is no connection to the class used by the caller, but on a more general level the lack of CLASS_CONSTRUCTOR call doesn't make sense from OO and from the SAP help and could catch people out.

Note if I remove LCL_SUPER's class constructor, I get blanks instead of 'Hello', so it isn't a sequencing thing either.

Regards,

Mike

horst_keller
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi,

The following sentences can be found under CLASS-METHODS in the ABAP Keyword Documentation:

  • "The static constructor is called automatically exactly once per class and internal session before the class is first accessed. An access to the class is the creation of an instance of the class or the addressing of a static component using the class component selector. "

  • "If a static component of a superclass is addressed using the name of a subclass, the superclass is addressed and its static constructor is executed, but not the static constructor of the subclass."

-> The above program behavior is explicitly documented already ....

I wouldn't say "doesn't make sense from OO" because no objects are involved here.

Best

Horst

0 Kudos

Hi Horst.

I understand that from your point of view, you want to check if the language is doing what is supposed to do, which is what the documentation says.

However, as a very seasoned developer myself. To me, it is very intuitive that the subclass static constructor shall be called before any static method in that subclass is executed, because otherwise it shouldn't be called (static class) constructor.

With respect to the documentation in your post, the first paragraph quote says -ordering in reverse the effect => cause, to get the cause => effect chain of events:

(1) Addressing of a static component using the class component selector  => it is an access to the class => before the first access: the static constructor is called automatically

And in the same documentation from your link, the next paragraph literally says:

(2) When a subclass is first accessed, the inheritance tree is searched for the next-highest superclass whose static constructor was not yet called. Then the static constructor of this superclass is executed followed by those of all subsequent subclasses up to the subclass in question. The static constructor must be fully executed, otherwise a runtime error occurs.

Which can be summarized as:

(3) If first subclass access => superclass constructor followed by all subsequent subclasses up to the subclass in question are executed


If we logically concatenate (1) and (3) we get:

(4) Addressing of a static component using the class component selector  => it is an access to the class => If first subclass access => superclass constructor followed by all subsequent subclasses up to the subclass in question are automatically executed

Nonetheless, the documentation note -in your second paragraph quote- is an exception to the above rule (4). For completeness I will quote it again:

(5) If a static component of a superclass is addressed using the name of a subclass, the superclass is addressed and its static constructor is executed, but not the static constructor of the subclass. 

Before reading this thread, I would never guess or expected such behavior. I am afraid that many software design patterns will fall in this trap.

If the class (including subclasses) constructor (static and non-static) is not called before any other method, it is not really a constructor at all, and it constitutes a very weird behaviour. To me this is a documented flaw in the language. I don't want to seem rude or mean but it is really what I think.


Please, to overcome this behaviour, how can we force the execution of the sublass static constructor?

Best regards.

OdL

horst_keller
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Oscar,

I don't see point (5) above as an exception to (4) but as a consequence because naming the class in the method call is not the same as addressing a component.

From my (admittedly ABAP based) understanding, the task of a constructor is to define the state of an object by setting its attributes. Regarding a static constructor, there are no objects and its task is to set the static attributes before they are needed the first time. And that is fullfilled in ABAP. Prove me wrong.

In the special case (5) no static attribute of the subclass is addressed and therefore the execution of the subclass constructor is just not necessary.

"To overcome this behavior" simply address a static attribute of the subclass. Then the constructor is executed for sure.

Or even better, follow thre programming guideline

Horst

0 Kudos

Hi Horst,

Great, so two parts of the SAP Help give mixed messages

Of course as SAP created ABAP, they are at liberty to implement their own views of OO. If redefinition of static methods were allowed - as it is in Java - then all this would not be an issue. I accept that SAP have made the decision not to allow it.


Static methods are not completely detached from their class, they form part of the scope of the other class components and can access e.g. a protected static attribute of the class. So even though there is no object, static components form part of the class 'bubble' (I'm writing a diagram here ).

So although technically the runtime redirects the call to the superclass, semantically it is wrong, because the intent of someone who writes ZCL_SUB=> is to touch class ZCL_SUB, otherwise s/he could just write ZCL_SUPER.


Regarding a static constructor, there are no objects and its task is to set the static attributes before they are needed the first time. And that is fullfilled in ABAP. Prove me wrong.

This is precisely what isn't happening and what creates the confusion. The code specifically refers to class ZCL_SUB, because I want ZCL_SUB's class constructor to execute. It sets different attributes to ZCL_SUPER. But I still end up with the attributes of ZCL_SUPER. This is the bit that is counterintuitive.

Regards,

Mike

0 Kudos

Hi Horst.


Quote from your post:


I don't see point (5) above as an exception to (4) but as a consequence because naming the class in the method call is not the same as addressing a component.


Just to check if we are using the same terms in the same sense: When in a language we refer to some data or code object (including class components), we are addressing some entity (the object) in a particular memory location. It's clear that the adressing occurs as a consequence of the reference, like when naming a static class component. In ABAP, the components of a class: attributes and methods, are examples of those addressed objects.


Looking clearly, the note (5) is not an exception of (4) but a contradiction. The note (5) says that if we refer to "zcl_sub=>something()", where something is a static component inherited from zcl_super (and not redefined) the compiler will interpret this as if we would be referring to the "zcl_super=>something()" object, in the sense it will address that object.


As we are talking about static components, that compiling simplification seems harmless... until we realize that as a consequence of this, compiler ends up calling only the constructor of zcl_super and not the one of zcl_sub. However, when we as developers, referred to "zcl_sub=>something()", we didn't mean to refer to "zcl_super=>something()",right? Is the compiler the one that makes that switch, and in a so strictly way that it doesn't call the expected static zcl_sub=>constructor but only the zcl_super one.


Compare the above facts with the point (4), composed by the points (1) + (3), also in ABAP documentation. The point (1) says "The static constructor is called automatically ... before the class is first accessed. An access to the class is ... the addressing of a static component using the class component selector". The tricky part here is: it is not possible to address a subclass inherited component! you can refer to it in your code "zcl_sub=>something" but for the compiler considerations, you are addressing to "zcl_super=>something". This is a proposition of the form "P then Q" (addressing a static component then the static constructor is called automatically) where P can never be true (in our case of inherited static components), so the proposition in red is always true!!


Nonetheless, the part (3) in (4) says "When a subclass is first accessed... the static constructor of the superclass is executed followed by those of all subsequent subclasses up to the subclass in question...". Clearly what happens contradict this.

Regarding a static constructor, there are no objects and its task is to set the static attributes before they are needed the first time. And that is fullfilled in ABAP. Prove me wrong.


Horst, of course that was proven wrong. In the example of Mike Pokraka, the call to the method zcl_sub=>say_hello() requires the previous setting of the hello attribute with the value "World" by the constructor, right when the zcl_sub class is referred for the very first time. However, for all we have seen above, the compiler, doesn't do that and executes only the zcl_super constructor, completely disregarding the semantic meaning of the zcl_sub static constructor. That's why the zcl_sub=>say_hello() unexpectedly writes "Hello".

Or even better, follow thre programming guideline 

Whaat??!! The Programming Guidelines are in public domain ? I demand the refund for the book "Official ABAP ™ Programming Guidelines" I bought from SAP Press in 2013!!


Now I understand why that guidelines recommend so adamantly to avoid the use of static classes (those with only static components). Conceptually I agree with that way of thinking, for all the good reasons exposed there. And now, even more because the issue we are dealing here.


However, the described situation in ABAP affects not only static classes, but also to those with just few static members. For example, I have a problem dealing with a hierarchy of exception classes whose constructors, as you know, are autogenerated by Netweaver and moreover can not be edited! This means, the only way to construct them without the regular constructors (this is for very good reasons, beyond the scope of this thread) is with static components. But this is minefield if I mix regular OOP factory designs with this peculiarity in ABAP.


You should warn about this with red big size letters in the documentation, otherwise many will become crazy trying to chase a bug in their code, when it is a language feature.


Interestingly, in the Scala language there are not static class components, they use instead "the companion object", decoupling completely the static components from the really OOP ones. This way they can define any particular behavior for those companion objects without clashing well known OOP behavior expected by the users as it is happening here.


Best regards.


OdL

horst_keller
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi,

If you accept the facts (even if you don't like them), that static components of classes  in ABAP are designed in a way that:

  • the static constructor is executed exactly once per internal session before an instance of the class created or a static component of the class is adressed

  • naming a  subclass for accessing a component of the super class does not access the subclass but the superclass

Mike's example does not prove that wrong but right.

According to these facts, the first

zcl_sub=>say_hello( ).

does not access the subclass but the superclass. The static constructor of the subclass is not executed because no static component of the subclass is adressed.

Only with

zcl_sub=>say_hello_2( ).

the subclass is adressed because a static component of the subclass (the method) is accessed. Therefore, the static constructor of the subclass is executed before method say_hello_2.

Maybe the whole confusion comes from the fact, that you think that the hello-Attribute is an (inherited) attribute of the subclass. It isn't. Static attributes always belong to their defining class. Subclasses can adress static attributes of superclasses but they don't inherit them as their own attributes. See also Inheritance and Static Components (in fact, an example similar to Mike's is already there ...).

You can dislike the design of static components in ABAP Objects, that's OK for me. But, if you accept it as it is, I still don't see contradictions in the documentation (if you accept the term "access" as defined above).

Horst

horst_keller
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Mike,

see also my response to Oscar below.

I guess, I see the source of all that confusion now: You think that inheriting a static attribute of a superclass in a subclass means to take it over as an own attribute and that accessing such an attribute should trigger the subclass' static constructor. Well, in ABAP Objects, static attributes are not inherited like instance attributes but are simply accessible along the inheritance tree. They always belong to their defining class. Accessing a superclass attribute in a subclass does not trigger the subclass' constructor but only the superclass constructor.

Maybe that's a fact that I can try to point out still more clearly in the documentation (besides the existing topic ...).

Best

Horst

0 Kudos

Hi Horst,

I understand it all, and I accept that SAP have taken the decision to implement it this way. The difference in opinion is that you are talking from the ABAP runtime point of view and I (and Oscar) are looking at it from a semantic side: If I write ZCL_SUB I mean ZCL_SUB. If I draw a diagram with words: I am going from my code into the class, then up to find the defining class. It's counterintuitive that the ABAP runtime just shortcuts this, but so be it.

Another small item to throw in here is that static constructors are executed down the whole hierarchy, so static classes themselves do follow some sort of class hierarchy logic just not the methods. To me the class model is and will always remain just a tiny bit inconsistent.

Thanks for all the info by the way, it's been very informative.

Regards,

Mike

0 Kudos

I think the whole matter is now clear.

I never denied the facts (that is not even possible, you can be in denial but you can not deny verifiable facts). I just stand my point with the naive hope that having you an input from your users may help a little bit to have a better ABAP; a language I can hate some minutes and just tolerate others, but most of the time I love it (like a wife ?).

I hope you don't mind a little humble suggestion for you and the ABAP documentation. I see you tend to express your reasons with the semantics that the ABAP compiler assigns to the code, which in some cases is not the same a developer want to express in his/her code, as in most known OOP languages give to those idioms.

For example, you say "zcl_sub=>say_hello( ) does not access the subclass", when that is exactly the semantic that a developer will give to that code. I now understand it doesn't address the subclass, but anyway, the expression looks for access to the subclass.

Another example is when you say the hello attribute is not inherited by the subclass. If the subclass didn't declare that attribute; from where does it come from if not from the inheritence?

That particular meaning of your words is the reason this topic needed too much text to understand it. It would be more helpful to hear something like "it seems like you are <some commonly used OOP semantics>, but in fact in ABAP you are <ABAP interpretation of code>" in the cases when those semantics doesn't match. Just like you express in your last mail to Mike.

Thank you for patience.

OdL

0 Kudos

Hello Horst,

it's been a while since you've posted this but I'd like to know how exactly were you parsing the code in this situation. I mean, in similar approach like Mike (FALV) I used RTTS to pass local subclass type to factory method and then I was able to create object with subclass type but I wanted to avoid it (passing the object type), so after reading this post I thought that maybe this would be the solution:

- read call stack

- get the source of the caller

- check if static method was called using subclass name or directly main class

- in case of the subclass was used then check what's the type of it using RTTS and then create object using this subclass.

The question is if you have this logic somewhere in a class or I have to build it from scratch?

Cheers

Łukasz

0 Kudos

Hello Horst Keller,

maybe from other way, is there a way to get from the stack not only the line of the caller but also offset?

Just as a background:
- I have factory method CREATE in class ZCL_FALV

- I have also local class which inherits from ZCL_FALV -> LCL_TEST

- I know that method CREATE is not inherited to LCL_TEST

- I'd like to check using source code and call stack, if the CREATE method was run using global class name or inherited class name

I think the only thing I miss is line and offset of the CREATE method in the stack, as currently when in CREATE method I will call any of known by me stack retrieving function or method for the example below, I will get info that the call is in 43rd line.

This is partly true. Means, that the start of the syntax is in the line 43 but the call of method is in 44th.

Additionally If I would have a line in the code (only theoretically) with such construction:

falv ?= lcl_test=>create( ) . falv2 ?= zcl_falv=>create( ) .


then for both of the calls I would receive from stack the same line in which it appeared.


Do you know and can you share the info how to get exact line and offset from the stack?


Cheers

Łukasz

horst_keller
Product and Topic Expert
Product and Topic Expert
0 Kudos

There's nothing, I'm proud of. You can debug CL_DEMO_OUTPUT and will land in

CL_DEMO_OUTPUT================CCIMP

where I try to get the name of a parameter passed in order to display it as a title. There are two  attempts that did not work in all situations and my WYCIWYG part. I also looked at CL_ABAP_COMPILER and the SCAN command, but never became friend of those. Since I know the method name, I help myself with string processing ...