Correct way of using TYPE REF TO data? - abap

I've declared a type with the type of ref to data. so it looks like this
my_type type ref to data.
Then I declare an internal table, which I want to assign to my_type.
Data:
ref_data type my_type.
itable type it_table.
ref_data = itable.
Why can't I assign itable to ref_data, isn't a ref to data is a generic data type and can be assigned to anything?

This is very similar to other programming languages, and it's not a problem of typing the variables or references. You're trying to assign a value to a pointer variable - that won't work anywhere. You need to use GET REFERENCE OF itable INTO ref_data.

That's not quite how a data reference works. A data reference has to be typed, but you type it at run time.
data: ref_data type ref to data.
data: itable type it_table.
"you access the data in a data reference via a field symbol
field-symbols: <dref> type any.
create data ref_data type it_table.
assign ref_data->* to <dref>.
<dref> = itable.
I now have a copy of itable in my dynamically typed variable ref_data, accessed by the field symbol .

Related

Structure where the data type of a member differs

Maybe superfluous, but some intro...
I am rewriting an add-in for my CAD-application (using VB.NET).
This add-in reads, via an API, a bunch of metadata from a file, presents it in a Form. This data can then be (partially) changed and written back to the file.
This metadata is accessible in a consistent way, however the data type is not the same everywhere (String, Currency, Date, Boolean, Long and IPictureDisp).
Currently I have a much too complex class with several arrays. I thought it might be smarter to create a structure. The problem is the varying data type.
Is it possible to define a structure with a member with varying datat type, or am I forced to define a different structure for each data type?
You have a few options...
1: Use Object
Nice and simple, every data type inherits from Object - so if your struct contains a property of type Object, you can put pretty much any data type in there
From the docs:
The Object data type can point to data of any data type, including any object instance your application recognizes. Use Object when you do not know at compile time what data type the variable might point to.
However, this does mean that you will get next to no help from the compiler when you are trying to write code using this property. You will also probably have to cast any time you need to do anything type-specific
2: Generic Types
This will not fit situations where you are not sure of the type. You can create a generic struct using the Of syntax.
You'd create it as so:
Structure MyStructure(Of T)
'our changing type
Dim MyCustomData As T
'...alongside regular types
Dim Name As String
Dim OtherThing As Integer
End Structure
and then when you need to create the structure, you'd simply pass the type in and assign the value
Dim struct As New MyStructure(Of Integer)
struct.MyCustomData = 123
Dim struct2 As New MyStructure(Of String)
struct2.MyCustomData = "a"

No domain values in CL_SALV_TABLE column. Why?

I have 2 rows shown in the ALV list, one of this column has domain values.
If I click on the search help right it doesn't show any values at all.
Do I have to activate something in the class to see the values of any domain?
Automatic search help (aka domain values) will be showed only when creating ALV via Dictionary structure, and that's why it is impossible with cl_salv_table, because it accepts only internal table.
However, it have special method set_ddic_reference for assigning F4 values.
DATA: lr_column TYPE REF TO cl_salv_column_table,
lr_columns TYPE REF TO cl_salv_columns_table.
DATA: ls_ddic type salv_s_ddic_reference.
lr_columns = o_alv->get_columns( ).
lr_column ?= lr_columns->get_column( columnname = 'MANDT' ).
ls_ddic-table = 'T001'.
ls_ddic-field = 'MANDT'.
lr_column->set_ddic_reference( ls_ddic ).
lr_column->set_f4( abap_true ).
This code should be called after the factory constructor and before the display() method.

Сlass for wrapping generic table crashes

I'd like to build a container ABAP class that wraps an arbitrary internal table.
My initial approach was to define a member variable of TYPE REF TO DATA and pass a reference into the constructor.
The problem is that due to the pointer the instance is still dependent on the original itab. So if the original table is freed from memory you cannot access the data anymore. I'd need to have a real copy of the table data stored within the object, so I would be able to pass the object outside the original scope of the itab.
Is there any way of achieving this in ABAP?
Sample code with references that crashes in the scenario defined in the end:
CLASS lcl_test_itab_wrapper DEFINITION LOCAL FINAL
CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS: access_outside_itab_scope.
METHODS: constructor IMPORTING itab TYPE table,
access_itab_data.
PRIVATE SECTION.
CLASS-METHODS: sample_itab_setup RETURNING VALUE(result) TYPE REF TO lcl_test_itab_wrapper.
DATA: table_ref TYPE REF TO data.
ENDCLASS.
CLASS lcl_test_itab_wrapper IMPLEMENTATION.
METHOD access_itab_data.
FIELD-SYMBOLS <table> TYPE table.
ASSIGN me->table_ref->* TO <table>.
WRITE:/ lines( <table> ).
ENDMETHOD.
METHOD constructor.
me->table_ref = REF #( itab ).
ENDMETHOD.
METHOD sample_itab_setup.
DATA: dummy_itab TYPE TABLE OF string.
APPEND 'test_record' TO dummy_itab.
CREATE OBJECT result EXPORTING itab = dummy_itab.
ENDMETHOD.
METHOD access_outside_itab_scope.
DATA(o_instance) = sample_itab_setup( ).
" Here it crashes as the referenced itab was freed already.
" I'd need to have a real itab copy stored in the instance
o_instance->access_itab_data( ).
ENDMETHOD.
Update: Solution based on #vwegert answer
Replace constructor reference assignment by:
CREATE DATA me->table_ref LIKE itab.
FIELD-SYMBOLS <table> TYPE table.
ASSIGN me->table_ref->* TO <table>.
<table> = itab.
You need to create a data object dynamically instead of (ab)using a statically defined one. Check the documentation of the CREATE DATA statement.
Check out the "GET REFERENCE of xx into xx" statement as well, you can save three lines of your code.

Getting an ABAP object's identity number

when inspecting an object-instance in the debugger, it will be printed like this:
{O:9*CLASS=CL_SOMETHING}
Is it possible to retrieve that class' identity-number 9 from a given object reference?
I want to distinguish multiple instances of the same class and print their instance-number.
I found no way using the RTTI to get that information, any advice?
As far as I know, you can't access that internal object identifier. The debugger uses some private kernel interface to do so that is not accessible to the ordinary user. You could try something like this:
CLASS lcl_object_id_map DEFINITION.
PUBLIC SECTION.
METHODS get_id
IMPORTING ir_object TYPE REF TO object
RETURNING value(r_id) TYPE sysuuid_c.
PRIVATE SECTION.
TYPES: BEGIN OF t_object_id,
object TYPE REF TO object,
id TYPE sysuuid_c,
END OF t_object_id,
tt_object_id_map TYPE HASHED TABLE OF t_object_id
WITH UNIQUE KEY object.
DATA gt_object_id_map TYPE tt_object_id_map.
ENDCLASS. "lcl_object_id_map DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_id_map IMPLEMENTATION.
METHOD get_id.
DATA: ls_entry TYPE t_object_id.
FIELD-SYMBOLS: <ls_entry> TYPE t_object_id.
READ TABLE gt_object_id_map
ASSIGNING <ls_entry>
WITH KEY object = ir_object.
IF sy-subrc <> 0.
ls_entry-object = ir_object.
ls_entry-id = cl_system_uuid=>create_uuid_c32_static( ).
INSERT ls_entry INTO TABLE gt_object_id_map ASSIGNING <ls_entry>.
ENDIF.
r_id = ls_entry-id.
ENDMETHOD. "get_id
ENDCLASS. "lcl_object_id_map IMPLEMENTATION
I actually found an (internal) way to get the object's internal ID in the Object Services CL_OS_CA_COMMON=>OS_GET_INTERNAL_OID_BY_REF:
CALL 'OBJMGR_GET_INFO' ID 'OPNAME' FIELD 'GET_OBJID'
ID 'OBJID' FIELD integer_oid
ID 'OBJ' FIELD ref_to_object.
Yes, this is internal stuff... Use at own risk.

How to read type of element for Oracle collection type?

I have Oracle collection type defined as:
type tab_foo as table of obj_foo
Where obj_foo is defined as:
type obj_foo as object
By calling:
select * from sys.all_types where typecode = 'COLLECTION';
I can get metadata for all the collection types, however there is no information what is the type of element contained in the collection.
How to retrieve collection element type metadata from oracle?
Look at ALL_COLL_TYPES, which lists all collection types. The column you are interested in is ELEM_TYPE_NAME.