Pharo: Refers to class name instead of "self class" - smalltalk

I have a simple class Amount with the fields value and unit and corresponding accessors. Now I want to create a class method for constructing amount objects like this:
value: aValue unit: anUnit
| amount |
amount := Amount new .
amount value: aValue ; unit: anUnit .
^ amount
I get the warning message Refers to class name instead of "self class". How can I improve this? I tried amount := (self class) new but then I get the error A Metaclass should only have one instance!. (Note that I am very new to Pharo and Smalltalk)

Refers to class name instead of "self class"
is a hint, that suggests you use
amount := self new.
instead of
amount := Amount new.
As your method is a class method, self refers to the class.
In a class method, (self class) new would (in your example) be the same as Amount class new. The class of a class (Amount) is a Metaclass, thus the error message you quoted.

Related

squeak(smalltalk) how to get all the methods of an object (inherited methods too)

how can I get a list of all the methods an object can understand?
for example:
set := 8 getAllMethods
will give me all methods 8 can understand in set
In code you can use allSelectors:
set := 8 class allSelectors
gives you a set of all the names of messages (a. k. a. selectors) that 8 can understand.
If you need the CompiledMethods instead of only the message names, you can use lookupSelector:
| class |
class := 8 class. "will be SmallInteger"
set := class allSelectors collect: [:each | class lookupSelector: each]
If you don't want to do this in code but rather find out in the IDE which messages an object can understand, then I propose to use the protocols browser (a. k. a. Lexicon tool). You can open it via "browse protocol" from the context menu of a class:
I used it to find allSelectors and lookupSelector:, which are inherited from Behavior and not defined in Class itself.
This is interesting because of the following. At first glance one might be tempted to consider an expression like this one
anObject class withAllSuperclasses gather: [:class | class methodDictionary]
which gathers all the methods implemented in the class and its superclasses. However, if a method is defined in a class and in one of its superclasses, we should ignore the latter because anObject will use the one in the class.
To remedy this side-effect of the above script we need to gather only the methods that are defined in the class which is closer to anObject class. One way to do this is to enumerate the classes from top to bottom, adding all their methods to a Dictionary. Since the dictionary will only retain the last element added to a given key (in this case a selector), only the ones that belong in the protocol of anObject will survive:
methods := Dictionary new.
anObject class withAllSuperclasses reverseDo: [:class |
methods addAll: class methodDictionary associations].
Note the use of reverseDo: for enumerating the classes downwards.
Another approach would be to enumerate the classes from bottom to top, checking whether the selector has already been visited:
methods := Dictionary new.
anObject class withAllSuperclasses do: [:class |
class methodDictionary do: [:cm |
methods at: cm selector ifAbsentPut: [cm]]]
(were cm stands for CompiledMethod)
The second version is a bit longer, more complex (it has two loops, one nested inside the other) and needs conditional logic (#at:ifAbsentPut:). In other words, it shouldn't be the one chosen.
Note
When looking for ways to create a collection (in this case the collection of all methods understood by an object), first make sure you really need such a collection. For instance, you will need the collection if you want to display it on the screen. However, if you are only going to use the collection for membership checking, there might be other ways to proceed. In your case, you could simply ask the object:
anObject respondsTo: <selector>
and in case the answer is true, recover the method using
anObject class lookupSelector: <selector>.
This is both simpler and more efficient because it doesn't create collections, etc.

Calling methods in pharo smalltalk

I'm trying to call a function from another class (Binario) but it says it's not implemented.
This is the code for the method in Binario class:
genlista
^ (1 to: 30) collect: [ :i | 2 atRandom - 1 ]
And this is the code for the other class method:
ListadelistasBin
| bin |
bin := Binario new.
^ (1 to: 30) collect: [ :i | bin genlista ]
Please, help me :(
Most likely #Uko is right and you defined the method in the class side of Binario rather than in the instance side. One way to check this would be to modify your second method like this:
ListadelistasBin
| bin |
bin := Binario. "<- new removed"
^ (1 to: 30) collect: [:i | bin genlista]
If now you get the answer, then what happened is that your genlista method is in the wrong place (class side instead of instance side).
In Smalltalk every method belongs in a class. However, there are two "sides" of a class. The instance side is where you put methods for the instances of the class. The class side is where you put methods for the class itself.
How can you tell in what side of a class you have saved a method? Just look for the switch that every browser has to select one or the other side. In Pharo, for example, there is a toggle button that you use to select each of the sides.
While instance methods define the behavior of the instance of your class (and subclasses), class methods are meant to be sent to the class. This is just a consequence of classes being objects. For example, Binario new is a message sent to the class Binario, and we believe that your intention was to define the genlista method for instances of Binario. If this is the case, then copy the source code of the method and paste it on the instance side of the class. Then remove the class method and try again. Ah! and don't forget to put the new message back next to Binario in your ListadelistasBin!

Why parent class is not able to access child class member

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.

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.

Typed collections in Smalltalk

I'm trying to learn some smalltalk programming.... I'm trying to create a list of objects of type myClass. What's the best way to do this?
I have the following:
| list |
list := OrderedCollection new.
Correct me if I'm wrong.
So how should I add elements to my list?
To create new instances of MyClass send the class the message #new
MyClass new
Now, to add an element to a collection, just send the collection the message #add:
list add: MyClass new
There is no such a thing as static types in Smalltalk. In other words, the equivalent of the Java ArrayList<MyClass> is just OrderedCollection.
Before answering the It's important to emphasis that there is no strong typing in Smalltalk. Every variable is an instance of some Class of object. But the class of object can change frequently over the lifecycle of the object and neither the interpreter nor the compiler will care.
Enter the following code into the Workspace (or in the "Playground" on Pharo 4.0 and up, or the command line in GNU Smalltalk)
aNumber := 3 . "new instance of Class SmallInt is created"
aNumber := 22/7 . "aNumber is now an instance of Class Fraction"
aNumber := 3.14159 . "aNumber is now an instance of Class Float"
aNumber := 'Pi' . "aNumber is now an instance of Class ByteString"
No warnings or exceptions will be raised for any of these statements.
Now that is out of the way,
how should I add elements to my list?
This depends on the type of list you are using.
An Array is an integer-indexed list of fixed size.
An OrderedCollection is an integer-indexed list of variable size.
A Set is a collection of unique objects.
A Dictionary is a Set of Association objects, i.e. key-value pairs
A SortedCollection is a list of objects, sorted based on a sort block definition.
They each have unique methods of adding items.
The commonest methods for the standard collections are -
add: (not available for Array or String - as they cannot have their number of elements changed, after initial creation)
at:put: (not available for Set, as in effect it only contains keys, but no values)
OrderedCollection also has addFirst:, add:after:, add:before:, add:beforeIndex:
If you send an adding message to a collection, but the collection does not understand that particular message, it will raise an exception.
So, for your list
| list newElement1 newElement2 newElement3 |
list := OrderedCollection new .
newElement1 := 'ABC' . "a ByteString"
newElement2 := 123 . "a SmallInt"
newElement3 := Dictionary new .
newElement3 at: 'Doh' put: 'A deer, a female deer' ;
at: 'Ray' put: 'A drop of golden sun' ;
at: 'So' put: 'A needle pulling thread' .
list add: newElement1 ;
add: newElement2 ;
add: newElement3 .
would result in
list (an OrderedCollection) [3 items] ('ABC' 123 aDictionary [2 items] ( 'Doh'->'A deer, a female deer' 'Ray'->'A drop of golden sun'))