I have a class X with some member variables except the database ID,
an object of X will be processed by some function and returned along with the ID
The question is what's the best data representation in this case?
I have the following options in mind
Option A:
define Class X and Class XwithID and convert X to XwithID when ID is available
Option B:
define Class X and return pair< ID , X >
Option C:
define Class X with the ID inside and throw exception if ID accessed before it is being assigned a value.
what are better options or best practice in this case?
Another option could be: have the ID property readonly, the class not creatable ( ie private or protected constructor ) and some sort of factory inside it:x.CreateOne() that assign the ID.
Related
In Kotlin's Pair data class it takes 2 values:
Pair<out A, out B>
and those values are targeted via first and second named properties:
Pair(first: A, second: B)
However, how are the first and properties targeted if these properties didn't exist (e.g. for other classes with two parameters OtherClass<Int, Int>? - Is there another way to target them?)
PS: Why is Pair a data class and not a regular class?
A and B are not properties, they are type parameters. The type parameters are then used to define properties.
This is the source code for Pair:
public data class Pair<out A, out B>(
public val first: A,
public val second: B
) : Serializable {
/**
* Returns string representation of the [Pair] including its [first] and [second] values.
*/
public override fun toString(): String = "($first, $second)"
}
You target the properties (first and second), not the type parameters.
Suppose for example you have Pair<Int, String>. This means A is Int, B is String.
first is a property of type A, second is a property of type B, therefore first is an Int and second is a String.
In answer to your 'PS', Pair is a data class because of the usual benefits this confers, e.g. a generated equals() method.
Pair repersents a generic pair of two values, think of it as a box with a divider in the middle. It doesn't care what you put in each side of the divider.
What are First and Second:
If you look at Robs Answer you'll see that Pair class has two public values, one is
name "first" and the other is named "second". It basically means that every box(Pair)
has two sides and it does not care what you put in either side, by default I have named
one side as "first" and the other side as "second" if you want something from left just
refer to it as first and if you want something from right side refer to it as second.
Doing Pair("Some Words", 99) simply means you want a box that one side holds a string and the other side holds an integer.
Doing myPair = Pair("value 1", 100) simply means you want a box that one side holds a string(value 1) and the other side holds an integer(100) and you have named this box myPair.
Since Kotlin does not care about the type of things that your putting in the box, than it is perfectly okay to add a null value to a pair, like myPair=Pair(null, 99), its your job to check if there is a null value being added or extracted from the pair.
Retrieving values:
Say you do something like var myPair = Pair("value 1", 100)
If you want to see what you are holding in myPair you can do:
println(myPair.first) -> "value 1"
println(myPair.second) -> 100
Why is Pair a data class and not a regular class?
The main purpose of a data class is to hold data.
Data classes have some restrictions so the compiler can add some standard functionality to all data classes, like eaquls(), hashCode()
Pair class is meant to hold a pair of data, therefore in can benefit from some standard functionality, like toString().
You can read the details HERE
If you take a look at how Pair is implemented, you see that it's a simple data class with two properties: first and second.
public data class Pair<out A, out B>(
public val first: A,
public val second: B
)
As a result, you can obviously access these properties with this syntax: pair.first and pair.second. The names first and second are no special keywords but simply property names.
Note that there's something special about pairs and data classes in general though, which can be observed here:
val p = Pair(1, 2)
val (f: Int, s: Int) = p
println(f) //1
println(s) //2
This technique is called destructuring and is made possible through componentX operators which are automatically generated for you if you use data classes.
If we go according to below code
class A;
int a = 10;
endclass
class B extends A;
int b = 20;
endclass
program test;
A a1;
B b1;
initial begin
b1 = new();
a1 = b1; //child class object is assigned to parent class handle
$display("Value of variable b is %x", a1.b);
end
endprogram
Then the above code results into error that "Could not find member 'b' in class 'A'"
Now my observation is that when extended class object is assigned to base class handle then simulator will check the type of handle and check whether variable is present in that class or not. As variable b is not defined in base class then it will result into error.
So I want to confirm whether my above observation is correct or incorrect?
I would welcome if anyone wants to add something to my observation, in case it's correct.
Thanks
You are correct, and it is the intended behavior in OOP languages I know (I don't especially know the one you are using, but your example is simple enough). Being able to use a variable declared by a child class would result in a violation of the object oriented principle of polymorphism (or subtyping).
I will answer you in Java, because I'm sure of the syntax in this language for the example i want to give. Imagine two variables with the same declared type :
public A buildA () {
return new B();
}
public static void main () {
A a1 = new A();
A b1 = buildA();
}
The polymorphism principle is that a1 and b1 should implement the same interface and be used indifferently. If I was allowed to access a variable's member b, since the compiler couldn't guess which is base and which is child, then it would allow the program to crash at runtime every time I access a concrete A, removing the safety net types are supposed to provide.
I would not use the terms parent and child class here. It implies you have two separate class objects.
What you describe is two different class types where one type is derived/extended from a base type. Then you declare two class variables: a1 and b1. These variables may hold a handle to class object of the same type, or a handle to an object of any type extended the type of the variable. However, the compiler will not let you reference any variable or member that has not been defined by type of the class variable regardless of the type of the object the class variable currently hold a handle to.
OOP gives you the ability to interact with a class variable with the possibility of it having a handle to much more complex object without you knowing what extensions have been made to that object. But you have to assume that the object could be the same type as the class variable. The compiler enforces this as well. If you want to interact with the extended class variables, you need to use an extended class variable type.
I want to have an immutable predefined table as class variable. How do I define such a variable?
This is an old question, with a simple answer:
Just create a static method (getter) that returns constant data.
Instead of using:
data(ls_sample) = lcl_myclass=>cs_data.
Use:
data(ls_sample) = lcl_myclass=>cs_data( ).
I would create an attribute and mark it as "Read Only", You can set it via Constructor or with Set-Method.
You cannot do like this using class constants in ABAP. The documentation explicitly says that:
You can specify a start value val for the ABAP types string and
xstring only.
Constant internal tables, reference variables, and structures with not
purely character-like flat components can be assigned their initial
value by IS INITIAL only, and are therefore always initial.
As Tapio suggested, your only choice is read-only attributes, and I also suggest you to use static attributes, which can be initialized in constructor.
For example
CLASS lcl_test DEFINITION.
PUBLIC SECTION.
CLASS-DATA: itab TYPE RANGE OF i READ-ONLY.
METHODS:
constructor.
ENDCLASS.
CLASS lcl_test IMPLEMENTATION.
METHOD constructor.
itab = VALUE #( sign = 'I' option = 'BT' ( low = 1 high = 10 )
( low = 21 high = 30 )
( low = 41 high = 50 )
option = 'GE' ( low = 61 ) ).
ENDMETHOD.
ENDCLASS.
One thing that after all that time would be a workaroud is the following:
Create your list
serialize it and save it as a read-only string
create a getter that deserializes it
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.
-Edit- This is for a finance API I am designing. I am in the process of creating some empty classes, getting a feel for the general structure. My primary concern is designing a pleasant user experience without requiring a manual to explain how to use it. -End Edit-
I have been scratching my head trying to think of the best way to go about designing a specific class. I will create a general example to illustrate.
Namespace SomeNamespace
Public Class Results
Public a1 as Integer
Public a2 as Integer
...
Public b1 as Integer
...
Public z1 as Integer
End Class
End Namespace
The example above is generic, but the point is there are many values within the class. The letter in the variable name represents a similar group of results. The "a" results are similar, "b" similar, etc. I had thought to make a class for each type of result value (since they are a type of result, but separate concepts from each other) within the Results class such as...
Public Class Results
Class a
Public a1 as Integer
End Class
Class b ... End Class
End Class
The problem with this is that it is not explicit that when a person uses the class
Dim ResultObject as new SomeNamespace.Results.a()
the Results object would have to be instantiated first, because any of the sub-classes a,b, etc would rely on the Results object. But the user would see the objects a,b, etc and perhaps not know that they must create the parent object first.
I thought about making the classes separate and each constructor would create a Result object, but that seems backwards logically. Any Advice? Sorry if it was confusing.
Why not make an Abstract class Result and create an inheritance structure ResultTypeA, ResultTypeB etc.? With no details on the problem it is really hard to give a meaningfull answer.
Why not use a single 2-dimensional integer array, where the first index is the result class (i.e. letter 'a' or 'b' etc), and the second index is the result number (i.e. a1 or z2 etc)?
Two quick recommendations.
1) In classes, don't expose your fields. Only expose methods and properties. If you're using auto implemented properties this is done by just adding the Property keyword in your declaration. Otherwise, declare your field as private and the property that exposes it as public:
Public Class Foo
Private _V1 As Integer ' Backing field
Public Property V2 As Integer ' Auto Property
Public Property V1 As Integer ' With backing field
Get
Return _V1
End Get
Set (Value as Integer)
_V1 = value
End Set
End Property
End Class
2) Don't nest your class declarations. Instead of
Public Class Results
Class a
Public a1 as Integer
End Class
Class b ... End Class
End Class
Do the following:
Public Class Results
Public Property A1 As A
Public Property B1 As B
End Class
Public Class A
Public Property A1 As Integer
End Class
Public Class B
Public Property B1 As Integer
End Class
For naming conventions, you should name your properties as nouns and methods as verbs. I regarding your ordering question, I recommend starting with the category (noun) and then adding adjectives after it in increasingly specific terms:
Property NameFirst As String
Property NameLast As String
Property ContactEmail As String
Property ContactPhoneHome As String
Property ContactPhoneWork As String