I want to implement a small class in Pharo so I have done this:
Object subclass: #Person
instanceVariableNames: 'name age'
classVariableNames: ''
category: 'Test'
and I want to simulate a constructor so I have made a method like the following:
newName:aName newAge:aAge
"comment stating purpose of message"
name:=aName.
age:=aAge.
^self.
but when I want to call it from the playground in Pharo like this:
objPerson:=Person newName:'Carl' newAge: 10.
it is not recognized by Pharo, what am I doing wrong?
The expression Person newName: 'Carl' newAge: 10 is a message to the class object Person. Therefore you have to implement it on the class side of Person.
Your code needs to be tweaked like this
Person class >> newName: aName newAge: anAge
| person |
person := self new.
person name: aName.
person age: anAge.
^person
Note that in the code above self refers to the class because the method is on the class side. But since person is an instance of Person, the messages name: aName and age: anAge have to be defined on the instance side.
Therefore, on the instance side, you need to add the two setters:
Person >> name: aString
name := aString
Person >> age: anInteger
age := anInteger
With these three methods you should be able to run your example.
Some additional comments on the coding style:
Firstly, I would have chosen a different selector for the "constructor" method (in Smalltalk we call these "instance creation" methods). For instance,
Person class >> named: aString age: anInteger
^self new name: aString; age: anInteger
Secondly, there is no need to use the temporary person for the newly created instance as the expression self new already refers to such an instance.
Finally, note the use of the cascade syntax in
^self new name: aString; age: anInteger
which means that the message age: anInteger will be sent to the same receiver that name: aString, which in this case happens to be the new instance returned by self new.
Although in general I agree with Leandro's answer, it exposes accessors to the private properties.
Kent Beck in his Smalltalk Best Practice Patterns (which I highly recommend), proposes to use set as a prefix for the instance-side constructor, e.g.:
"add to class side to 'instance creation' protocol"
Person>>class name: aName age: anAge
^ self new
setName: aName age: anAge;
yourself
"add to instance side to 'initialization' protocol"
Person>>setName: aName age: anAge
name := aName.
age := anAge.
This way you can control whether you will or will not expose the properties.
Or you could stick with your original naming and just add new, which you forgot.
objPerson := Person new newName:'Carl' newAge: 10.
Related
Indeed it is within the framework of a research. I'm trying to generate random values for the instance variables of an X object. So when instantiating the object, I replace the parameters of the object initialization method with the values that are generated.
So, I manage to retrieve instance variables, generate random values. The problem now is how to replace the arguments of the initialization method with the generated values?
we have my Person class
Object subclass: #Person
instanceVariableNames: 'name lastName birthDate'
classVariableNames: ''
package: 'Moi'
the method that i use to initialize a person is:
withName: aName andBirthDate: aBirthDate andLastName: aLastName
name:= aName.
lastName:= aLastName.
birthDate:= aBirthDate
For example I have the method
Person>>#withName:aName andBirthDate:aBirthDate andLastName:aLasatName
and I have the following values:
"toto", "13 sept 2022" and "tata"
How to override or rebuild method like this
Person>>#withName:'toto' andBirthDate:'13 Sep 2022'andLastName:'tata'?
```bri
the Person class is an example. Instead of the Person class, we can have Point, Car or any other class.
No, you will need to call the constructor and break out the arguments:
Person
withName: (list at: 1)
lastName: (list at: 2)
birthDay: (list at: 3)
So I started learning Kotlin today and got to Classes when I noticed something weird.
When I run this code:
fun main() {
val dog_1 = Dog("Walrek", 7)
}
open class Animal(
open val type: String,
open val name: String,
open val speed: Int,
) {
init {
println("(Ani init) New animal: $type called $name with $speed speed")
}
}
class Dog(
override val name: String,
override val speed: Int,
): Animal("Dog", name, speed) {}
The init method will print out: (Ani init) New animal: Dog called null with 0 speed.
At first I thought I messed up somewhere and somehow I'm not passing the arguments properly into the Animal class, but then I added these two lines of code:
init {
println("(Dog init) New animal: $type called $name with $speed speed")
}
into Dog class, and
println(dog_1.name)
in the main function, and got this as an output:
(Ani init) New animal: Dog called null with 0 speed
(Dog init) New animal: Dog called Walrek with 7 speed
Walrek
So now my question is, why weren't the parameters passed into the Animal class, and yet I can access them as usual after creating the Dog instance?
You should be getting a compiler warning. You should never use open properties or functions at construction time (in init blocks or property declarations), because it causes this kind of unwanted behavior. It's just about the only way you can get a NullPointerException in Kotlin without using !!.
The reason it happens is that the superclass's constructor (which includes init blocks and property declarations) is run before the subclass. Since you override the property name in the subclass, the backing field of the property name has not yet been initialized by the time init of the superclass is called, so the property returns the default Java field value of null. In the case of speed, the field type is a Java primitive int so its default value is 0.
Note that in your specific example, there was no need to override these properties because you are passing these values to the superconstructor anyway. You could remove the open keyword before the properties and declare your Dog like:
class Dog(
name: String,
speed: Int,
): Animal("Dog", name, speed) {}
Then it will behave properly.
This question already has answers here:
Constructors in Go
(10 answers)
Closed 2 years ago.
Abstract & Codes
I'm learning Golang and Nim which don't have class but has struct, and new to these kind of language. Being used to OOP I tried to make a class-like thing using struct but found that struct's fields are optional. I want to turn them mandatory in order to write strict code.
JAVA
class Person {
String Name
int Age
Person(String Name, int Age) {
this.Name = Name;
this.Age = Age;
}
}
// Ok
Person p1 = new Person("John Doe", 30);
// FAILS
Person p2 = new Person("John Doe");
Golang
type Person struct {
Name string
Age int
}
// Ok
p1 := Person{
Name: "John Doe",
Age: 30,
}
// Ok
p2 := Person{
Name: "John Doe",
}
One of the solution is to implement a function that initializes struct; if arguments are not entirely passed it fails.
Golang
func newPerson(Name string, Age int) Person {
return Person{
Name: Name,
Age: Age,
}
}
// Ok
p1 := newPerson("John Doe", 30)
// FAILS
p2 := newPerson("John Doe")
Question
I feel the above solution redundant because init function has to come along with each struct. Is this method popular or there's better solution?
In Golang, you can have constructor-like factory functions (like the one you defined above) to initialize default values when initializing structs.
Yes, this is the correct solution and there are several advantages of choosing such solution. I have listed down some of them:
You will implement a factory function only when necessary thus avoid unnecessary typing.
Have complete control on the object construction i.e. if initialization doesn't succeed you can comfortably return an error by having function signature as func newPerson(Name string, Age int) (Person, error). In a constructor this is not possible.
Implementing constructors in other languages is no different from implementing factory functions in Golang.
Apart from the above advantages, since you can directly instantiate struct where ever necessary, factory functions help in avoiding repetition for initializing default values.
Lets say I've created a class MyClass in Pharo Smalltalk...
If I in Workspace write:
MyClass new.
and select print-it (Ctrl-P), I get:
A MyClass
With a bit of tinkering with MyClass's printOn: method,
I could get a bit more, for example:
A MyClass with value: 5
+++
So comes my question... How can I make a test (instance of TestCase-class)
that checks that the textual-representation of MyObject - what I would get
if I did "MyObject new" and Print-It - is what it's supposed to be?
How do I get the textual representation so I can check it against a
string-constant with what it should be, when I do a self assert: equal: (or something similar) in my test?
For example that after using my cutomized printOn: method, it will
look something like
A MyClass with value: 5
Sorry for such a newbie question, but there goes...
To get the textual representation of an object you can send the message printString to the object. For example Object new printString will return you the string 'an Object'.
To create a test case you should create a subclass of TestCase:
TestCase subclass: #MyClassTestCase
instanceVariableNames: ''
classVariableNames: ''
package: 'MyTest-Package'
Then a test is a method that begins with test. For example the following test verifies the string representation of Object new:
testClassRepresentation
self assert: Object new printString equals: 'an Object'
I'm having trouble in getting the singleton pattern to initialize a instance variable in smalltalk. (here is a link to another implementation for clarification)
this is what I have:
new
^UniqueInstance ifNil: [UniqueInstance := self basicNew.
UniqueInstance: instanceVar := Object new. ].
that last line (UniqueInstance: instanceVar := Object new.) doesn't work, but that's basically what I need to do: instantiate instanceVar as an Object before returning UniqueInstance back to the caller.
Notice that this 'new' method is used as a classinstantiation, and that libraries is a instance variable of UniqueIsntance (the isntance of the wanted class).
Can anyone point me in the right direction?
Try simpler:
YourClass class>>singleton
UniqueInstance ifNil: [UniqueInstance := self basicNew initialize].
^UniqueInstance
then on instance side of your class implement an appropriate #initialize method, for example:
YourClass>>initialize
someInstvar := someInitalValue.
^self
Update:: Name of the class method accessing the singleton varies, it can be #default, #current, or #singleton. I mostly use later.