How to expose the return type of a global class method? - oop

I've written an ABAP Method, which returns me some analyses in a custom table.
Now I want to call this Method from an RFC module.
So far so good - the method works fine, but I'm curious of how to return this table?
Do I have to create a table / structure ... in SE11 to make it work because otherwise I can't refer to this table type or is there an easier way?
I'm quite new to ABAP so I don't know the best practices.
m_analyses = new zcl_manalyses( ).
data(lt_m_analyses) = m_analyses->analyse_m_data(
budat_from = budat_from
budat_to = budat_to
).

The TYPES statement can not only occur inside a method's body, but also inside the class definition, in which case it can be accessed from other places with class_name=>type_name (if it's public):
CLASS cl_user_registry DEFINITION PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF user,
firstname TYPE string,
lastname TYPE string,
END OF user,
users TYPE STANDARD TABLE OF user.
METHODS:
get_current_users
RETURNING users.
ENDCLASS.
DATA current_users TYPE cl_user_registry=>users.
current_users = cl_user_registry=>get_current_users( ).

You first have to create a structure in ABAP Dictionary (SE11), then you create a table type in SE11 as well.
You then reference the structure in the line type of the table type.
Try using the new global table type, it should work. (with typing 'TYPE')

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"

Return an internal table in ABAP

Is it possible to return an internal table when calling a method of a class?
The idea is the following:
In my method, i am calculating all periods within a certain date-range.
E.g my range is: 01.01.2020 - 31.03.2020, so I want to get an internal table with the following results:
01.01.2020 - 31.01.2020
01.02.2020 - 28.02.2020
01.03.2020 - 31.03.2021
The calculation already works and i can display the results via the WRITE statement, but I am not sure how to return the result.
I created an internal table with the following structure:
TYPES: BEGIN OF periods,
begda TYPE dats,
endda TYPE dats,
END OF periods.
DATA: lt_periods TYPE STANDARD TABLE OF periods.
But I don't understand how to return the data to work with it in another method.
Thank you in advance.
Yes, it is possible to have an internal table as returning parameter of a method.
The type of the returning parameter has to be a table type, so a table type has to be declared:
TYPES tt_periods TYPE STANDARD TABLE OF periods WITH DEFAULT KEY. "As pointed out by Sandra, see below :)
And the method is declared like this:
METHODS method
... "IMPORTING parameters (if exist)
RETURNING
VALUE(rt_periods) TYPE tt_periods.
Just to add a little bit, you can do as follow:
define your data type in the public / protected or private section of your class
return / export / change in your method the specific data type defined above
If you data type definition is done in public section this will become visible for any other ABAP objects (for example you can use it in a function module definition or in other ABAP objects, as: <class_name>=><type_name>)

Which should be used in ABAP : TYPE or LIKE?

So these both seem to work for me:
TABLES:
T001, "Table of Company Codes.
Z_KNA1_VBRK. "View I created..
DATA:
CCNAME TYPE T001-BUTXT,
CCCURR TYPE T001-WAERS,
KNAVBK TYPE Z_KNA1_VBRK,
AMNICC TYPE Z_KNA1_VBRK-NETWR.
and
DATA:
CCNAME LIKE T001-BUTXT,
CCCURR LIKE T001-WAERS,
KNAVBK LIKE Z_KNA1_VBRK,
AMNICC LIKE Z_KNA1_VBRK-NETWR.
PARAMETERS:
COMPCODE LIKE T001-BUKRS.
Is there any difference between them technically? Which is preferred / best practice and why?
To get the difference try to compile the following program.
REPORT zzz.
CLASS lcl_main DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
main.
ENDCLASS.
CLASS lcl_main IMPLEMENTATION.
METHOD main.
DATA: ls_t000t TYPE t000,
ls_t000l LIKE t000.
ENDMETHOD.
ENDCLASS.
The error message you will get is
Within classes and interfaces, you can only use "TYPE" to refer to ABAP Dictionary types, not "LIKE" or "STRUCTURE".
This is because in the OO context you need to write explicitly TYPE when you actually refer to a type. This is the current state of the art.
Now change your program slightly and try to declare global variables with LIKE and TYPE.
REPORT zzz.
DATA: gs_t000t TYPE t000,
gs_t000l LIKE t000.
CLASS lcl_main DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
main.
ENDCLASS.
CLASS lcl_main IMPLEMENTATION.
METHOD main.
DATA: ls_t000t TYPE t000.
* ls_t000l LIKE t000.
ENDMETHOD.
ENDCLASS.
As you can see there are no compilation errors in this case. In this context TYPE and LIKE are interchangeable, they mean the same. This applies also to the "old" parts of ABAP means of modularization like subroutines and function modules.
However I use the following rule of thumb.
Whenever I refer to a DDIC or local type I use TYPE. If I want to create a variable that is exactly of the same type like other variable I use LIKE. Should the type of the original variable change in the future, the change has to be made only in one place then.
Example.
METHOD main.
DATA: ls_t000t TYPE t000. "should the type change from T000 to T002
"in the future, one has to change it only in one place.
DATA: ls_t000l LIKE ls_t000t.
ENDMETHOD.
Yes, there is a difference. You cannot get this difference because you declared your structures via TABLES statement, which is obsolete now and shouldn't be used.
TABLES statement declares interface work area with a name identical to Data Dictionary structure. Therefore both your LIKE and TYPE declarations treat Z_KNA1_VBRK either like data object or DDIC structure correspondingly.
In any other case such declaration won't compile because LIKE and TYPE statements are not interchangable.
You should declare separate structures in your program rather than using such obsolete elements. The only allowed exception is data exchange with classic dynpros.
To further details, switch to ABAP documentation.

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.

Anonymous Type Collection

How would you solve this? I want to return this collection:
Public Function GetShippingMethodsByCarrier(ByVal Carrier As ShippingCarrier) As List(of ?)
Return Carrier.ShippingMethods.Select(Function(x) New With {.ID = x.ID, .Name = String.Format("{0} {1}", Carrier.Name, x.Description)})
End Function
Thanks!!
You can't return an anonymous type from a function like this because it has no name.
Since this is a public function is should have a well defined return type. Create a new class holding those two properties.
Its possible to return it if the return type is an inferred generic parameter, but that's not what you want here. This is useful for LINQ where an anonymous type essentially gets passed through from a parameter to the result type, but not useful for what you're doing.
You could also use a Tuple, but then you'd lose the property names. And it wouldn't be extensible since adding a new property would break caller code. So I wouldn't recommend that either.
The problem here is you're attempting to return an anonymous type in a strongly typed manner. This is just not possible in VB.Net (or C# for that matter). Anonymous types are meant to be anonymous and their names cannot be stated explicitly in code. The two ways to work around this are to
Option #1 Use / Create a strongly named type like the following
Structure Item
Public ID as Integer
Public Name As String
Public Description As String
End Structure
Option #2 Set the return type to be Object and access the list in a late bound manner
EDIT
As CodeInChaos it is possible to return them in a strongly type manner in a generic context. But that doesn't appear to help you for this particular problem.