ABAP News for Release 7.51 – Enumerations
It is a common pattern. A data object, say an attribute of a class, should assume only values from a given set. Before Release 7.51 that might have looked as follows:
CLASS cx_wrong_size DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.
CLASS shirt DEFINITION.
PUBLIC SECTION.
TYPES tsize TYPE i.
CONSTANTS:
size_s TYPE tsize VALUE 0,
size_m TYPE tsize VALUE 1,
size_l TYPE tsize VALUE 2,
size_xl TYPE tsize VALUE 3.
METHODS
constructor IMPORTING size TYPE tsize
RAISING cx_wrong_size.
...
PRIVATE SECTION.
DATA
size TYPE tsize.
ENDCLASS.
CLASS shirt IMPLEMENTATION.
METHOD constructor.
IF size <> size_s AND
size <> size_m AND
size <> size_l AND
size <> size_xl.
RAISE EXCEPTION TYPE cx_wrong_size.
ENDIF.
me->size = COND #(
WHEN size <> size_s AND
size <> size_m AND
size <> size_l AND
size <> size_xl THEN THROW cx_wrong_size( )
ELSE size ).
ENDMETHOD.
ENDCLASS.
Here, the size attribute of a shirt class should have only values that are defined as a set of constants in the class. Other values lead to an exception. A user can create an object of the shirt class as follows:
TRY.
DATA(shirt) = NEW shirt( shirt=>size_xl ).
CATCH cx_wrong_size.
...
ENDTRY.
You see the overhead? Why not let the runtime environment do the value check for you? There is a concept for this called enumeration or enumerated type.
With Release 7.51, ABAP will support the concept of enumerations too. Let’s rewrite the example using such a new enumerated type:
CLASS shirt DEFINITION.
PUBLIC SECTION.
TYPES:
BEGIN OF ENUM tsize,
size_s,
size_m,
size_l,
size_xl,
END OF ENUM tsize.
METHODS
constructor IMPORTING size TYPE tsize.
...
PRIVATE SECTION.
DATA
size TYPE tsize.
ENDCLASS.
CLASS shirt IMPLEMENTATION.
METHOD constructor.
me->size = size.
ENDMETHOD.
ENDCLASS.
A new variant of the TYPES statement, BEGIN OF ENUM – END OF ENUM, serves as a bracket around a set of constants. The standard base type of the constants is i and the enumerated values are counted up starting with 0.
The usage looks as before:
DATA(shirt) = NEW shirt( shirt=>size_xl ).
But hey, there’s no need for exception handling any more. If you try to pass an illegal value you get a syntax error!
DATA(shirt) = NEW shirt( 333 ).
Enumerations are a mixture of types and constants. With BEGIN OF ENUM enum – END OF ENUM enum you declare an elementary type enum that can be used behind the TYPE addition. In between, you declare a set of constants, the so called enumeration constants, that define the enumerated values that are allowed for enumerated objects that have the type enum. At this position TYPES in fact works as the CONSTANTS statement.
The ABAP runtime environment takes care, that only allowed enumerated values can be assigned to enumerated objects:
TYPES:
BEGIN OF ENUM tsize,
size_s,
size_m,
size_l,
size_xl,
END OF ENUM tsize.
DATA size TYPE tsize.
size = size_xl. "Allowed
DATA dobj LIKE size.
dobj = size. "Allowed
dobj = 333. "Syntax or runtime error
You can assign enumerated objects only to enumerated objects of the same enumerated type and you can compare enumerated objects only with enumerated objects of the same enumerated type. Of course, this includes the enumeration constants itself.
Normally, you are not interested in the contents of an enumerated object at all. The semantics of an enumerated object is defined by the enumeration constant that defines its value. Nevertheless, you can define enumerated types with other base types than i and with other enumerated values (where one value must be initial):
TYPES:
basetype TYPE c LENGTH 2,
BEGIN OF ENUM tsize BASE TYPE basetype,
size_i VALUE IS INITIAL,
size_s VALUE `S`,
size_m VALUE `M`,
size_l VALUE `L`,
size_xl VALUE `XL`,
END OF ENUM tsize.
DATA size TYPE tsize.
size = size_xl. "Allowed
DATA dobj LIKE size.
dobj = size. "Allowed
This enables you to easily transform your existing “enumerated values” to the new concept. If you are lucky, you might be able to this without having to adjust their usage (in fact, I was able to do so for one of my classes).
If you have more than one enumerated type within one context, you might want to organize the respective enumerated values in structures:
TYPES:
BEGIN OF ENUM tsize STRUCTURE size,
s,
m,
l,
xl,
END OF ENUM tsize STRUCTURE size.
DATA dobj TYPE tsize.
dobj = size-xl. "Allowed
With that, you declare a constant enumeration structure size. The components of the structure are the enumeration constants of the enumerated type.
The main usage of enumerated objects is comparing them with the respective enumeration constants in order to branch to some according functionality.
TYPES:
BEGIN OF ENUM tsize STRUCTURE size,
s,
m,
l,
xl,
END OF ENUM tsize STRUCTURE size.
DATA dobj TYPE tsize.
...
CASE dobj.
WHEN size-s.
...
WHEN size-m.
...
WHEN size-l.
...
WHEN size-xl.
...
ENDCASE.
Besides that, there are a few other allowed usages:
You can assign an enumerated object to text fields of type c or text strings of type string. The result is the name of the enumeration constant that defines the current value.
TYPES:
BEGIN OF ENUM tsize,
size_s,
size_m,
size_l,
size_xl,
END OF ENUM tsize.
DATA text TYPE string.
text = size_xl.
cl_demo_output=>display( text ). "Output is SIZE_XL
You can also write
DATA(text) = CONV string( size_xl ).
You can access the current value with the CONV operator by specifying the base type.
TYPES:
BEGIN OF ENUM tsize,
size_s,
size_m,
size_l,
size_xl,
END OF ENUM tsize.
DATA(value) = CONV i( size_xl ) .
cl_demo_output=>display( value ). "Output is 3
The other way around, a valid enumerated value can be converted to an enumerated object (which is not possible in a normal assignment):
TYPES:
BEGIN OF ENUM tsize,
size_s,
size_m,
size_l,
size_xl,
END OF ENUM tsize.
DATA(num) = 3.
TRY.
DATA(dobj) = CONV tsize( num ) .
cl_demo_output=>display( dobj ). "Output is SIZE_XL
CATCH cx_sy_conversion_no_enum_value.
...
ENDTRY.
There is also a new class CL_ABAP_ENUMDESCR in RTTI.
TYPES:
BEGIN OF ENUM tsize,
size_s,
size_m,
size_l,
size_xl,
END OF ENUM tsize.
DATA(size) = VALUE tsize( ).
DATA(enum_descr) = CAST cl_abap_enumdescr(
cl_abap_typedescr=>describe_by_data( size ) ).
cl_demo_output=>new(
)->write_data( enum_descr->kind "E, for elementary
)->write_data( enum_descr->type_kind "k, new for enumerated type
)->write_data( enum_descr->base_type_kind "I, the base type
)->write_data( enum_descr->members "Table of constants and values
)->display( ).
And that’s basically all.
Lean back and let the ABAP runtime environment do the work for you. It takes care that enumerated objects can only be used at appropriate operand positions and that they can only contain their prescribed values. An illegal enumerated value in an enumerated object should never occur (OK, there’s one known gap …).
Thanks Horst, I think I can see a few good uses for this.
Why is the output 3? Isn't ABAP an one based language?
Cheers,
Custodio
Hi Custodio,
As I said above,
ABAP follows the general design pattern for enumerations here.
Horst
Hi Horst,
that's a big step towards input check simplification and data consistency. What I'm still missing is that one killer feature - integration with domain values from ABAP DDIC when typing with data elements. But I know: this will never happen.
Regards,
Thomas
You are so right. That was the first question, that crossed my mind, when I’ve seen the enumerations for the first time. In fact, the design is there, it’s only a question of ressources and priorities. Hopefully it will happen.
Hi Horst,
Sorry, I have some stupid question: what is actually release 7.51?
When I check Netweaver in the marketplace it seems it has 7.45 kernel, so not really sure if it's a like a patch for a NW 7.50 system or something new?
Are there other bigger changes in this release or smaller ones?
Thanks,
Peter
RTC of 7.51, the successor of 7.50 was planned for today, but postponed a few days.
-> Yes I am a bit too early, but the temptation to blog in the new community was just too big …
(and well, Karl Kessler mentioned it too)
Therefore, pls. just wait a couple of days until official announcement and you'll see further blogs with other nice stuff.
Thanks a lot for the clarification.
Peter
PS: Currently I feel a little bit lost in the new platform, however now I'm happy that there is syntax highlighting for ABAP code. Rendering takes some time, but hopefully it will be improved.
Here we go ...
Thanks
nice feature, I’m really looking forward to use it.
By the way that’s what you can do in lots of other programming languages. E.g. C++, and as far as I know the ABAP kernel is programmed in C/C++, well…
Just an idea, what do you think?
I've been wanting this feature for years! When I've had to use DATA instead, I've felt a little sad. 🙁
Forwarded to development ...
If I may add, I think it would be cool to put a freezing condition for the constant creation, it is also used in some languages (Like Ruby)
Br,
Raphael Pacheco.
Hi Christian,
Believe it or not, but the Kernel developers had it already on their minds. Working title "static single assignment". But for the time being its tentative.
Best
Horst
Good to hear 🙂
I'm curious. Let me know if you need a beta tester.
More or less like the let keyword in C# or Swift – Static Single Assignment.
Hello, Horst.
Thanks for this blog, it is very interesting information.
I would like to ask, do you use Eclipse for development or GUI.
And what kind of development environment for ABAP you can recommends? Maybe Eclipse is the future of ABAP development.
I believe the future of ABAP is in the web based IDE (whose name escapes me).
I use a mixture of Eclipse and SAPGui in my daily work, but generally prefer SAPGUI, because I find it is actually better suited to software design (as opposed to coding)..
Hi Matthew,
currently we have no plans to integrate ABAP into the Web IDE as there are no plans to integrate ABAP into HCP.
Eclipse is the development platform of choice for ABAP development. SAP GUI based ABAP workbench is obsolete but still supported for compatibility reasons. Modern concepts like CDS are only supported in eclipse. So the clear recommendation from SAP site is to use Eclipse.
Kind Regards,
Thomas.
Yes, I know you'd like us all to use Eclipse, but I find it more awkward to use - and I really have given it a fair go - I use Eclipse all the time for Java development.
It may be SAP's choice, but it ain't mine. Yet.
Hi Matthew,
why do you think eclipse is more awkward to use compared to SE80.
Can you give some examples?
Regards,
Thomas.
Thomas, and what to do with objects that have not been implemented in Eclipse? Such as GUI Status, screens, lock object and other?
"I would like to ask, do you use Eclipse for development or GUI."
Exactly as Matthew, "I use a mixture of Eclipse and SAPGui in my daily work, but generally prefer SAPGUI".
"Maybe Eclipse is the future of ABAP development."
Let's hear Thomas Fiedler about that ...
Mabe we can ask Björn Goerke as he was already in the future 🙂 #SAPTeched
Converting semantic error that has to be coded for to a syntax error, is a very good thing. This gives a quick and easily convertible ENUM implementation, but was consideration made (is it being made) to a more class based ENUM implementation - as in Java - with constructors and other methods (like toString) being possible?
I found a nice implementation of enumeration classes or better how to simulate them.
http://stackoverflow.com/questions/20637925/is-it-possible-to-create-an-enumeration-enum-in-abap
I don’t think it’s too much overhead. You can create nice check and validation methods than, if you need them.
Hello Horst,
I’m a little perplexed when you say that “The usage looks as before: DATA(shirt) = NEW shirt( shirt=>size_xl )."
If I read your next examples about assignments to data objects, I guess it should behave the same for parameters, but you don’t mention it explicitly. So, I mean the following should compile too (size_xl instead of shirt=>size_xl): DATA(shirt) = NEW shirt( size_xl ).
Thanks for the clarification.
Sandra
Hi Sandra,
It is simply a question of visibilty. In the first example, the enumeration constants are declared as static components of a class. As always, you have to put class=> before them in order to access them from outside the class. Your DATA(shirt) = NEW shirt( size_xl ). would work inside the class only.
The following examples for simplicity declare und use enumerated types within the same context (program, class, method, ...) and therefore no prefix class=> is needed.
Best
Horst
Oh, really too bad, I'm disappointed ! 🙂
But, as the type of the parameter is an enumeration, the compiler should be able to locate it automatically in the class pool, and I hope the ABAP team can improve it in next releases.
Example: the parameter types are all enumerations from the ZCALENDAR class:
thanksgiving = zcalendar=>get_date( year = '2016' month = november day = thursday month_week = fourth ).
“compiler should be able to locate it automatically in the class pool”
How???
Two different types. How should the compiler know which one you mean?
But OK, I get the idea, you want a short form
If a parameter is typed with an enum of the same class, always put implicitly cls=> in front of the actual parameter. Let's see, what the ABAP team says ...
As a data object of type enumeration can only be assigned a member of this enumeration, the compiler should also do the same with a parameter of type enumeration. It means that the compiler should not locate the types as usual based on names and scope, i.e. the type can only be the type of the parameter.
Your example in “correct” Syntax:
For the time being, the last line gives a syntax error, because the program global constant thursday is not compatible to the class constant thursday. You have to write
or
You want an automatic zcalendar=> in front of thursday.
Now let me give you a counter-example (not very realistic, but how should the compiler know?)
Agreed. I understand the dilemma now 🙂
But the compiler is able to take decisions if several symbols have the same names (local versus global scopes or class visibility).
Couldn't it decide that it may select the enumeration if there's no local data object with that name (I guess the rule should be "local data object has priority over enumeration" so that to keep ascending compatibility) ?
Well, yes it could. But it would open another trap (what is "local"?). Introducing "local" variables later on that by chance have the same name as an enumeration constant could lead to syntax or even runtime errors.
The problem of specifying (long) class names in front of static components is not restricted to enumerations anyhow. A general solution could be to introduce explicit aliases for class/Interface names (or to work with objects).
As I'd really like the enumeration members to be extended to parameter arguments, I'm trying to propose some possible rules here. Anyway, it seems not to be in the plans, so let's forget it... Thank you very much for your time and argumented clarifications! 🙂
Hi Horst,
Its really amazing stuff. But I'm facing below error while using it in ADT.
SAP_ABA 75A Cross-Application Component
Regards,
Prashant Sharma.
Seems that you’re not on 7.51. Does the F1 help describe enums?
Hello Horst,
awesome blog with great explanation of the concept. Just went through your latest blogs and learned so many new things! Thanks so much!
I just wanted to add, that maybe it’s worth to mention that the conversion back into the enum type is also possible with CX_SY_CONVERSION_NO_ENUM_VALUE being raised in case the input has no suitable enum value assigned. I found the need for this in case a component needs to work with externally defined configuration input (e.g. DB table, JSON/Text Files etc.) and the enum type.
Best regards,
Stefan
Yep, that’s documented under Enumerated Objects as follows:
… a valid enumerated value can be converted to an enumerated object:
The argument dobj is converted to the base type of the enumerated type enum_type and CONV returns an enumerated object with this value. Any invalid values raises an exception.
And in full under CONV - Conversion of Enumerated Types
I also added it to the blog now, thx for pointing it out.
Horst
I've just had a thought.
If the ideal end state is a syntax error if a variable - for example - is typed as TRVOG which has a domain, and in my program I try to assign an invalid value e.g. "H" which is not in the domain.
Even in 7.51 this has not yet been implemented, but was mentioned above as a "killer feature". Indeed I have seen problems caused by spelling mistakes, assigning nonsense values to variables, then passing them into BAPIS, and the whole thing falls over. it happened to me last week
While we are blue skying, why not have such a check on domains with value tables as well?
I am going to add to my (incredibly long) "things to look into" list, the idea of creating some sort of code inspector check, to look for precisely this sort of thing. The overhead might well be too high.
I understand the aversion to putting literals in code. The "fat finger" syndrome will almost always end in tears.....
Any chance of this happening ?
Problem:
The simple names
“false” and “true”
are not allowed.
Simple names are already used.
You need something clumsy as:
or as:
I just now got what the structure addition does...
How about this?
That is a brilliant way of enforcing development time checks for forms and method calls, where you are passing things through rather than numbers. I wish this had appeared earlier as I can see lot of uses for that kind of check.
It is also a cool way of dealing with constants.
This works fine:-
TYPES: brain_size2 TYPE c LENGTH 8,
BEGIN OF ENUM monster_brain_size2 BASE TYPE brain_size2,
normal2 VALUE IS INITIAL,
small2 VALUE ‘SMALL’,
micro2 VALUE ‘MICRO’,
END OF ENUM monster_brain_size2.
DATA(brain2) = NEW monster_brain_size2( small2 ).
But if I declare the base type as longer than 8 characters I get a syntax error.
Yet domains can have values longer than 8 characters. You probably would not want long domain names, but if it is possible someone would have done it.
A I doing something wrong or is this limitation intentional?
Cheersy Cheers
Paul
https://help.sap.com/http.svc/rc/abapdocu_752_index_htm/7.52/en-US/index.htm?file=abaptypes_enum.htm -> Addition 2
OK it is deliberate - maximum length 8 characters.
This is probably a crazy question - which you may not be able to answer - but is there any logic behind this decision?
As I said I personally never have a domain with a really long value, but if it is possible someone will have done it.
I am betting the answer will be "technical reasons" as in the cast iron truth I kept hearing when I was fourteen that was "text compression will never be able to reduce the memory size of a file by more than 50% for technical reasons".
The point is, that for enumerations the value itself doesn't has a meaning. Can't be compared directly with fixed values for domains.
I cannot correct the above comment o get rid of the nonsens before the code ... SCN will not let me....
I removed the nonsense and herewith the evidence that there was nonsense 🙂
Hi !
I wanted to use an enum type in one of my programs, and when I try to run an ATC check, I get these errors:
And in ATC Cockpit, it seems there is nothing to configure Enum types naming.
I didn’t find any help about this matter, nor SAP Notes, can you tell me what’s wrong with it?
Thank you.