If you didn’t have a chance to read first part of this blog you can make up for it by readingDo you really know everything about typing?, as I am going to discuss the same concept but in terms of dynamic typing. You can also read this part independently of the first one, as general idea is to familiarize you with dynamic data typing per se and show its use in more advanced examples.
Static vs dynamic
You must have heard of this terms before. Static are all data objects and data types known before runtime i.e
In those definitions syntax checker staticallyknows the data objects and data types used for typing the former, so can check their correctness. This also means that evaluation of memory space these data will occupy can be done before runtime.
In contrary to statically defined data objects and types, we have dynamic ones. Those are unknown to syntax checker, hence they cannot be checked before the program is run. This is like telling syntax checker: “Please don’t check these definitions/types until you reach that point during runtime. I assure you I will deliver that missing information later”.
What is the risk?
While dynamic definition and typing open new doors to developer to create highly generic programs it also leave all the responsibility for erroneous situations to him/her as well. Syntax checker assumes you are skilled and know what you are doing. Ultimately you told it indirectly you are not interested in its help. As the code is almost always not perfect, very often this creates situations we didn’t predict. To decrease the risk we should always try to catch such situations by i.e. using exceptions. But let’s leave these digression now and focus on dynamic data and types themselves.
In all the examples explained here I will not use any exception catching as I want you to focus on different thing. However, in your program, you should always consider that as this is a very good practice and protects your programs from errors.
I need that be defined dynamically!
I often meet such requirement while going through different forum threads. I know it has been a lot said about it so far, but let’s pretend we know nothing about this.
The most uncommon situation, though most basic one is creating dynamically a single field (data object). We can do this in couple ways. The first way is to use CREATE DATA statement. This allows to create physical data objects for which the memory is allocated.
The above statements create in memory the following
So we got the empty, unnamed fields of appropriate type in the memory.
In order we could access any of them we need to dereferencerespective reference variable (getting the value of such field the reference is pointing at). For this we use field symbols.
Discussing field symbols would be of topic so I won’t focus on this part. You can easily follow up with documentation.
Based on the above we can also create structures and tables
Ok, we now know there is something that lets us creating dynamically physical data objects in memory, but how about creating a pure dynamic type. Unfortunately there is no statement like CREATE TYPE in ABAP. You would probably say, that designating data type dynamically can be done as here…
…which means that data type comes during runtime. Your are right then. But how if you want to provide more custom type which is not a DDIC or local one. Creating a new structure in DDIC just for typing purpose of reference variable in one program? This would be a waste of space. So we need some generic way of creating any TYPE we want, starting from the basic field type, ending with really complex ones as nested structure type and table type.
The solution comes with introduction of RTTS (Run Time Type Services). Basically this is a bunch of SAP delivered classes, which serve the purpose of Run Time Type Information (RTTI -> as of SAP Web AS 6.10) and Run Time Type Creation (RTTC -> as of SAP Web AS 6.40). What does it mean is that we can use RTTI to designate type of existing data objects in program during runtime, or we can use RTTC to create new dynamic types and use them for typing.
Before we delve into this lets see those classes as inheritance tree
We can see that the more specific the class is the lower in inheritance tree it lies. It is tightly connected with the inheritancewhich you can read about in documentation. The casting term is also what you should get familiar with, but which is of this blog topic.
The basic rule of using RTTI would be calling one of static methods describe_by_…. of one more generic class (those which have any child like CL_ABAP_TYPEDESCR, CL_ABAP_DATADESCR, CL_ABAP_COMPLEXDESCR, CL_ABAP_OBJECTDESCR) in order to get returned instance of more specific class (those which don’t have any children like CL_ABAP_ELEMDESCR, CL_ABAP_REFDESCR, CL_ABAP_STUCTDESCR).
So this can be used to get the type of already existing data object, data reference, structure etc.
The second use is creating new data types. For this purpose we would be using one of static factory methods create_… or get_…. The rule is the same as above. We finally expect to get instance of non-parent class. Such instance is just and object which describes a new data type.
Lets take a closer look at their usage.
First dynamic data types
For creating those we use class cl_abap_elemdescrand its get_… methods. I will start working on the example I used in my last blog – the headcount and capacity.
So first we need a headcount and capacity data types.
In both cases we receive reference variable of type cl_abap_elemdescr. This is nothing but the class instance which describes this data type. To create a data object from this type description we need.
GR_I and GR_P are nothing but reference variables same as we created earlier. They receive the type which is HANDLED by objectsgr_elemdescr_i and gr_elemdescr_p respectively.
So we just created our dynamic data types and used that objects for typing dynamic data objects. Simple, isn’t it?
The same as above we can easily achieve with RTTI methods. These however require existing data object which we derive the type from. This goes like
The first statement shows us that we can take the type from the existing data object. For obvious reason the above doesn’t have much sense (we first create g_headcount and just right after it we take its type). We normally use it in cases where i.e. some parameter is passed to procedure which is typed as ANY, and only during runtime we can derive its type from the parameter. We can then evaluate whether it is a table, a structure or a data object.
The second example shows us how to take the type of some DDIC object. Here we use SFLIGHT to take the type from it.
In real cases you more often use RTTI then RTTC, however the later gives more power to developer as he can construct his/her own data types in customized way.
One step further
Let’s go back to our RTTC and focus on the functionality it delivers.
The next thing to do is to create a structured data type which we will use for creating dynamic structure. The static definition goes like:
Before that a small task for you. Go back and have a look at RTTS tree. Which class do you think is suitable for creating above structure type? ….
I believe you found the right one, so I will just go for next snippet, which fulfills this task.
That’s it. Supprised? I think you already start feeling what is going on here. We use specially typed table gt_components adding two rows to it. Each of them holds name of the component and corresponding type. If you double click component_tableand then navigate to its definition in class builder, you shall see that type expects cl_abap_datadescr, so we can add any RTTS class object we want apart from those from node cl_abap_objectdescr.
Again to create a dynamic structure from this type we need:
For nesting, we just use two remaining fields from component_tablestructure, namely as_include and suffix (if necessary).
The static type we want to create is
We will therefore use our already created structured type gr_structdescr to include it as component of another structured type. I will also create another elementary data type (N(8)) for typing the first component.
GR_DATA now holds what we expected. Each component is renamed (to keep components’ naming uniqueness) and the structure after dereferencing to field symbol can be addressed as presented in first blog.
As promised last time I will show how to finalize the creation of second nesting structure.
Again for reminder we want to create such type
This time ts_year_data will include two nestings. First one is basic classification for DATA and MEAN, second one contains basic components itself.
I am using naming in reversed order i.e if I use gr_structdescrthis means I am referring basic components (which are in fact twice nested), while gr_structdescr1 stands for structure ts_data (which is once nested) and gr_structdescr for ts_year_data which has the top level components (is not nested itself). This is due to fact that we are going from the basic examples to more advanced. I didn’t want to scarry you with the gr_strucdescr_lev2 at the very beginning, so I used gr_structdescr instead and incremented this value for next examples. Apologies for this confusion.
And in the previous coding we just change gr_structdescr_lev1 to be included as component of final nesting + use different ref variable gr_strucdescr_lev2 as a result of type generation.
The entire snippet would therefore be
You can check in the debugger how our structure gr_structure looks like.
Before we end up I want you to see how to create a table for this or any other structure type. All we need is
What I hope you have learnt with this blog is how to create complex structured data types dynamically. If you combine this technique with the ability to address subcomponents as independent units (as presented in previous blog) you will have quite powerful tool in your hand. How you are going to use it, is up to you. Anyhow I encourage to build couple of examples to feel the rock yourself.