Skip to Content
Author's profile photo Horst Keller

ABAP News for Release 7.40 – Constructor Operators CONV and CAST

With Release 7.40 ABAP supports so called constructor operators. Constructor operators are used in constructor expressions to create a result that can be used at operand positions. The syntax for constructor expressions is

… operator type( … ) …

operator is a constructor operator. type is either the explicit name of a data type or the character #. With # the data type can be dreived from the operand position if the operand type is statically known. Inside the parentheses specific parameters can be specified.

Conversion Operator CONV

The conversion operator CONV is a constructor operator that converts a value into the type specified in type.

… CONV dtype|#( … ) …

You use CONV  where you needed helper variables before in order to achieve a requested data type.

Example for parameter passing

Method cl_abap_codepage=>convert_to expects a string but you want to convert a text field.

Before release 7.40

DATA text TYPE c LENGTH 255.

DATA helper TYPE string.

DATA xstr   TYPE xstring.

helper = text.

xstr = cl_abap_codepage=>convert_to( source = helper ).

With release 7.40

DATA text TYPE c LENGTH 255.

DATA(xstr) = cl_abap_codepage=>convert_to( source = CONV string( text ) ).

In such cases it is even simpler to write

DATA text TYPE c LENGTH 255.

DATA(xstr) = cl_abap_codepage=>convert_to( source = CONV #( text ) ).

Example for influencing a calculation

IF 1 / 3 > 0.

  …

ENDIF. 

is false, but

IF CONV decfloat34( 1 / 3 ) > 0.

  …

ENDIF.

is true!

Example for influencing a comparison

The infamous

 

IF ‘ ‘ = ` `.

  …

ENDIF.

is false. But

IF ‘ ‘ = CONV char1( ` ` ).

  …

ENDIF.

is true!

Casting Operator CAST

The casting operator CAST is a constructor operator that executes an up or down cast for reference varaibles with the type specified in type.

… CAST dtype|class|interface|#( … ) …

  • You use CAST for a down cast where you needed helper variables before in order to cast with ?= to a requested reference type.
  • You use CAST for an up cast, e,g, with an inline declaration, in order to construct a more general type.

You can write a compnent selector -> directly behind CAST type( … ).

 

Example from RTTI

Common example where a down cast is needed.

Before release 7.40

DATA structdescr TYPE REF TO cl_abap_structdescr.
structdescr ?= cl_abap_typedescr=>describe_by_name( ‘T100’ ).

DATA components  TYPE abap_compdescr_tab.

components = structdescr->components.

With release 7.40

 

DATA(components) = CAST cl_abap_structdescr(

  cl_abap_typedescr=>describe_by_name( ‘T100’ ) )->components.

Example with up cast

The static type of the reference variable iref declared inline should be the interface not the class.

INTERFACE if.
  …
ENDINTERFACE.

CLASS cl DEFINITION CREATE PRIVATE.
  PUBLIC SECTION.
    INTERFACES if.
    CLASS-METHODS factory RETURNING value(ref) TYPE REF TO cl.
    …
ENDCLASS.

CLASS cl IMPLEMENTATION.
  METHOD factory.
    ref = NEW #( ).
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  DATA(iref) = CAST if( cl=>factory( ) ).

Example with data objects

A constructor expression with CAST followed by -> is an LHS-expression, you can assign values to it.

TYPES: BEGIN OF t_struc,
        col1 TYPE i,
        col2 TYPE i,
       END OF t_struc.

DATA dref  TYPE REF TO data.
DATA struc TYPE t_struc.

dref = NEW t_struc( ).

CAST t_struc( dref )->col1 = struccol1.

Assigned Tags

      50 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      While you're blogging about all the nice new features in ABAP 7.40 - is there any chance you could smuggle in a `... IS INSTANCE OF ...` operator? As I've blogged some time ago, this is one small change (at least from the outside) that would really help a lot...

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      I can ask the developers about that.

      For the time being I myself also work like you have described it in your blog (using CAST from 7.40 on).

      TRY.
          CAST class( oref ).
          ...
        CATCH cx_sy_move_cast_error.
      ENDTRY.

      Author's profile photo Former Member
      Former Member

      Tbh i was coding a (super)class yesterday & share Volker's desperation for IS INSTANCE OF 😉 There is no simple way of doing this in ABAP, sigh 🙁

      Horst Keller - Judging by the looks of it, i can see the demise of helper variables. Btw one thing came to my mind (in fact i had this in the back of my mind for sometime now, basically since i started chaining my methods 🙂 )

      We have a functional method:

      go_animal=>get_instance->get_no_of_legs( )

      Suppose i have to call this method multiple times in my method (for some weird reason), what do we suggest we should do -

      1. Call this chained statement everytime, or
      2. Declare a helper variable & use it?

      BR,

      Suhas

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author
      1. Call this chained statement everytime, or
      2. Declare a helper variable & use it?

      The recommendation is absolutely clear for such cases:

      2. Declare a helper variable & use it

      Unfortunately the compiler does not recognize and buffer such intermediate results.

      Use expressions to:

      • make source code better readable
      • but avoid
        • obfuscation
        • performance leaks
        • less maintainability (also for debugging it can be wise to awitch in one or the other helper variable)
      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author
      Author's profile photo Former Member
      Former Member

      Unfortunately the compiler does not recognize and buffer such intermediate results.

      I was wondering if the Kernel was smart enough to buffer the results 😛

      I generally refer to the ABAP Programming guidelines (http://help.sap.com/abapdocu_731/en/abenabap_pgl.htm), in fact this 1 liner is a gem :

      Beauty is in the eye of the beholder

      - Suhas

      Author's profile photo Former Member
      Former Member

      Suhas Saha wrote:

                             

      Unfortunately the compiler does not recognize and buffer such intermediate results.

      I was wondering if the Kernel was smart enough to buffer the results 😛

      It probably will never be because it can't determine whether the return value might have changed. Think, for example, of an iterator, where invoking the next() method will actually change the state of the iterator so that consecutive calls of next() always return a different result - you wouldn't want the kernel to buffer that, would you?

      Suhas Saha wrote:

                             

      Beauty is in the eye of the beholder

                         

      Doesn't that hurt? 🙂

      Author's profile photo Former Member
      Former Member

      Darn!!!!

      Should have remembered about the iterator before commenting, my bad! 😐

      Horst Keller - What prompted you to quote John Keats in ABAP Keyword documentation? #needtoknow 😉

      Cheers,

      Suhas

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Did I?

      Author's profile photo Former Member
      Former Member

      Sorry, it's not Keats.

      Beauty is in the eye of the beholder

      It's right there at the top of the ABAP programming guidelines 😛 http://help.sap.com/abapdocu_731/en/abenabap_pgl.htm

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      It was the SAP-internal motto for the project that resulted in the ABAP PGLs.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      PS: The correct answer of thread Object problem can be rewritten as follows in release 7.40:

      DATA oref TYPE REF TO object.

      oref = NEW some_class( ).

      IF CAST cl_abap_classdescr(
           cl_abap_typedescr=>describe_by_name( 'some_class' )
             )->applies_to( oref ) = 'X'.
        ...
      ENDIF.

      At least one expression without helper variables ...

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      I asked, and the answer goes as as follows:

      http://www.javapractices.com/topic/TopicAction.do?Id=31

      😀

      Author's profile photo Former Member
      Former Member

      Does that mean that just because some people don't know how to use a language construct it's not going to be implemented? I can think of tons of ways to create bad examples for all the additions you blogged about. In contrast, there are valid uses of an 'instance of' operator - "if the class has implemented an interface to support some special handling, call the method of that interface, else use a generic method". You don't always have the option of changing the inheritance structure unless your language supports multiple inheritance - which C++ does, but neither Java nor ABAP do. So that's not much of an answer, to be honest.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Well, it's the opinion of the colleagues who design and implement all that stuff. I myself have use cases for INSTANCE OF too (especially in connection with RTTI) and I also use

      TRY.
          CAST
      class( oref ).
         
      ...
       
      CATCH cx_sy_move_cast_error.

      ENDTRY.

      Author's profile photo Former Member
      Former Member

      IF CONV decfloat34( 1 / 3 ) > 0.

        ...

      ENDIF.

      is true!

      I would have expected that the integer division happens first and the resulting integer zero is then converted to float.

      I guess my expectation is even more evident if I add some brackets:

      data(a) = conv decfloat34( ( 1 / 3 ) ).

      But a will be 0.33333..

      Could you explain this behavior to me please?

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Bernhard,

      In ABAP, arithmetic calculations have a calculation type that is derived not only from the operands at the RHS but also from the result type (LHS). The result type in your case is decfloat34 and therefore, the calculation is carried out in decfloat34.

      See also Calculation Type, where the observed behavior is explained.

      Author's profile photo Former Member
      Former Member

      Thanks for the infos.

      Do you know how to get the CONV to work with a CHANGING parameter?

      the example here

      ABAP Keyword Documentation

      works for importing but not changing

      e.g. I cannot activate the * commented lines below - see Syntax-Error

      >>

      class lcl_conv1 definition.
         public section.
           types tt_sta
             type standard table of scarr with key mandt carrid.
           methods import
             importing
               !II type LCL_CONV1=>TT_STA
             changing
               !CI type LCL_CONV1=>TT_STA optional
          .
         private section.
           methods test.
      endclass. " lcl_conv1 definition.
      class lcl_conv1 implementation.
         method IMPORT.
         endmethod. " IMPORT.
         method TEST.
           data li type sorted table of scarr with unique key mandt carrid.
           me->IMPORT( conv #( li ) ).
           me->IMPORT( exporting II = conv #( li ) ).
      *    me->IMPORT(
      *      exporting
      *        II = conv #( li )
      *      changing
      *        CI = conv #( li ) "Syntax-Error: Unexpected operator "CONV"
      *    ).
         endmethod. " TEST.
      endclass. " lcl_conv1 implementation.

      <<

      TIA

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Let me play the senior teacher here: 😈

      How do you think could any expression work as an actual parameter for CHANGING?

      Hint: Why can't you use expressions for EXPORTING/RETURNING parameters or use them as target fields of any assignments?

      Author's profile photo Former Member
      Former Member

      Actually, I'm whining about having to always copy my internal tables to a standard table just to display them, because salv takes a standard table only;- so I thought CONV would be a relief for that:

      >>

      class lcl_conv2 definition.
         public section.
           types tt_sta
             type standard table of scarr with key mandt carrid.
           methods show
             changing
               !CI type LCL_CONV2=>TT_STA
           .
           methods test.
      endclass. " lcl_conv2 definition.
      class lcl_conv2 implementation.
         method show.
           data lo type ref to CL_SALV_TABLE.
           cl_salv_table=>FACTORY(
             importing
               R_SALV_TABLE = lo
             changing
               t_table      = CI
           ).
           lo->DISPLAY( ).
         endmethod. " show.
         method TEST.
           data li type sorted table of scarr with unique key mandt carrid.
           data li_helper type LCL_CONV2=>TT_STA.

           select * from scarr into table li.
           li_helper = li.
           me->SHOW( changing CI = li_helper ).
         endmethod.
      endclass. " lcl_conv2 implementation.
      <<

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Well, you can never write to an expression (with some exceptions).

      An expression returns a temporary result that can be used at the operand position, but not further. An actual parameter for CHANGING clearly is a write position. The changed parameter cannot be returned to the expression. You wouldn't write meth( CHANGING para = a + b ) either.  Only some expressions are wirtable expressions: variants of NEW, CAST, and table expressions. Those can be used at some few write positions, but not with CHANGING.

      Therefore, your problem cannot be solved by the compiler. I myself did never understand why the SALV classes do not accept any table type and why it is a CHANGING and not an IMPORTING parameter. But these classes are not  part of ABAP language,.

      Author's profile photo Former Member
      Former Member

      yes yes yes.

      I was hoping CONV would do something it doesn't.

      I fully understand your point on Expressions,

      Thanks much for your insights.

      I guess I have an explanation for your "question" on SALV:

      Class CL_SALV_TABLE has its method "FACTORY" with changing parameter t_table typed as "TYPE TABLE";

      (i.e. standard table)

      it then passes this to method "r_salv_table->set_data()" via parameter t_table typed as "TYPE STANDARD TABLE";

      this method contains: "get reference of t_table into me->r_table"

      where "me->r_table" is typed "Type Ref To DATA"

      Class CL_GUI_ALV_GRID has its method "SET_TABLE_FOR_FIRST_DISPLAY"

      with parameter IT_OUTTAB typed as "TYPE STANDARD TABLE";

      and this method does a "get reference of it_outtab into mt_outtab."

      where mt_outtab is typed "Type Ref To DATA"

      So these both eventually pass into variables that would take any table.

      BUT, checking for usage of e.g. the ladder mt_outtab, this gives e.g.:

      Class CL_GUI_ALV_GRID with method "APPLY_FILTER":

      This method contains: "assign mt_outtab->* to <tab1>." where <tab1> is typed "type standard table."

      This calls function module "LVC_FILTER_APPLY" which has parameter tables "it_data" which is typed "TABLE"

      (i.e. standard table)

      and so on...

      So this would required re-typing all these and more usages.

      But there is more:

      Hashed tables do not administrate sy-tabix within a Loop.

      e.g. look at: "form filt_conv_fcat_to_lvcfilter"

      in function group: SLVC_DIALOG

      (include = LSLVC_DIALOGF18)

      It contains:

      >>

          loop at t_data[] into t_data.

            if sy-tabix = 1.

      <<

      where t_data is "tables t_data type table"

      Now, if t_date was "any table", and then if we pass a hashed table, then sy-tabix would always be 0.

      Like for example here:

      sy-tabix is 0 (it's not a bug, it's a feature?)

      >>

      form z_hashed_sy_tabix.

        data li type hashed table of scarr with unique key mandt carrid.

        data li2 type sorted table of scarr with unique key mandt carrid.

        field-symbols <lfs> like line of li.

        select * from scarr into table li.

        sort li by mandt carrid.

        sy-tabix = -1.

        LOOP at li assigning <lfs>.

          write: /'sy-tabix=', (2) sy-tabix, <lfs>-CARRID.

        ENDLOOP.

      endform. " z_hashed_sy_tabix.

      <<

      So "sy-tabix = 1" cannot be used to find the first line with a hashed table.

      Yet, even if the typing was merely changed to "index table",

      that would allow for standard AND sorted tables.

      http://help.sap.com/saphelp_nw2004s/helpdata/en/fc/eb366d358411d1829f0000e829fbfe/content.htm

      As things are, I'll keep copying my tables;

      at least this does NOT copy the body of the tables, because copy-on-write happens (I guess)

      http://help.sap.com/saphelp_snc700_ehp02/helpdata/en/88/84fb5269d34838a1f119b41dcdbc57/content.htm

      So "only" a table header needs to be created (?)

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      because copy-on-write happens (I guess)

      see table sharing

      Table sharing only occurs between tables of the same category

      Author's profile photo Clemens Li
      Clemens Li

      Hi Armin,

      for me this is a good example of unreadable code.

      data li

      data li2

      field-symbols <lfs> like line of li.

      If you do not use meaningful names for IDs here, where do you?

      Regards

      Clemens

      Author's profile photo Clemens Li
      Clemens Li

      Great work! Nice features!

      Where will I find these articles the day my customer uses 740? If I understand right, some of the features have been introduced with different service packs of 740. Is there an overview for this?

      Thank you, I enjoy reading the articles and the discussion - really encouraging!

      And: "Beauty Is Not in the Eye of the Beholder. Beauty Is All Around Us, Contained in Nature!"

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Is there an overview for this?

      See the News in the ABAP Documentation.

      Author's profile photo Ralf Wenzel
      Ralf Wenzel

      Seems, that CONV does not work in CONCATENATE:

      data: stringfield type string.

      concatenate conv string( sy-tabix ) 'anythingelse' into stringfield.

      Could you tell me, why?

      Author's profile photo Matthew Billingham
      Matthew Billingham

      stringfield = CONV string( sy-tabix ) && 'anythingelse.' works, however. (As does   stringfield = sy-tabix && 'anythingelse'.)


      You still use CONCATENATE? :-O

      Author's profile photo Ralf Wenzel
      Ralf Wenzel

      Yes, I did - until now. 😉 Thanks!

      Author's profile photo Ralf Wenzel
      Ralf Wenzel

      Additonal Question: stringfield = sy-tabix && 'anythingelse' results in an output without a space (15anythingelse) - there is no pendant of "separated by...."?

      Author's profile photo Matthew Billingham
      Matthew Billingham

      stringfield = sy-tabix && | | && 'anythingelse'.

      Of course, only use | delimiter for character data that shouldn't be translatable.

      Author's profile photo Ralf Wenzel
      Ralf Wenzel

      Does not work

      Author's profile photo Clemens Li
      Clemens Li

      are you sure? Shouldn't it be

      |sy-tabix| && 'anythingelse'

      You need the space?

      ` anythingelse` should do.

      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      I concur.

      Note && is not required: |{ sy-tabix } anythingelse|

      Author's profile photo Matthew Billingham
      Matthew Billingham

      No

      |sy-tabix| will give you the string literal sy-tabix

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      As Jacques has shown, you use curly brackets to embed ABAP data objects or expressions into string templates. |{ sy-tabix }| converts the numeric contents of sy-tabix to string. |{ ... } { ... }| concatenates the contents of the expressions in the brackets separated by space.

      Author's profile photo Matthew Billingham
      Matthew Billingham

      Thanks. Learning every day.

      Author's profile photo Ralf Wenzel
      Ralf Wenzel

      After reading a few answers to my question, I asked myself, why the godfather of ABAP (TM) himself does not answer. Thanks for helping me!

      Perhaps it's time for an updated ABAP Reference Book @galileo

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      godfather of ABAP (TM)

      Who is TM?

      Perhaps it's time for an updated ABAP Reference Book @galileo

      Arrgh, I'm pushing the deadlines of the new book again and again and really feel very bad about it (only a few chapters are finished), no reference bokk (that you find online) but a handbook ...

      Author's profile photo Matthew Billingham
      Matthew Billingham

      Ok guys. Now's the time to pile on the guilt and pressure. 😉

      TM = = Trademark.

      Author's profile photo Ralf Wenzel
      Ralf Wenzel

      "TM" is also used without a legal context: "The term trademark is also used informally to refer to any distinguishing attribute by which an individual is readily identified, such as the well-known characteristics of celebrities." (Trademark - Wikipedia, the free encyclopedia). Or in german: "Der Inbegriff"

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      The individual  readily identified was here

      /wp-content/uploads/2014/11/argent_584636.jpg

      Absolutely no ABAP for 15 days ...

      Author's profile photo Former Member
      Former Member

      Sehr schön 😛

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Could you tell me, why?

      See Matthew's answer. Expressions and new functions are supported mainly in expressions, not in old style ABAP.

      Author's profile photo Former Member
      Former Member

      Hi Horst,

      given following example of the CAST operator:

      TYPES t_c_big TYPE c LENGTH 262143.
      DATA lv_char1 TYPE char1 VALUE '@'.
      DATA lr_data_1 TYPE REF TO data.
      GET REFERENCE OF lv_char1 INTO lr_data_1.
      DATA(lr_data_2) = CAST t_c_big( lr_data_1 ).

      Why do I get access to foreign memory in LR_DATA_2 after the first character? Is this a bug in the CAST operator?

      I would have expected an exception due to some kind of memory check.

      Kernel: 742 PL#200
      SAP_BASIS: SAPKB74011

      Thank you in advance!

      Best regards,

      Sebastian

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Now, that doesn't look good 😯 .

      According to the documentation the down cast should not be possible but lead to an exception CX_SY_MOVE_CAST_ERROR.

      It is not the CAST operator alone, but also the ?= operator behaves wrongly:

      DATA lr_data_3 TYPE REF TO t_c_big.
      lr_data_3 ?= lr_data_1.

      I tested in 7.40, SP08 and 7.50 and as you said, there is no exception and after assigning to a field symbol there is access to memory outside the allowed limits.

      Only in our internal 7.63 system I get at least a runtime error CAST_INTERNAL_ERROR, which also shouldn't occur, but of course the CX_SY_MOVE_CAST_ERROR.

      I forward to development. Thanks for notifying!

      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      Hello Horst,

      dereferencing a CASTed object attribute seems to add an implicit conversion, or what is happening here?

      REPORT zz_cast_issue.
      * Tested on Netweaver 7.51
      TYPES tv_real TYPE decfloat34.  " real data type
      
      CLASS lcl_real DEFINITION.
        PUBLIC SECTION.
          METHODS constructor IMPORTING iv_real TYPE tv_real.
          METHODS to_string RETURNING VALUE(rv_str) TYPE string.
        PRIVATE SECTION.
          DATA real TYPE tv_real.
      ENDCLASS.
      
      CLASS lcl_real IMPLEMENTATION.
      
        METHOD constructor.
          real = iv_real.
        ENDMETHOD.
      
        METHOD to_string.
          DATA lo_real TYPE REF TO lcl_real.
      *    rv_str = condense( real ).  " <--- Error - real must be a character-like data object (expected)
          rv_str = condense( CAST lcl_real( me )->real ). " works (not expected) ??
        ENDMETHOD.
      
      ENDCLASS.
      
      START-OF-SELECTION.
        WRITE NEW lcl_real( '2.423' )->to_string( ).

      JNN

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

       

      To make a long thing short:

      DATA(str1) = condense( CONV decfloat34( '1' ) ).
      
      DATA decf TYPE decfloat34.
      DATA(str2) = condense( decf ). "Syntax error

      One of the many peculiarities of our good ol' ABAP language.

      As a data object, the operand must be character like (character-like data types or date types and time types, structures with flat-only character-like components),

      As an expression it is enough to be convertible.

       

      Author's profile photo B@lu .
      B@lu .

      Can't we use CONV #( ) constructor for passing parameters while calling Function Modules?

      because i am getting below error while calling FM

      regards,

      B@lu.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Please note that a function module call other than a method call is always dynamic. You specify the function module as a character field and not as a direct operator. Using a literal is kind of static but not for the compiler. It is evaluated a runtime only. Only the extended program check and the where-used list evaluate the literals.