Technical Articles
ABAP-Types with class
An application has its types: table types, structures, even types for references to classes may be useful. In order to make types accessible to all classes of our application, it’s obvious that they should go to a central point, which could be a class or an interface.
I personally prefer a class for types, because an interface has a different usage: it is made for being implemented by another class. Types are only declarations that should be available from different classes. But all what I am going to talk about works for interfaces and classes as well.
So we start our application in our brand new packet, let’s name it ZAPP.
The types class
class zcl_app_types definition.
public section.
types awesome_data_line type some_structure_from_ddic.
types awesome_data_lines type standard table of awesome_data_line with empty key.
endclass.
Now we are ready to use it:
class zcl_app_backend definition.
public section.
methods do_the_magic_on_table
importing data_line type zcl_app_types=>awesome_data_lines.
methods do_the_magic_on_line
importing data_line type zcl_app_types=>awesome_data_line.
private section.
data awesome_data_lines type zcl_app_types=>awesome_data_lines.
endclass.
Use a shorter alias for the type class
But how can we make it slimmer? It’s pretty noisy having always the ZCL_APP_TYPES as a prefix for each type. In real live, the name may be much longer (real live example: ZCL_MM00_PURCH_HISTORY_TYPES). With interfaces, we could use aliases to map types to local names. But this means creating a new alias for each new type of the local class which is quite noisy too.
With a type class, we can do a mapping with a simple trick: creating a data object with reference to the class. The data object offers all public static elements such as types. Using this, the class transforms like this:
class zcl_app_backend definition.
public section.
data types type ref to ZCL_APP_TYPES.
methods do_the_magic_on_table
importing data_line type types->awesome_data_lines.
methods do_the_magic_on_line
importing data_line type types->awesome_data_line.
private section.
data awesome_data_lines type types->awesome_data_lines.
endclass.
Types from other APIs
Now we have types-> as a prefix for all types of out application-own types class. When we use types from other API applications, the name extends a bit:
data common_types type ref to zcl_abap_common_types.
...
methods get_binary_lines
returning(result) type common_types->ty_binary_lines.
When use types classes
I personally keep all types that are used in more than one class in my types class. In other words: no public types if not in the type class. However, there are always exceptions to the rule. In DB_ACCESS classes that are intended to only transfer data from the data base to the application, I sometimes define my result table directly in the interface:
interface zif_app_db_access.
types settings type standard table of zdb_pp01_001 with empty key.
methods read_settings
returning(result) type settings.
This is OK for me as long as I never see
type zif_app_db_access=>settings
in my code. As soon a the type is needed in other classes than the DB_ACCESS class, I would transfer it to zcl_app_types.
Where is the benefit?
To me, it is very simple to just use types->… to have access to the types that my app is using. Using the editor’s code completion I can see directly every type already available. Since every type is in one class, no ambiguous names occur. (think of zif_db_access=>ty_data, zcl_app_backend=>ty_data…). Distinguishing between types and variables is also easier for the types look always like type->data_lines while the variable appears as data_lines only.
The shorter naming extends also legibility because code lines are kept shorter. Each set of types can have a clear name that replaces the global name of the class.
Hi Jörg,
I personally use a lot the types declaration within a class but I have to disagree with you on one point: "When use types classes - I personally keep all types that are used in more than one class in my types class".
If you need to use the same type in more than one place, I would always suggest creating it in SE11.
Cheers,
André
To me, a DDIC type is useful when using it in user interaction. Otherwise defining texts for labels in different sizes and languages seems needless to me. I prefer to define types that serve for program logic and not for user interaction directly in ABAP code. This is also less time-consuming.
I agree with this philosophy. If it's a purely "technical" type, i.e. we don't need any semantic definitions and don't plan taking advantage of anything associated with dictionary types (i.e. it won't be anything user-facing or used in a service definition that can be generated, and such) then there seems to be no advantage in using dictionary. Granted, SE11 has better "discoverability" but it also means it can easily become polluted, especially when similarly named elements are used in different contexts with different definitions.
It's all about the use case, plain put.
Thanks for the blog!
what is the difference between DDIC-structure and public type of interface?
in both cases it is in server memory, but in DDIC it is more manageable and clear to check and compare.
I guess one argument in favor of defining a type in the DDIC is to avoid having errors during the transport of repository objects, by transporting the DDIC objects first in a dedicated request (as far as a DDIC type does not refer to a class or an interface...)
But there is the Transport Check tool to avoid those errors too...
As a note: If a class isn't a type class and you discover a lot of types statements in it, then this can be a hint that the class has too many tasks (see "Separation of concerns").
I think for NetWeaver is not the best option to use types in class. DDIC is the more preferable.
The main reason: when the types in class or interface is changing , the program where it is used is forced to regenerate and it could cause the syntax errors (LOAD_PROGRAMM_MISMATCH) during the transporting.
Another option is DTO (but it is differ from types).
What is DTO?
DTO on wiki
Data Transfer Object sample:
Sincerely I do not get your point Wouldn't a change of a ddic type also cause a regeneration of the program? Whether you have types in DDIC or a class, the repo objects must be always aligned before running the program.
In case of a type class with 100 types you have one repo object to align. When each type is in ddic you have 100 repo objects to align. I prefer the first one.
in case class will be used in several reports/classes/functions - all this functions would be regenerated even if you change .
in case you have 100 separate objects - small change will cause regeneration only where exactly it one changed object is used.
For global types abap_help mostly tells us that declaration is up to context, but provide recommendation about separation of concerns and semantics meaning.
ABAP declaration
I understand the point. But I do not see the disadvantage - when a change comes with transport order, why should i be concerned whether 10 or 40 programs are regenerated?
As described above, the type classes are application-exclusive. So the where-used lists of them are not too big.
Another thing is the name: a ddic type can have a 30 character name. Depending on your naming conventions (or even worse a name space) few space may remain for a clear and descriptive name.
Having the type in a class, you can use all of the 30 characters available to the name. Since the type class is application-exclusive, no prefixes or namespaces are needed.
yes, you are correct. it depends on the situation. And sometimes we should not care about this. Agree. But sometimes we should.
? However in DDIC I could put also documentation and make reference to data element.
PS. Actually I am using both types in class/interface and DDIC and agree with you point but trying to provide another approach.
Mostly I am using types in class + DTO and it provides more semantic information for code understanding.
For a reader of my code, the documentation is several clicks away.
Say, we have an application in a package ZMM01_MRP_UTIL. Using a types class, I can name a needed type freely
Using a DD type, I have to take care of the name in order to avoid conflicts with other application. It could lead to a coding like this:
Personally, I find the first example better to read.
References to data elements can be made in type declarations too.
I think it depends on whether the method public or private.
In case you have incapsulated logic (or group of class) - it would be very nice to have type in interface or class as you specified.
But in case you have many-points to use type (structure or data element) - it would be more clear to use DDIC-structure.
Another score for DDIC is parameters in RFC/UPDATE TASKs and OData-services. It is impossible there to use interfaces types. and in that case where used list would show that object is part of some integration. in case of interface type you would not find it.
Lars Hvam what are your thoughts on this? Especially the part on public types: "no public types if not in the type class", is it an approach we could adopt?
I have not read the full blog, but it seems like a anti-pattern, the types class will become a god object
Define the types in the interfaces where they belong with the logic/abstraction, define types in ddic if its used in databases or dynpros(for texts)
I am creating own types classes for each application. Why should these have the smell of a god class?
If an application is small, it will not matter, but applications tend to grow over time.
Take abapGit as an example, would it be considered an application? It has around 530 TYPES definitions.
It's true that one should not have one class with 500 types in it. As applications grow, things should be drilled down to smaller entities. So do types classes. Typically, I add sub packages when applications grow big. so I can divide also my types classes.
This code throws error:
That's because the object "types" is not instantiated in the defintion section. I don't know whether such issue depends on de abap version (I'm using 7.4 sp6)
Anyway I've used this method in the implementation section but only after starting the "types" object in the constructor:
I found that having a class as a types and constants container has some nice advantages if you need some semi-constant data. For instance:
I am on 750 SP 19 - here it works.
However - meanwhile I found out that generating the test frame for classes (when pressing F8 from the editor) does not work with declarations like this. It seems that ABAP (in my version) is able to access the types of a non-instantiated object variable, but the code generator is not able to handle it.
Therefore, I switched to creating the types class as abstract and derive a local class-relevant class from it:
Note that with this approach (as shown abovd), you will have to use the full class name in the public section
How to reference to a parameter of a method when the type is not defined in the class?
Something like this:
Why should you abuse a parameter definition as a type defintion? Define your type in the types class:
then refer to the type from both the method definition and the data line.
I use the same approach, but I am facing a problem on how to correctly determine the domain at runtime of a type that uses your kind of "alias".
Say, I have a class y_owner with one type and a setter method with an input parameter of that class type.
WCB_OWNER_TYPE is a domain with fixed values. I want to write a unit test for setting valid values, and for that I want to get all fixed domain values of "type" (WCB_OWNER_TYPE).
Before I can do that, I need the domain name of the field, so WCB_OWNER_TYPE.
But I can't get it through RTTI, because the absolute name is obfuscated by the class type:

RTTI of iv_type
This also leads to the fact that it is not recognized as a DDIC type, despite it actually being one, but underneath that "class type".
I don't want to hardcode the domain name into my tests and I also want to keep using the "class type".
Any idea? I'm on 7.56.
Hello,
you can use the public attribute HELP_ID of the class cl_abap_typedescr to determine the domain at run time. See my example (note that I use the abstract class approach mentioned in my comment above):
Thanks, Jörg! I had noticed the help_id, but could not be certain that it always contains the domain.