Skip to Content

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.

To report this post you need to login first.

46 Comments

You must be Logged on to comment or reply to a post.

    1. Horst Keller 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.

      (0) 
      1. Suhas Saha

        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

        (0) 
        1. Horst Keller 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)
          (0) 
            1. Volker Wegert

              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? 🙂

              (0) 
              1. Suhas Saha

                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

                (0) 
      2. Horst Keller 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 …

        (0) 
      1. Volker Wegert

        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.

        (0) 
        1. Horst Keller 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.

          (0) 
  1. Bernhard Klefer

    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?

    (0) 
    1. Horst Keller 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.

      (0) 
  2. Armin Schmitt

    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

    (0) 
    1. Horst Keller 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?

      (0) 
      1. Armin Schmitt

        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.
        <<

        (0) 
        1. Horst Keller 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,.

          (0) 
          1. Armin Schmitt

            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 (?)

            (0) 
        2. 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

          (0) 
  3. 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!”

    (0) 
  4. 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?

    (0) 
    1. Matthew Billingham

      stringfield = CONV string( sytabix ) && ‘anythingelse.’ works, however. (As does   stringfield = sytabix && ‘anythingelse’.)


      You still use CONCATENATE? :-O

      (0) 
      1. Ralf Wenzel

        Additonal Question: stringfield = sy-tabix && ‘anythingelse’ results in an output without a space (15anythingelse) – there is no pendant of “separated by….”?

        (0) 
            1. Horst Keller 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.

              (0) 
              1. 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

                (0) 
                1. Horst Keller 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 …

                  (0) 
    2. Horst Keller 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.

      (0) 
  5. Sebastian Zeller

    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

    (0) 
    1. Horst Keller 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!

      (0) 

Leave a Reply