Access static methods and attributes of the friend class in ABAP - class

This is how my two global classes look like:
CLASS zcl_singleton_class DEFINITION CREATE PRIVATE friends ZCL_FLINFO
PUBLIC SECTION.
CLASS-METHODS:
CLASS_CONSTRUCTOR,
get_instance
RETURNING VALUE(r_instance) TYPE REF TO zcl_singleton_class.
PRIVATE SECTION.
types:
TY_CONNECTION_LIST TYPE STANDARD TABLE OF SPFLI WITH KEY carrid connid.
class-data instance type ref to zcl_singleton_class .
class-data CONNECTION_LIST type TY_CONNECTION_LIST .
ENDCLASS.
CLASS zcl_singleton_class IMPLEMENTATION.
method CLASS_CONSTRUCTOR.
instance = instance.
SELECT * FROM SPFLI INTO TABLE CONNECTION_LIST.
endmethod.
METHOD get_instance.
r_instance = instance.
ENDMETHOD.
ENDCLASS.
CLASS ZCL_FLINFO DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
CLASS_CONSTRUCTOR,
get_connection
IMPORTING im_carrid type S_CARR_ID
RETURNING VALUE(re_connection) TYPE.
ENDCLASS.
CLASS ZCL_FLINFO IMPLEMENTATION.
METHOD get_connection.
LOOP at CONNECTION_LIST TRANSPORTING NO FIELDS WHERE carrid = im_carrid.
re_connection = re_connection + 1.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
How can I implement the get_connection method of ZCL_FLINFO so it to iterate through the internal table CONNECTION_LIST of zcl_singleton_class, to count the number of connections for the given airline and return it in the parameter?

I figured out something the work out fine in my case. If a class A(zcl_singleton_class) offers friendship to another class B(ZCL_FLINFO), B can access the private components of A. So, I simply access the internal table(CONNECTION_LIST) by calling it in my loop.
method GET_N_O_CONNECTIONS.
LOOP AT zcl_singleton_class=>CONNECTION_LIST TRANSPORTING NO FIELDS WHERE CARRID = IM_CARRID.
RE_N_O_CONNECTIONS = RE_N_O_CONNECTIONS + 1.
ENDLOOP.
endmethod.

Related

Unknown type "zcalc_result"

I am trying to run a unity test on an abap code using Eclipse.
I am learning from a video series on youtube from a channel called Abap101.
Everything was going well until he uses a variable from the zcalc_result type.
It seems to run well on the video, but my code displays the error message "ZCALC_RESULT TYPE IS UNKNOWN"
REPORT zfsaf_tdd3_babysteps.
*Desenvolvedores:
*Salário igual ou aima de $3000, desconto de 20%
*Salário abaixo de $3000, desconto de 10%
*
*DA e Testadores:
*Salário igual ou acima de de $2500, desconto de 25%
*Salário de $2500, desconto de 15%
CLASS employee DEFINITION.
PUBLIC SECTION.
METHODS constructor IMPORTING employee_name TYPE string
employee_salary TYPE zcalc_result
employee_position TYPE string.
METHODS get_salary RETURNING VALUE(salary) TYPE zcalc_result.
METHODS get_position RETURNING VALUE(position) TYPE string.
PRIVATE SECTION.
DATA name TYPE string.
DATA salary TYPE zcalc_result.
DATA position TYPE string.
ENDCLASS.
CLASS employee IMPLEMENTATION.
METHOD constructor.
me->name = emplyee_name.
me->position = employee_position.
me->salary = employee_salary.
ENDMETHOD.
METHOD get_salary.
salary = me->salary.
ENDMETHOD.
METHOD get_position.
position = me->position.
ENDMETHOD.
ENDCLASS.
CLASS test_payment_calculator DEFINITION FOR TESTING RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA test_employee TYPE REF TO employee.
DATA test_payment_calculator TYPE REF TO payment_calculator.
METHODS setup.
METHODS calc_developer_bellow_limit FOR TESTING.
ENDCLASS.
CLASS test_payment_calculator IMPLEMENTATION.
METHOD setup.
CREATE OBJECT me->test_payment_calculator.
ENDMETHOD.
METHOD calc_developer_bellow_limit.
CREATE OBJECT me->test_employee
EXPORTING
employee_name = 'Chaves'
employee_position = 'Developer'
employee_salary = '1500.00'.
DATA(value) = me->test_payment_calculator->calculate_payment( ).
cl_abap_unit_assert=>assert_equals( exp = '1350' act = value ).
ENDMETHOD.
ENDCLASS.
CLASS payment_calculator DEFINITION.
PUBLIC SECTION.
METHODS calculate_payment IMPORTING emploee TYPE REF TO employee
RETURNING VALUE(value) TYPE zcalc_result.
ENDCLASS.
CLASS payment_calculator IMPLEMENTATION.
METHOD calculate_payment.
value = '1350.00'.
ENDMETHOD.
ENDCLASS.
I was expecting to run a test activate the code, but I get the given messsage when a I try to activate it.
It appears that zcalc_result is a custom data-type which still needs to be defined. It could be defined as a type within the program using the TYPES keyword, or as a global type in the data dictionary (transaction SE11). The name starting with the letter z hints at the latter, but it could just as well be the former.
When you are following a tutorial, then it is possible that the author already did that but you skipped that part, that the author is going to do that next, or that the author forgot to mention it.
Judging from context, the intended purpose of this type is to hold a currency value. So if you want to declare it yourself, you would do that as a packed number (type P) with a reasonable length and two decimals. For example with this line at the top of the program:
TYPES: zcalc_result TYPE p LENGTH 10 DECIMALS 2.

Set class property of an instance within class method in MATLAB

My Objective is:
Using MATLAB, set the property value within one class method, and the property values are different between instances.
My Problem is:
When using SET in the class method, I will change the property value of all instances of this class, which is not what I want. I only want to change the property value of this instance.
About the dynamic property: I think it's used to create a unique property of the instance instead of setting the unique value of a general class property, is that right?
Code example:
classdef Storage
properties
tree = containers.Map('KeyType','int32', 'ValueType','any')
end
methods
function obj = set_tree(obj,period, value)
obj.tree(period) = value;
end
end
end
When setting the value using this method:
st1 = Storage();
st2 = Storage();
st1 = st1.set_tree(10,1);
st2 = st2.set_tree(10,2);
Right now, the value set to st2.tree(10) will override the value set to st1.tree(10), which I am trying to avoid.
The problem you're having is caused by setting a handle class object as a default value for a class property. The relevant documentation says this:
MATLAB® evaluates property default values only once when loading the class. MATLAB does not reevaluate the assignment each time you create an object of that class. If you assign an object as a default property value in the class definition, MATLAB calls the constructor for that object only once when loading the class.
So, for your Storage class above, all of your instances will be using the same default containers.Map object stored in the tree property. And since the containers.Map class is a subclass of the handle class it has reference behavior, which means the copies of the object will all point to the same underlying key/value map. If you want independent objects for each instance, you can initialize the tree property in the constructor:
classdef Storage
properties
tree
end
methods
function obj = Storage()
obj.tree = containers.Map('KeyType','int32', 'ValueType','any');
end
function obj = set_tree(obj, value, period)
obj.tree(period) = value;
end
end
end

Can you pass by reference in PeopleCode?

I'm new to PeopleCode and as I'm learning functions, I noticed that in PeopleCode, we'd normally pass value using %PATIENT_ID. A friend told me that you can also pass by reference in PeopleCode but how?
PeopleCode passes by reference for functions.
Function addOne(&num As integer)
&num = &num + 1
End-Function;
Local integer &val = 9;
addOne(&val);
MessageBox(0, "", 0, 0,String(&val));
Results in 10
If you are using App Classes it behaves differently
for methods:
Pass by value for simple types (string, int, number,etc)
Pass by reference for objects (rowsets, records, app classes)
Can pass by reference for simple types using the OUT keyword in the parameter list
method addOne(&num as integer out)
Functions which are defined in the same context as the executing code, e.g. page/component/record/field event PeopleCode, always consider parameters as refernces.
Within Application Classes, parameters of simple types on methods can be defined with the 'out' key word to state that they are a references. Methods also automatically pass parameters as references for complex types. Think: "If there is a lot of data, it is a reference"
This documentation will be very helpful for you.
https://docs.oracle.com/cd/E26239_01/pt851h3/eng/psbooks/tpcr/chapter.htm?File=tpcr/htm/tpcr07.htm
Passing Parameters with Object Data Types
Parameters with object data types are always passed by reference:
/* argument passed by reference */
method storeInfo(&f as File);
If you specify the out modifier for a method parameter with an object
data type, it becomes a reference parameter. This means that the
parameter variable is passed by reference instead of the object that
it is pointing at when passed.
For example, if you pass an object parameter with the out modifier:
method myMethod(&arg as MyObjectClass);
Local MyObjectClass &o1 = create MyObjectClass("A");
Local MyOtherObjectClass &o2 = create MyOtherObjectClass();
&o2.myMethod(&o1);
And inside myMethod this occurs:
Method myMethod
&arg = create MyObjectClass("B");
end-method;
Since the method argument is reassigned within the body of myMethod,
&o1 does not point at the new instance of MyObjectClass (initialized
with "B") after the method call completes. This is because &o1 still
references the original instance of MyObjectClass.
However, if &o1 had been passed with the out modifier, after the
method call completes, &o1 points at whatever the parameter was last
assigned to; in this case, the new instance of MyObjectClass. The
parameter, rather than the object, is passed by reference. Using
the Out Specification for a Parameter
In the following example, a class, AddStuff, has a single public
method, DoAdd. This adds two numbers together, then assigns them as
different numbers. In the signature of the method declaration, the
first parameter is not declared with an out statement, while the
second one is.
class AddStuff
​method DoAdd(&P1 as number, &P2 as number out);
​end-class;
method DoAdd
&X = &P1 + &P2;
&P1 = 1;
&P2 = 2;
end-method;
In the following PeopleCode example, an object named &Aref is
instantiated from the class AddStuff. Two parameters, &I and &J are
also defined.
local AddStuff &Aref = Create AddStuff();
local number &I = 10;
local number &J = 20;
The following code example is correct. &J is changed, because of the
outstatement in the method signature, and because the value is being
passed by reference. The value of &I is not updated.
&Aref.DoAdd(&I, &J); /* changes &J but not &I */
The following code example causes a design time error. The second
parameter must be passed by reference, not by value.
&Aref.DoAdd(10, 20); /* error - second argument not variable */

Why does VB disallow type conversion from parent to subclass?

I have already asked a question here where I basically require an instance of a base class to be converted into a subclass (or a new instance of the subclass to be created using the instance of the base class' properties). The conclusion seems to be that the best way to do this is to manually assign every property I need to transfer in the constructor of the base class.
While this is feasible in some cases, it certainly is not when there are many properties to transfer, or when the base class is subject to change — every time you add a property to the base class, the constructor needs to be changed too, so this solutions is inelegant.
I have searched online, and can't see any reason for why this kind of type-casting isn't implemented. The arguments I have seen so far describe this operation to 'not make any sense' (making a minivan from a car was an analogy I saw), question what to do about the non-inherited variables in the subclass, or claim that there must be some better solution for what was trying to be achieved.
As far as I can see, the operation doesn't need to 'make sense' as long as it's useful, so that isn't much of a good reason. What's wrong with adding a few more properties (and perhaps methods/overriding them) to change an instance into a subclass? In the case of the non-inherited variables, that can simply be solved by allowing this kind of type-cast only a constructor is added to the subclass or by just simply setting them to their default values. After all, constructors usually call MyBase.New(...) anyway. What's the difference between using the constructor of the base (essentially creating a new instance of the base) and using an instance which is already initialised? Lastly, I don't think the third argument is well-justified — there are times when all of the other solutions are inelegant.
So finally, is there any other reason for why this kind of casting isn't allowed, and is there an elegant way to circumvent this?
Edit:
Since I don't know a lot about this topic, I think I meant to say 'convert' rather than 'cast'. I'll also add an example to show what I'm trying to succeed. The conversion would only be allowed at the initialisation of the Subclass:
Class BaseClass
Dim x as Integer
Dim y as Integer
End Class
Class Subclass1 : Inherits BaseClass
Dim z as Integer
Sub New(Byval value As Integer)
'Standard initialisation method
MyBase.New()
z = value
End Sub
Sub New(Byval value As Integer, Byval baseInstance As BaseClass)
'Type conversion from base class to subclass
baseInstance.passAllproperties()
'This assigns all properties of baseInstance belonging to BaseClass to Me.
'Properties not in BaseClass (eg. if baseInstance is Subclass2) are ignored.
z = value
End Sub
End Class
Class Subclass2 : Inherits BaseClass
Dim v As Integer
End Class
What you describe is not casting. Have you ever heard the expression"to cast something in a different light"? It means to look at the same thing in a different way or to make the same thing look different. That is the exact way that the term "cast" is used in programming. When you cast, you do NOT change the type of the object but only the type of the reference used to access the object. If you want to cast from a base type to a derived type then the object you're referring to has to actually be that derived type. If it's not then you're not performing a cast but rather a conversion.
So, why can't you convert an instance of a base type to an instance of a derived type. Well, why would you be able to? Yes, it's something that might save writing a bit of code on occasion but does it actually make sense? Let's say that you have a base type with one property and a derived type that adds another property. Let's also say that that derived type has constructors that require you to provide a value for that second property. You're suggesting that the language should provide you with a way to magically convert an instance of the base class into an instance of the derived class, which would mean it would have to slow you to circumvent that rule defined by the author via the constructors. Why would that be a good thing?
Use System.Reflection to iterate over properties and fields of the base class and apply them to the derived class. This example includes a single public property and single public field, but will also work with multiple private/protected properties and fields. You can paste the entire example into a new console application to test it.
Imports System.Reflection
Module Module1
Sub Main()
Dim p As New Parent
p.Property1 = "abc"
p.Field1 = "def"
Dim c = New Child(p)
Console.WriteLine("Property1 = ""{0}"", Field1 = ""{1}""", c.Property1, c.Field1)
Console.ReadLine()
End Sub
Class Parent
Public Property Property1 As String = "not set"
Public Property Field1 As String = "not set"
End Class
Class Child
Inherits Parent
Public Sub New(myParent As Parent)
Dim fieldInfo = GetType(Parent).GetFields(BindingFlags.NonPublic _
Or BindingFlags.Instance)
For Each field In fieldInfo
field.SetValue(Me, field.GetValue(myParent))
Next
Dim propertyInfo = GetType(Parent).GetProperties(BindingFlags.NonPublic _
Or BindingFlags.Instance)
For Each prop In propertyInfo
prop.SetValue(Me, prop.GetValue(myParent))
Next
End Sub
End Class
End Module
Output:
Property1 = "abc", Field1 = "def"
This solution is automated, so you won't need to change anything when adding or removing properties and fields in the base class.
In general, because of this:
Class TheBase
End Class
Class Derived1 : TheBase
Sub Foo()
End Sub
End Class
Class Derived2 : TheBase
Sub Bar()
End Sub
End Class
Sub Main()
Dim myDerived1 As New Derived1
' cast derived to base
Dim myTheBase = CType(myDerived1, TheBase)
' cast base to derived?
' but myTheBase is actually a Derived1
Dim myDerived2 As Derived2 = CType(myTheBase, Derived2)
' which function call would you like to succeed?
myDerived2.Foo()
myDerived2.Bar()
End Sub

Need help understanding Generics, How To Abstract Types Question

I could use some really good links that explain Generics and how to use them. But I also have a very specific question, relater to working on a current project.
Given this class constructor:
public class SecuredDomainViewModel<TDomainContext, TEntity> : DomainViewModel<TDomainContext, TEntity>
where TDomainContext : DomainContext, new()
where TEntity : Entity, new()
public SecuredDomainViewModel(TDomainContext domainContext, ProtectedItem protectedItem)
: base(domainContext)
{
this.protectedItem = protectedItem;
}
And its creation this way:
DomainViewModel d;
d = new SecuredDomainViewModel<MyContext, MyEntityType>(this.context, selectedProtectedItem);
Assuming I have 20 different EntityTypes within MyContext, is there any easier way to call the constructor without a large switch statement?
Also, since d is DomainViewModel and I later need to access methods from SecuredDomainViewModel, it seems I need to do this:
if (((SecuredDomainViewModel<MyContext, MyEntityType>)d).CanEditEntity)
But again "MyEntityType" could actually be one of 20 diffent types. Is there anyway to write these types of statements where MyEntityType is returned from some sort of Reflection?
Additional Info for Clarification:
I will investigate ConstructorInfo, but I think I may have incorrectly described what I'm looking to do.
Assume I have the DomainViewModel, d in my original posting.
This may have been constructed via three possible ways:
d = new SecuredDomainViewModel<MyContext, Order>(this.context, selectedProtectedItem);
d = new SecuredDomainViewModel<MyContext, Invoice>(this.context, selectedProtectedItem);
d = new SecuredDomainViewModel<MyContext, Consumer>(this.context, selectedProtectedItem);
Later, I need to access methods on the SecuredDomainViewModel, which currently must be called this way:
ex: if (((SecuredDomainViewModel<MyContext, Order)d).CanEditEntity)
ex: if (((SecuredDomainViewModel<MyContext, Invoice)d).CanEditEntity)
ex: if (((SecuredDomainViewModel<MyContext, Consumer)d).CanEditEntity)
Assuming I have N+ entity types in this context, what I was hoping to be able to do is
something like this with one call:
ex: if (((SecuredDomainViewModel<MyContext, CurrentEntityType)d).CanEditEntity)
Where CurrentEntityType was some sort of function or other type of call that returned Order, Invoice or Consumer based on the current item entity type.
Is that possible?
You can create a non-generic interface that has the CanEditEntity property on it, make SecuredDomainViewModel inherit off that, then call the property through the interface...
Also, the new() constructor allows you to call a constructor on a generic type that has no arguments (so you can just write new TEntity()), but if you want to call a constructor that has parameters one handy trick I use is to pass it in as a delegate:
public void Method<T>(Func<string, bool, T> ctor) {
// ...
T newobj = ctor("foo", true);
// ...
}
//called later...
Method((s, b) => new MyClass(s, b));
I can't help on the links, and likely not on the type either.
Constructor
If you have the Type, you can get the constructor:
ConstructorInfo construtor = typeof(MyEntityType).GetConstructor(new object[]{TDomainContext, ProtectedItem});
Type
I'm not really sure what you're looking for, but I can only see something like
if (((SecuredDomainViewModel<MyContext, entityType>)d).CanEditEntity)
{
entityType=typeof(Orders)
}
being what you want.