Skip to Content
Author's profile photo Horst Keller

ABAP News for Release 7.40 – Constructor Operator VALUE

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.

Value Operator VALUE

The value operator VALUE is a constructor operator that constructs a value for the type specified with type.

  • … VALUE dtype|#( ) …

    

constructs an initial value for any data type.

 

  • … VALUE dtype|#( comp1 = a1 comp2 = a2 … ) …

constructs a structure where for each component a value can be assigned.

  • … VALUE dtype|#( ( … ) ( … ) … ) …

constructs an internal table, where for each line a value can be assigned. Inside inner parentheses you can use the syntax for structures but not the syntax for table lines directly. But you can nest VALUE operators.

Note that you cannot construct elementary values (which is possible with instantiation operator NEW) – simply because there is no need for it.

For internal tables with a structured line type there is a short form that allows you to fill columns with the same value in subsequent lines

VALUE dtype|#( col1 = dobj11 … ( col2 = dobj12 col3 = dobj13 … )
                                 ( col2 = dobj22 col3 = dobj23 … )
                                   …
               col1 = dobj31 col2 = dobj32 … ( col3 = dobj33 … )
                                               ( col3 = dobj43 … )
               … ).

Example for initial values

Why would you like to construct an initial value anyhow? Well, you can pass an initial actual parameter to a structured or tabular formal parameter without the need of an initial hleper variable now.

CLASS c1 DEFINITION.
  PUBLIC SECTION.
    TYPES: BEGIN OF t_struct,
             col1 TYPE i,
             col2 TYPE i,
           END OF t_struct.
    CLASS-METHODS m1 IMPORTING p TYPE t_struct.
ENDCLASS.

CLASS c1 IMPLEMENTATION.
  METHOD m1.
    …
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  c1=>m1( VALUE #( ) ).

Example for structures

Three different ways to construct the same nested structure:

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

TYPES: BEGIN OF t_struct,
         col1 TYPE i,
         col2 TYPE t_col2,
       END OF t_struct.

DATA: struct TYPE t_struct,
      col2 TYPE t_col2.

“1
struct = VALUE t_struct( col1 = 1
                         col2-col1 = 1
                         col2-col2 = 2 ).

“2

col2   = VALUE   t_col2( col1 = 1
                         col2 = 2 ).
struct = VALUE t_struct( col1 = 1
                         col2 = col2 ).

“3

struct = VALUE t_struct( col1 = 1
                         col2 = VALUE #( col1 = 1
                                         col2 = 2 ) ).

Examples for internal tables

Elementary line type:

TYPES t_itab TYPE TABLE OF i WITH EMPTY KEY.

DATA itab TYPE t_itab.

itab = VALUE #( ( ) ( 1 ) ( 2 ) ).

Structured line type (RANGES table):

DATA itab TYPE RANGE OF i.

itab = VALUE #( sign = ‘I’  option = ‘BT’ ( low = 1  high = 10 )
                                          ( low = 21 high = 30 )
                                          ( low = 41 high = 50 )
                            option = ‘GE’ ( low = 61 )  ).

Other expressions in VALUE operator

Of course, the arguments of VALUE can be expressions or function calls:

 

TYPES t_date_tab TYPE TABLE OF string  WITH EMPTY KEY.

DATA(date_tab) = VALUE t_date_tab(
  ( |{ CONV d( sy-datlo – 1 ) DATE = ENVIRONMENT }| )
  ( |{         sy-datlo       DATE = ENVIRONMENT }| )
  ( |{ CONV d( sy-datlo + 1 ) DATE = ENVIRONMENT }| ) ).

So you can do a lot of crazy things now, but be aware of obfuscation …

Assigned Tags

      59 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Katan Patel
      Katan Patel

      Really handy little feature.  Thanks for sharing that.  I'll be looking to use that to reduce some of the coding for my local class data.  Also liking the fact we can use expressions for the assignment. 

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Yes, best ABAP ever!!

      Now we have to get rid of the blanks in between the brackets and we'll become the best friends 😉 (cc Hendrik Neumann )

      Author's profile photo Former Member
      Former Member

      I don't believe this will ever happen - it would break every single character operation using offsets and brackets...

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Do you have an example where this could be a problem?

      Author's profile photo Former Member
      Former Member

      Can do:

      var = gr_foo->bar(baz).

      will try to find a public attribute named bar and transfer the first baz characters into var.

      var = gr_foo->bar( baz )

      will call a method named bar and transfer baz as a parameter.

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      As it's not possible to define a method with the same name like an attribute, the compiler should know what to do.

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

      CLASS class DEFINITION.
        PUBLIC SECTION.
          METHODS main.
          METHODS meth IMPORTING p1 TYPE data
                  RETURNING VALUE(r) TYPE string.
      ENDCLASS.

      CLASS class IMPLEMENTATION.
        METHOD main.
          DATA meth TYPE string.
          DATA res  TYPE string.

          res = meth(2).    "Offset/Length

          res = meth( 2 )"Method Call

        ENDMETHOD.
        METHOD meth.
        ENDMETHOD.
      ENDCLASS.

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Damned, I've forgot the local vars. Thank you.

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

      And the global vars 😉

      DATA meth TYPE string.

      CLASS class DEFINITION.
        PUBLIC SECTION.
          METHODS main.
          METHODS meth IMPORTING p1 TYPE data
                  RETURNING VALUE(r) TYPE string.
      ENDCLASS.

      CLASS class IMPLEMENTATION.
        METHOD main.
          DATA res  TYPE string.

          res = meth(2).    "Offset/Length

          res = meth( 2 )"Method Call

        ENDMETHOD.
        METHOD meth.
        ENDMETHOD.
      ENDCLASS.

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      You know, nobody is using global variables anymore... 😈

      Author's profile photo Former Member
      Former Member

      Uwe Fetzer wrote:

                             

      You know, nobody is using global variables anymore... 😈

                         

      Yeah, in Utopia 😛

      Author's profile photo Former Member
      Former Member

      Assuming that the ABAP compiler works like other compilers do: It can't, because checking whether a method or variable exists is part of the linking process, and the buildup of the AST and the symbol tables happens way before that. If someone is interested in this, I might hack together a small blog article about this...

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Interesting question. But maybe it can be solved because the ABAP compiler is a Multi Pass Compiler since 7.02.

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

      In fact, we have the problem for inline declarations. It is solved by the following rule:

      If a field named "data" is already declared in a context, the syntax "data(...)" at an operand position is not an inline declaration but an offset length access to "data". Only if "data" is not yet declared, the syntax "data(data)" declares "data".

      😥

      Author's profile photo Hendrik Neumann
      Hendrik Neumann

      Let's just say: get rid of the mandatory blanks in between the brackets.. and while we're at it I would love to see the mandatory blanks surrounding assigments gone as well 😉 Something like this lv_number=  5.  is just more expressive than lv_number = 5. Did see that first used by Kent Beck and liked it right away...

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

      Unfortunately, in non-Unicode programs variable names can contain symbols 🙁 .

      Still have to support non-Unicode programs.

      Author's profile photo Former Member
      Former Member

      Hello Horst,

      Finally we have upgraded the ABAP Kernel to 740 & i have already started to get my hands dirty.

      I am using your examples as reference to my learning. Is there any guideline to using the concrete datatype(dtype) or # while using VALUE operator?

      For e.g., i can re-write your code as

      struct = VALUE #( col1 = 1
                         col2 = VALUE #( col1 = 1
                                         col2 = 2 )
                       ).


      What are your suggestions?


      BR,

      Suhas

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

      Hi Suhas,

      The syntax of all constructor expressions is:

      ... operator type(  ... ) ...

      where operator is NEW, VALUE, CONV,  etc. and type specifies the data type of the return value.

      For type you can either specify the name dtype of a concrete data type or #. With # you let the compiler deduce the appropriate data type for the operand position (operand type) where the constructor expression is used. This is appropriate in most cases and relieves you from finding and typing the name of the type yourself. Typical example: a method meth expects a structured input parameter of type mystruct. When calling the method you can write

      meth( value #( col1 = ... col2 = ... )  )

      The compiler implicitly replaces # by mystruct. You could also write

      meth( value mystruct( col1 = ... col2 = ... )  )

      but that is not necessary here. So, you always use #, if you want to use the operand type and it can be deduced by the compiler.

      You use the explicit type, if you want to override the implicit operand type (normally not a use case), if you want to make your coding more clear by expressing the type explicitly, or if the compiler cannot deduce the operand type and you simply cannot use #. Example:

      DATA(struct) = mystruct( col1 = ... col2 = ... ).

      Here you must tell the compiler what type of structure you want to construct. If struct is already declared, you can use #:

      struct = #( col1 = ... col2 = ... ).

      Regards

      Horst

      Author's profile photo Former Member
      Former Member

      Thanks for your reply

      if you want to make your coding more clear by expressing the type explicitly

      This is what i wanted to know, I think using # may lead to obfuscation especially when passing it to procedures 😐

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

      It depends also on the operator.

      For CONV,  # is exactly what you need in most cases.

      Before:

      DATA text TYPE c LENGTH 255.

      ...

      DATA helper TYPE string.

      helper = text.

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

      After:

      DATA text TYPE c LENGTH 255.

      ...

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

      I don't need to know what the type is and if the interface of the method is changed, your code has a good chance to survive.

      Author's profile photo Former Member
      Former Member

      I don't need to know what the type is and if the interface of the method is changed, your code has a good chance to survive.

      Great tip Horst!

      Author's profile photo Adi Sieker
      Adi Sieker

      Hi Horst,

      first of thank you for an absolutely amazing ABAP version. A lot of the feature come naturally and I use them on a daily basis.

      One thing I just tried that isn't working as expected is the following:

      DATA(lv_date) = VALUE dats( '20140929' ).

      I get a syntax error that dats is not a structure.

      I know I can rewrite this as:

      DATA lv_date type dats value '20140929'.

      but is there a way to get the first version working using the new features?

      Regards

          Adi

      Author's profile photo Former Member
      Former Member

      As per the SAP documentation of VALUE, it does -

      • creates initial values for any non-generic data types
      • constructs the content of
      • structured types
      • table types

      Refer - ABAP Keyword Documentation

      BR,

      Suhas

      Author's profile photo Adi Sieker
      Adi Sieker

      Hi Suhas,

      dats is not a generic type IMHO.

      But Horst did give a nice solution in his reply.

      adi

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

      Hi Adi,

      The resaon for the syntax error is, that VALUE does not allow you "construct" elementary types. One might argue "why not?" and in fact I did so often, but up to now this restriction is kept.

      But the gap can simply be closed as follows:

      DATA(lv_date) = CONV dats( '20140929' ).

      Best

      Horst

      Author's profile photo Former Member
      Former Member

      That's a smart workaround Horst 😎

      Anyway was there any reason why it was decided why VALUE cannot be used to build the value of elementary types?

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

      You should construct elementary values only where needed:

      ... NEW elem_type(  elem_value ) ...

      ... VALUE table_type( ... ( elem_value ) ... ) ...

      In all other elementary operand positions you can place the elementary operands directly, no need to construct them. The only use case - conversions - is handled by the dedicated conversion operator CONV. And be aware that you also get a syntax warning, if you use CONV superfluously, as e.g. here:

        DATA int TYPE i.
        int = CONV #( 555 ).

      Another solution would have been to overload VALUE in a way that makes CONV superfluous. But the decision was to offer two distinct operators.

      Author's profile photo Adi Sieker
      Adi Sieker

      Hi Horst,

      thanks that will works like a treat.

      Regards

          Adi

      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      Let us assume I create the following types

      TYPES: BEGIN OF ts_path,

                caller TYPE i,

                called TYPE i,

              END OF ts_path.

      TYPES: BEGIN OF ts_trace,

           id         TYPE satr_de_id,

           path       TYPE ts_path,

           mod        TYPE seocpdname,

         END OF ts_trace.

      With this, the following code compiles

      DATA(ls_call) = VALUE

            ts_trace( id = 'm'

                     path = VALUE #( caller = 3

                                               called = 5 ) ).

      while this does not:

      DATA(ls_call2) = VALUE ts_trace(

           id = 'm'

           path = VALUE #( caller = 3    "<--- Error: Arithmetic calculation not permitted

                                     called = 5 )

           mod = 'MAIN' ).


      Now, is this a bug or a feature ?

      (the work around is to rename the field mod to something.. else).

      regards,

      JNN

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

      Hi Jacques,

      Seems that you are Mr. Bugfinder, No.1.

      Writing it as

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

      TYPES: BEGIN OF struc2,
               col1 TYPE c LENGTH 1,
               col2 TYPE struc1,
               col3 TYPE c LENGTH 10,
             END OF struc2.

      TYPES: BEGIN OF struc3,
               col1 TYPE c LENGTH 1,
               col2 TYPE struc1,
               mod  TYPE c LENGTH 10,
             END OF struc3.

      DATA(ls_call2) = VALUE struc2(
           col1 = 'x'
           col2 = VALUE #( col1 = 3
                           col2 = 5 )
           col3 = 'XXX' ).

      DATA(ls_call3) = VALUE struc3(
           col1 = 'x'
           col2 = VALUE #( col1 = 3    "<--- Error: Arithmetic calculation not permitted
                           col2 = 5 )
           mod = 'XXX' ).

      clearly hints to a bug.

      I forwarded to development.

      Cheers!

      Horst

      B.T.W., replacing mod with div gives the same error.

      Author's profile photo Arshad Ansary
      Arshad Ansary

      Hi Horst,

      Thanks for sharing the new syntax in strcutred manner

      just out of curiosity I did a perfomance analysis of the append . The new syntax was taking thrice time of the old syntax.


      TYPES ty_itab_value TYPE TABLE OF i WITH EMPTY KEY.

      DATA itab_value TYPE ty_itab_value.

      get RUN TIME FIELD DATA(lv_fld1).

      itab_value = VALUE #( ( ) ( 1 ) ( 2 ) ).

      get RUN TIME FIELD DATA(lv_fld2).

      DATA(lv_fld_diff) = lv_fld2 - lv_fld1.

      WRITE: / lv_fld_diff.

      clear:itab_value.

      get RUN TIME FIELD DATA(lv_fld3).

      APPEND 0 to itab_value.

      APPEND 1 to itab_value.

      APPEND 2 to itab_value.

      get RUN TIME FIELD DATA(lv_fld4).

      DATA(lv_fld_diff1) = lv_fld4 - lv_fld3.

      WRITE: / lv_fld_diff1.


      The result was 3:1. Ofcourse this is not a serious test(but without scalable data) . Is there any doc where we have perf impications comapred to older syntax.


      Regards

      Arshad

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Hi Arshad,

      not a serious test


      hehe, you are right 😉


      I've tested it within a loop (DO 10 million TIMES...)  and the ration changed to 4:3. The new syntax is still a bit slower, but we are talking about milliseconds, so not really a problem, isn't it?

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

      With your "test" you can also show the opposite behavior 🙂

      TYPES ty_itab_value TYPE TABLE OF i WITH EMPTY KEY.

      DATA itab_value TYPE ty_itab_value.

      "itab_value = VALUE #( ( ) ( 1 ) ( 2 ) ).

      clear:itab_value.

      get RUN TIME FIELD DATA(lv_fld3).

      APPEND 0 to itab_value.

      APPEND 1 to itab_value.

      APPEND 2 to itab_value.

      get RUN TIME FIELD DATA(lv_fld4).

      DATA(lv_fld_diff1) = lv_fld4 - lv_fld3.

      WRITE: / lv_fld_diff1.

      clear:itab_value.

      get RUN TIME FIELD DATA(lv_fld1).

      itab_value = VALUE #( ( ) ( 1 ) ( 2 ) ).

      get RUN TIME FIELD DATA(lv_fld2).

      DATA(lv_fld_diff) = lv_fld2 - lv_fld1.

      WRITE: / lv_fld_diff.

      You measure the creation of the internal table in your first go that takes more time than filling it.

      If you take away the " above, the internal table is created before both measurements ...

      Author's profile photo Sougata Chatterjee
      Sougata Chatterjee

      Hi Horst,

      Before 7.4 the below code inserted a new line into table itab.

      Start-of-selection.

           my_class=>my_method( changing ct_tab = itab ).

      Method my_method.

           Insert c1=>m1( ) into table ct_tab.               "ct_tab is changing param

      Endmethod.

      Now in 7.4 this code overwrites the content of ct_tab instead of inserting a new line.

      Method my_method.

           ct_tab = VALUE #( ( c1=>m1( ) ) ).

      Endmethod.

      Where:

      Method m1.

           rs_line = ls_line.               "rs_line is returning param

      Endmethod.

      I want to insert a new line into the itab - where am I going wrong?

      Regards,

      Sougata.

      Author's profile photo Former Member
      Former Member

      Method my_method.

           ct_tab = VALUE #( ( c1=>m1( ) ) ).

      Endmethod.

      Aren't you are using the wrong command (VALUE)?

      Author's profile photo Sougata Chatterjee
      Sougata Chatterjee

      I was working with the 7.4 example:

      Before 7.4:

      Data:

          itab type tt,

          wa  like line of itab.

      wa-c1 = 7.

      wa-c2 = 9.

      INSERT wa INTO TABLE itab.

      wa-c1 = 3.

      wa-c2 = 5.

      INSERT wa INTO TABLE itab.

      Instead in 7.4:

           Data(itab) = VALUE tt( ( c1 = 7 c2 = 9 )

                                                ( c1 = 3 c2 = 5 ) ).

      Is it not possible to use the same inside a method instead of INSERT or APPEND?

      Author's profile photo Former Member
      Former Member

      Well,

      VALUE is a constructor and not insert command.

      You may use (... VALUE #( ... ( LINES OF itab ) ... ) ...) for this purpose.

      Check ABAP News for 7.40, SP08 - Start Value for Constructor Expressions for further details.

      Author's profile photo Sougata Chatterjee
      Sougata Chatterjee

      Thanks but I'm on 7.4 SP05 so this syntax will not work.

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

      With 7.40, SP08, there will be the BASE addition to constructor operators to achieve this.

      http://scn.sap.com/community/abap/blog/2014/09/29/abap-news-for-740-sp08--start-value-for-constructor-expressions

      Author's profile photo Former Member
      Former Member

      When you construct the structure with the operator #, this code cannot be found via where-used list.

      Example:

      lo_obj->set_structure( VALUE #( field1 = 'aaa' field2= 'bbb'' ).
      The type of importing structure is STRUCT_TYPE

      When you enter where used list on STRUCT_TYPE, this line of code does not appear.

      It can be "solved" via replacing # with STRUCT_TYPE:

      lo_obj->set_structure( VALUE struct_type( field1 = 'aaa' field2= 'bbb'' ).

      but it's not the nicest workaround, I think.

      Regards,

      Radek

      Author's profile photo Former Member
      Former Member

      Hi Horst

      I'v been using this new syntax for a while now, and until today everything was fine, but today I stumbled upon something that surprised me, the next line doesn't compile:

      data(itab) = VALUE string_table( ( 'string1' ) ( 'string2' ) ).


      Error is "'string1'" and the line of "ITAB" are incompatible., while this other line does compile:


      data(itab) = VALUE string_table( ( |string1| ) ( |string2| ) ).


      I guess it has something to do with Text field literals and Text string literals, but still find it weird as all other assigments between text field literals and strings work, even when calling methods like this:


      CLASS lcl_test DEFINITION.

         PUBLIC SECTION.

           CLASS-METHODS test IMPORTING st TYPE string.

      ENDCLASS.

      CLASS lcl_test IMPLEMENTATION.

         METHOD test.

           WRITE st.

         ENDMETHOD.

      ENDCLASS.


      START-OF-SELECTION.

      lcl_test=>test( 'string' ).


      So, any ideas on why this happens?


      btw thanks for the blog, I find it very interesting.

      Regards

      Simón

      .

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

      So, any ideas on why this happens?

      Sure, works as documented:

      The constructed rows must meet the requirements of the statement INSERT for inserting work areas using table keys and therefore be compatible with the row type.
      For passing parameters to methods, there are other rules:


      Best
      Horst
      Author's profile photo Evgeniy Astafev
      Evgeniy Astafev

      Hi Horst.

      Is there any way to debug step by step the VALUE operator? Like LOOP AT.

      i.e.

      data(z) = value t_table( for wa in some_table where ( <some condition> )

                                              ( field1 = cond #( when wa-field1 > 0 then x else y ) ).

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

      In SAP GUI, you can change the "Step Size" to debug expressions. In ADT not yet.

      /wp-content/uploads/2015/08/debugger_771681.jpg

      Author's profile photo Evgeniy Astafev
      Evgeniy Astafev

      Never used that button 😀 Thanks!

      Author's profile photo Vinodkumar Tarlana
      Vinodkumar Tarlana

      TYPES: BEGIN OF ty_ship,
                 tknum
      TYPE tknum,     "Shipment Number
                 name 
      TYPE ernam,     "Name of Person who Created the Object
                 city 
      TYPE ort01,     "Starting city
                 route
      TYPE route,     "Shipment route
            
      END OF ty_ship.
      TYPES: ty_ships TYPE SORTED TABLE OF ty_ship WITH UNIQUE KEY tknum.
      TYPES: ty_citys TYPE STANDARD TABLE OF ort01 WITH EMPTY KEY.

      GT_SHIPS type ty_ships. -> has been populated as follows:

      Row TKNUM[C(10)] Name[C(12)] City[C(25)] Route[C(6)]
      2 002 Gavin Sydney R0003
      4 004 Elaine Perth R0003
      1 001 John Melbourne R0001
      3 003 Lucy Adelaide

      R0001


      DATA(gt_citys) = VALUE ty_citys( FOR ls_ship IN gt_ships ( ls_ship-city ) ).


      Above line will copy CITY column data into GT_CITYS.


      What we should do if we need Column ROUTE data along with CITY?.

      I want to copy all the lines of CITY and ROUTE data to another table.

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

      Use the syntax for structures within the brackets, ( comp1 = ... comp2 = ... ).

      Horst

      Author's profile photo Vinodkumar Tarlana
      Vinodkumar Tarlana

      Thanks Horst Keller.. It worked.

      Author's profile photo Timothy Muchena
      Timothy Muchena

      Hi thanks for your blogs

      On performance - is there a performance gain when you use VALUE expression to move internal table contents from itab1 to itab2 instead of looping through itab1 and appending to itab2?

      Regards

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

      No, internally the same kernel functions are called.

      Author's profile photo Former Member
      Former Member

      Hi Horst,

      I've a question regarding VALUE with FOR:

          DATA(del) = VALUE tt_vbeln( FOR line IN deliveries (

                                         table_line  = line-document_numb ) ).

      An error is ocuring in "table_line". It says "Type "C" is not a structure".

      Can't I use this?

      Thank you.

      Regards,

      Luís

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

      Hi Luís,

      You cannot use the pseudo comment table_line inside the construction of a structured table line. The only position where table_line can be used in FOR is the WHERE condition.

      The syntax error stems from the fact, that you use the syntax for constructing a structure. But the line type of tt_vbeln is not structured.

      Instead, your code should simply worke like this:

      DATA(del) = VALUE tt_vbeln( FOR line IN deliveries

                                                            ( line-document_numb )  ).

      Horst

      Author's profile photo Former Member
      Former Member

      Thank you! It worked fine!

      Author's profile photo Rafal Gawel
      Rafal Gawel

      Hello Horst,

      I would like to ask how I could use VALUE operator with ‘FOR wa IN itab’, instead of traditional ‘Loop at itab assigning <fs>’, where in the loop I could remove lines and modify fields based on the values from other fields.

      I tried with something like below, but it didn’t copy all lines from itab2, but only this for which field3 has been modified.

      itab1 = VALUE #( FOR wa IN itab2 where ( field1 = '123' AND field2 = 'ABC' )
                        
                            ( field3 = COND #( WHEN wa-flag EQ 'X'
                                              THEN 'TRUE' ELSE 'FALSE' )
                         ).

      When I add ( wa ) to parameters or I used ‘BASE CORRESPONDING #( itab2 ) before ‘FOR’ – like below:

      itab1 = VALUE #( FOR wa IN itab2 where ( field1 = '123' AND field2 = 'ABC' )
                            ( wa )
                            ( field3 = COND #( WHEN wa-flag EQ 'X'
                                              THEN 'TRUE' ELSE 'FALSE' )
                         ).

      or:

      itab1 = VALUE #( base CORRESPONDING #( itab2 )
                            FOR wa IN itab2 where ( field1 = '123' AND field2 = 'ABC' )
      
                            ( field3 = COND #( WHEN wa-flag EQ 'X'
                                              THEN 'TRUE' ELSE 'FALSE' )
                         ).

      … then all the lines have been copied + few additional lines with changed values of field3. So eventually there was more lines in itab1 then in itab2.

      What would be the best approach for this kind of requirement ?

      Kind Regards
      Rafal

      Author's profile photo Enno Wulff
      Enno Wulff

      Hey!

      According to the example "Structured line type (RANGES table)":

      DATA itab TYPE RANGE OF i.itab = VALUE #( sign = ‘I’  option = ‘BT’ ( low = 1  high = 10 )                                          ( low = 21 high = 30 )                                          ( low = 41 high = 50 )                            option = ‘GE’ ( low = 61 )  ).

      I would like to additonally use FOR/ CORRESPONDING:

      TYPES: BEGIN OF range,
               field  TYPE fieldname,
               sign   TYPE c LENGTH 1,
               option TYPE c LENGTH 2,
               low    TYPE c LENGTH 40,
               high   TYPE c LENGTH 40,
             END OF range,
             ranges TYPE SORTED TABLE OF range WITH NON-UNIQUE KEY field.
      DATA fieldranges TYPE ranges.
      
      SELECT-OPTIONS s_bukrs FOR h_bukrs.
      
      fieldranges = VALUE #( field  = 'BUKRS' ( for bukrs IN s_bukrs[]
                                  ( corresponding #( bukrs ) ) ) ) .
      

      But I get the following error at FOR:

      The component "FIELD" and its superstructure "" were specified at the same time.

      I get the error " ")" expected, not "("." when trying to integrate FIELD in the FOR loop:

      fieldranges = VALUE #( FOR bukrs IN s_bukrs[]
                                ( field  = 'BUKRS' 
                                ( corresponding #( bukrs ) ) ) ).
      

      Without the "(" it says:

      Unable to interpret "CORRESPONDING". Possible causes of error include incorrect spellings or comma errors.

      Is it not possible or am I doing something wrong?

      The only way it worked is the straight way, but I would like to use corresponding:

      fieldranges = VALUE #( FOR bukrs IN s_bukrs[]
                                ( field  = 'BUKRS'
                                  option = bukrs-option
                                  sign   = bukrs-sign
                                  low    = bukrs-low
                                  high   = bukrs-high ) ) .

      Thanks for any hint.

      Author's profile photo Sandra Rossi
      Sandra Rossi

      This syntax?

      fieldranges = VALUE #(
          FOR bukrs IN s_bukrs[]
          ( VALUE #( BASE CORRESPONDING #( bukrs ) field = 'BUKRS' ) ) ).
      
      Author's profile photo Enno Wulff
      Enno Wulff

      Yes, cool! Thanks Sandra!

      I tried similar syntax, but without the 2nd VALUE.

      Thanks a lot!

      Author's profile photo Ahmet Sahan
      Ahmet Sahan

      Hi,

      constructor operators are cute...

      but now we need more power in real coding.  :))

       

      *                                      reduce #( init type betrw_kk for wa_topeb in gt_print_amount
      *                                                                      where ( ‘DGT/#ETUKB/FAIZ/GUC’ cs print_doc_item )
      *                                                                      next x = x + wa_topeb-amount ) 
      not possible

       

      *                                      reduce #( init type betrw_kk for wa_topeb in gt_print_amount
      *                                                                      where ( print_doc_item = ‘DGT’ or
      *                                                                              print_doc_item = ‘#ETUKB’ or
      *                                                                              print_doc_item = ‘FAIZ’ or
      *                                                                              print_doc_item = ‘RI’ or
      *                                                                              print_doc_item = ‘RC’ or
      *                                                                              print_doc_item = ‘ILAVE’ or
      *                                                                              print_doc_item = ‘KCK’ or
      *                                                                              print_doc_item cp ‘GUC*’ )
      *                                                                      next x = x + wa_topeb-amount )
      nice but it can be more…

       

      reduce #( init type betrw_kk for wa_topeb in gt_print_amount
      where print_doc_item in 
      value bizc_selopt_tabsign ‘I’ option ‘EQ’ 
      low ‘DGT’ )
      low ‘#ETUKB’ )
      next + wa_topebamount )      

      *awkward, in need of a generic functional method to build range from a string  or value list.

       

      Author's profile photo Sandra Rossi
      Sandra Rossi

      Why don't you define this functional method?

      PS: SAP has never provided rich ABAP APIs so it's useless asking this kind of thing according to me. Instead, create your own library of utilities.