Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Type "REF TO" is incompatible with type "REF TO ..."

ennowulff
Active Contributor

Hi there!

I experienced a strange problem with references:

see the following program

TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.

DATA b TYPE REF TO t_t000.
DATA BEGIN OF a OCCURS 0.
INCLUDE STRUCTURE t000.
DATA END OF a.

b = REF #( a[] ).

The "source" data is defined with DATA ... OCCURS. Yes, I know, it's outdated and should not be used anymore. tell this to the persons maintaining SAPMV45A... 😂

the report can not be activated due to the error

Type "REF TO " is incompatible with type "REF TO T_T000".

Is there any chance to define an internal table with exactly the same technical conditions so that it can be referenced?I tried various definitions:
  • WITH EMPTY KEY
  • INITITAL SIZE 0
  • WITHOUT FURTHER SECONDARY KEYS

I also know that there is a workaround: Use TYPE REF TO DATA and use Field-Symbols to access.

1 ACCEPTED SOLUTION

stekoester
Explorer

Hi enno.wulff,

with your sample in mind I've created a new sample. Maybe this is what you need.

TYPES:
  BEGIN OF _data_reference,
    name TYPE string,
    data TYPE REF TO data,
    type TYPE tablename,
  END OF _data_reference,
  _data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.

DATA:
  BEGIN OF xvbap OCCURS 125.
    INCLUDE STRUCTURE vbapvb.
  DATA:
  END OF xvbap.

DATA:
  BEGIN OF yvbap OCCURS 2.
    INCLUDE STRUCTURE vbapvb.
  DATA:
  END OF yvbap.

CLASS lcl_reference DEFINITION.
  PUBLIC SECTION.
    CLASS-DATA:
      grt_xvbap TYPE REF TO va_vbapvb_t,
      grt_yvbap TYPE REF TO va_vbapvb_t.

    CLASS-METHODS:
      set_references
        IMPORTING
          it_data_references TYPE _data_references.
ENDCLASS.

CLASS lcl_reference IMPLEMENTATION.
  METHOD set_references.
    FIELD-SYMBOLS:
      <lt_data> TYPE STANDARD TABLE.

    LOOP AT it_data_references REFERENCE INTO DATA(lr_data_reference).
      TRY.
          ASSIGN lr_data_reference->data->* TO <lt_data> CASTING TYPE (lr_data_reference->type).
          CASE lr_data_reference->name.
            WHEN 'XVBAP'.
              grt_xvbap = REF #( <lt_data> ).
            WHEN 'YVBAP'.
              grt_yvbap = REF #( <lt_data> ).
          ENDCASE.
        CATCH cx_sy_assign_cast_illegal_cast cx_sy_assign_cast_unknown_type.
      ENDTRY.
    ENDLOOP.

    IF grt_xvbap IS NOT INITIAL AND grt_yvbap IS NOT INITIAL.
      cl_demo_output=>write_html( html = '<h1>Before modifikation:</h1>' ).
      cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
                                         |<thead>| &&
                                         |<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
                                         |<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
                                         |<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
                                         |</thead>| &&
                                         |<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
                                         |<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).

      grt_xvbap->*[ 1 ]-vbeln = '0000000011'.
      grt_yvbap->*[ 1 ]-vbeln = '0000000012'.

      cl_demo_output=>write_html( html = '<h1>After modifikation:</h1>' ).
      cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
                                         |<thead>| &&
                                         |<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
                                         |<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
                                         |<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
                                         |</thead>| &&
                                         |<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
                                         |<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).
      cl_demo_output=>display( ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

TYPES:
  gtyt_xvbapvb LIKE STANDARD TABLE OF xvbap WITH NON-UNIQUE DEFAULT KEY,
  gtyt_yvbapvb LIKE STANDARD TABLE OF yvbap WITH NON-UNIQUE DEFAULT KEY.

START-OF-SELECTION.

  xvbap[] = VALUE #( ( vbeln = '0000000001' ) ).
  yvbap[] = VALUE #( ( vbeln = '0000000002' ) ).

  lcl_reference=>set_references( VALUE #( ( name = 'XVBAP' data = REF gtyt_xvbapvb( xvbap[] ) type = 'VA_VBAPVB_T' )
                                          ( name = 'YVBAP' data = REF gtyt_yvbapvb( yvbap[] ) type = 'VA_VBAPVB_T' ) ) ).

Greetings
Stephan

25 REPLIES 25

ChristianGünter
Contributor

Hi Enno,

not long ago I had the same issue. Didn't find a better solution than generic TYPE REF TO DATA.

Though, if only local access is sufficient this should work.

DATA b LIKE REF TO a[].

OR

DATA(b) = REF #( a ).

Christian

0 Kudos

Thanks for the feedback, christian.guenter !

local access is not possible.

stekoester
Explorer

Hi Enno,

maybe this will solve your issue. The magic is NEW instead of REF.

TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.

DATA b TYPE REF TO t_t000.
DATA:
  BEGIN OF a OCCURS 0.
    INCLUDE STRUCTURE t000.
DATA:
  END OF a.

SELECT * FROM t000 INTO TABLE a.

b = NEW #( a[] ).

Greetings

Stephan

0 Kudos

Direct access to the reference b is possible.

DATA(client) = VALUE #( b->*[ 1 ]-mandt OPTIONAL ).

LOOP AT b->* REFERENCE INTO DATA(b_line).
  DATA(mandt) = b_line->mandt.
ENDLOOP.

Greetings

Stephan

Thanks a lot stephkoester ! I will check tomorrow!

0 Kudos

Maybe it's better to combine NEW with CORRESPONDING (see sample output of sample report).

TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.

DATA b TYPE REF TO t_t000.
DATA d TYPE REF TO t_t000.
DATA:
  BEGIN OF a OCCURS 0.
    INCLUDE STRUCTURE t000.
DATA:
  END OF a.

SELECT * FROM t000 INTO TABLE a.

SELECT mandt, mtext, ort01, mwaer, adrnr,
       cccategory AS ddcategory, cccopylock AS ddcopylock
  FROM t000 INTO TABLE @DATA(c).

cl_demo_output=>write_data( value = c
                            name  = 'Selected data (only 7 fields including renaming two of them)' ).

d = NEW #( c[] ).
cl_demo_output=>write_data( value = d->*
                            name  = 'Referencing without corresponding' ).

d = NEW #( CORRESPONDING #( c[] ) ).
cl_demo_output=>write_data( value = d->*
                            name  = 'Referencing with corresponding' ).

d = NEW #( CORRESPONDING #( c[] MAPPING cccategory = ddcategory cccopylock = ddcopylock ) ).
cl_demo_output=>write_data( value = d->*
                            name  = 'Referencing with corresponding and mapping' ).

cl_demo_output=>display( ).

b = NEW #( a[] ).
DATA(client) = VALUE #( b->*[ 1 ]-mandt OPTIONAL ).

LOOP AT b->* REFERENCE INTO DATA(b_line).
  DATA(mandt) = b_line->mandt.
ENDLOOP.

Greetings
Stephan

NEW will create a new data object, and copies the contents of the original data object. If A is changed, B will not reflect it.

I don't think it's what the OP wants. But let's see.

Doesn't NEW create a new data object and copies the internal table? I think Enno wants a reference so he can carry it around change the content of a[] with that. In your example if you change b->* this change isn't reflected in a[].

Yes, just realized it after seeing the comment of sandra.rossi.

But there is another workaround.

TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.

DATA b TYPE REF TO t_t000.
DATA:
  BEGIN OF a OCCURS 0.
    INCLUDE STRUCTURE t000.
DATA:
  END OF a.

SELECT  mandt, mtext, ort01, mwaer, adrnr, cccategory FROM t000 INTO CORRESPONDING FIELDS OF TABLE @a.

cl_demo_output=>write_data( value = a[] name = 'Selected Data' ).

* Create a helper reference
DATA(c) = REF #( a[] ).
b = c.

LOOP AT b->* REFERENCE INTO DATA(b_line).
  b_line->mandt = b_line->mandt + 800.
ENDLOOP.

cl_demo_output=>display_data( value = a[] name = 'Manipulated Data' ).

Greetings
Stephan

0 Kudos

Well that's interesting. That gives me a warning with 752 and syntax error with >=754.

0 Kudos

Strange. With 750PL22 it's working.

So, in which system we have a bug?

0 Kudos

works perfectly fine! Thanks a lot stephkoester !!

0 Kudos

Hey stephkoester christian.guenter sandra.rossi

thanks for all your comments!

But, as already mentioned, this is not a solution to my problem.

NEW creates a copy of the table and returns the reference.

We now have the following solution:

pass the reference by REF TO DATA and store the reference in a variable TYPE REF TO DATA.

Before accessing the data, it must be assigned to a typed field-symbol:

FIELD-SYMBOLS <tab> TYPE TABLE OF special_type.

again: thanks to all!

Hi Enno,

what about my last comment where I don't use the new statement?

DATA:
  BEGIN OF a OCCURS 0.
    INCLUDE TYPE t000.
DATA:
  END OF a.

TYPES t_t000 LIKE STANDARD TABLE OF a WITH NON-UNIQUE DEFAULT KEY.

DATA b TYPE REF TO t_t000.

SELECT  mandt, mtext, ort01, mwaer, adrnr, cccategory FROM t000 INTO CORRESPONDING FIELDS OF TABLE @a.

cl_demo_output=>write_data( value = a[] name = 'Selected Data' ).

b = REF #( a[] ).

LOOP AT b->* REFERENCE INTO DATA(b_line).
  b_line->mandt = b_line->mandt + 800.
ENDLOOP.

cl_demo_output=>display_data( value = a[] name = 'Manipulated Data' ).

Greetings
Stephan

0 Kudos

Hey stephkoester

just saw this afterwards and this is a genius solution! I just test it. but seems good.

Only thing that worries me is the comment of christian.guenter concerning the higher releases...

"my" system release is

SAP_BASIS 754
SAP_ABA 75E

unfortunately your solution does not work because of cheating. 😄

The definition of B is done with LIKE instead of TYPE.

TYPES t_t000 LIKE STANDARD TABLE OF a WITH NON-UNIQUE DEFAULT KEY.

This only works if you can access the variable what I can't. my goal is to transfer the reference of XVBAP[] of SAPMV45A to a class attribute via a general interface:

Types: BEGIN OF _data_reference,
         name TYPE string,
data TYPE REF TO DATA,
END OF _data_reference,
_data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name. IN SAPMV45A: class=>set_references( VALUE #(
( name = 'XVBAP' data = REF #( xvbap[] ) ).
the assignment inside the class does not work: CLASS-DATA mt_xvbap TYPE va_vbapvb_tt.
CLASS-METHODS set_references
IMPORTING
it_data_references TYPE _data_references.

METHOD set_references.
mt_xvbap = it_data_references[ name = 'XVBAP' ]-data.
ENDMETHOD.

0 Kudos

Tested in SAP_BASIS 750 and 756 and it`s working fine.

enno.wulff

The curse of <br> (and SAP Community being a custom development without the best developers...)

so, for any people reading your post, with the right "pretty print":

Types: BEGIN OF _data_reference,
         name TYPE string,
         data TYPE REF TO DATA,
      END OF _data_reference,
      _data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.
In SAPMV45A:
class=>set_references( VALUE #( 
  ( name = 'XVBAP' data = REF #( xvbap[] ) ).

the assignment inside the class does not work:

CLASS-DATA mt_xvbap TYPE va_vbapvb_tt.
CLASS-METHODS set_references
  IMPORTING
    it_data_references TYPE _data_references.

METHOD set_references.
  mt_xvbap = it_data_references[ name = 'XVBAP' ]-data.
ENDMETHOD.

stekoester
Explorer
0 Kudos

This is my last idea (working in 750 and 756)

DATA:
  BEGIN OF a OCCURS 0.
    INCLUDE TYPE t000.
DATA:
  END OF a.

TYPES t_t000 LIKE STANDARD TABLE OF a WITH NON-UNIQUE DEFAULT KEY.

DATA b TYPE REF TO t_t000.

SELECT  mandt, mtext, ort01, mwaer, adrnr, cccategory FROM t000 INTO CORRESPONDING FIELDS OF TABLE @a.

cl_demo_output=>write_data( value = a[] name = 'Selected Data' ).

b = REF #( a[] ).

LOOP AT b->* REFERENCE INTO DATA(b_line).
  b_line->mandt = b_line->mandt + 800.
ENDLOOP.

cl_demo_output=>display_data( value = a[] name = 'Manipulated Data' ).

Greetimgs
Stephan

0 Kudos

I appreciate your efforts stephkoester !

unfortunately:

TYPES tt_vbapvb LIKE STANDARD TABLE OF vbapvb.

Only use "TYPE" to reference ABAP Dictionary types, not "LIKE" or "STRUCTURE".

matt
Active Contributor

Just out of interest, I tried this:

  METHOD do.
    DATA(c) = REF #( a[] ).
  ENDMETHOD.

Then, I used the Eclipse assistance to explicitly define local variable c.

It came up with

DATA: c LIKE REF TO standard table OF a.

Which isn't even syntactically correct!

horst_keller
Product and Topic Expert
Product and Topic Expert

Hi Enno!

You can drill it down to

DATA BEGIN OF s.
INCLUDE STRUCTURE t000.
DATA END OF s.
DATA r TYPE REF TO t100.
r = REF #( s ). "Error

It has nothing to do with the internal tables or with the REF or NEW syntax, but with the structure definitions.

The structure types do not match.

See Assignments Between Data Reference Variables

"Both have an identical structured type. In the case of structured types, identical technical type attributes are not sufficient, but the same structured type must have been used to define the static types. "

INCLUDE STRUCTURE is different compared to typing with the structure itself.

Horst

0 Kudos

Thanks for your explanation horst.keller !

Unfortunately the reference with LIKE does not work with internal tables.Structures do work. the problem is the internal table.

I will use the work around with TYPE REF TO DATA and ASSIGN to specific type.

horst_keller
Product and Topic Expert
Product and Topic Expert

And I say, it is the difference in the structure definitions, in your case of the table lines.

The LIKE was a typo ...

Yes, if you have to use these weird declarations, well, you need workarounds.

stekoester
Explorer

Hi enno.wulff,

with your sample in mind I've created a new sample. Maybe this is what you need.

TYPES:
  BEGIN OF _data_reference,
    name TYPE string,
    data TYPE REF TO data,
    type TYPE tablename,
  END OF _data_reference,
  _data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.

DATA:
  BEGIN OF xvbap OCCURS 125.
    INCLUDE STRUCTURE vbapvb.
  DATA:
  END OF xvbap.

DATA:
  BEGIN OF yvbap OCCURS 2.
    INCLUDE STRUCTURE vbapvb.
  DATA:
  END OF yvbap.

CLASS lcl_reference DEFINITION.
  PUBLIC SECTION.
    CLASS-DATA:
      grt_xvbap TYPE REF TO va_vbapvb_t,
      grt_yvbap TYPE REF TO va_vbapvb_t.

    CLASS-METHODS:
      set_references
        IMPORTING
          it_data_references TYPE _data_references.
ENDCLASS.

CLASS lcl_reference IMPLEMENTATION.
  METHOD set_references.
    FIELD-SYMBOLS:
      <lt_data> TYPE STANDARD TABLE.

    LOOP AT it_data_references REFERENCE INTO DATA(lr_data_reference).
      TRY.
          ASSIGN lr_data_reference->data->* TO <lt_data> CASTING TYPE (lr_data_reference->type).
          CASE lr_data_reference->name.
            WHEN 'XVBAP'.
              grt_xvbap = REF #( <lt_data> ).
            WHEN 'YVBAP'.
              grt_yvbap = REF #( <lt_data> ).
          ENDCASE.
        CATCH cx_sy_assign_cast_illegal_cast cx_sy_assign_cast_unknown_type.
      ENDTRY.
    ENDLOOP.

    IF grt_xvbap IS NOT INITIAL AND grt_yvbap IS NOT INITIAL.
      cl_demo_output=>write_html( html = '<h1>Before modifikation:</h1>' ).
      cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
                                         |<thead>| &&
                                         |<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
                                         |<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
                                         |<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
                                         |</thead>| &&
                                         |<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
                                         |<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).

      grt_xvbap->*[ 1 ]-vbeln = '0000000011'.
      grt_yvbap->*[ 1 ]-vbeln = '0000000012'.

      cl_demo_output=>write_html( html = '<h1>After modifikation:</h1>' ).
      cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
                                         |<thead>| &&
                                         |<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
                                         |<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
                                         |<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
                                         |</thead>| &&
                                         |<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
                                         |<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).
      cl_demo_output=>display( ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

TYPES:
  gtyt_xvbapvb LIKE STANDARD TABLE OF xvbap WITH NON-UNIQUE DEFAULT KEY,
  gtyt_yvbapvb LIKE STANDARD TABLE OF yvbap WITH NON-UNIQUE DEFAULT KEY.

START-OF-SELECTION.

  xvbap[] = VALUE #( ( vbeln = '0000000001' ) ).
  yvbap[] = VALUE #( ( vbeln = '0000000002' ) ).

  lcl_reference=>set_references( VALUE #( ( name = 'XVBAP' data = REF gtyt_xvbapvb( xvbap[] ) type = 'VA_VBAPVB_T' )
                                          ( name = 'YVBAP' data = REF gtyt_yvbapvb( yvbap[] ) type = 'VA_VBAPVB_T' ) ) ).

Greetings
Stephan

Thanks a lot stephkoester!!

the main part is the workaround via field-symbol.

ASSIGN lr_data_reference->data->* TO <lt_data> CASTING TYPE (lr_data_reference->type).

another Stefan provided this solution which is mainly the same:

FIELD-SYMBOLS <xvbap_tab> TYPE TABLE OF va_vbapvb_t.
ASSIGN xvbap[] TO <xvbap_tab>.
grt_xvbap = REF #( <vbap_tab> ).

Your solution with passing the desired specific type is very elegant!

I also tried to retrieve the type by

CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( xvbap[] )

but this will of course return the "wrong" type which cannot be used.

thanks for your tenacity and this elegant solution!