Reputation: 11
I have 2 classes: one with 2 properties and one with an array. I want to make an array of objects of the first class.
The example compiles, but gives a wrong answer. Why?
[indent=4]
class data
prop first_name : string = " "
prop last_name : string = " "
class Arr : Object
person : data
dataset : array of data[]
init
person = new data()
dataset = new array of data[3]
def date_input()
print "\n data input \n"
person.first_name = "Egon"
person.last_name = "Meier"
dataset[0] = person
print dataset[0].first_name + " " + dataset[0].last_name
person.first_name = "John"
person.last_name = "Schneider"
dataset[1] = person
print dataset[1].first_name + " " + dataset[1].last_name
person.first_name = "Erwin"
person.last_name = "Müller"
dataset[2] = person
print dataset[2].first_name + " " + dataset[2].last_name
def date_output()
print "\n data output \n"
for i : int = 0 to 2
print dataset[i].first_name + " " + dataset[i].last_name
init
Intl.setlocale()
var a = new Arr()
a.date_input()
a.date_output()
Upvotes: 1
Views: 132
Reputation: 4289
The fundamental problem is you are referring to the same person three times, but changing their name each time. In Genie there are both value types and reference types. Value types are simpler and automatically copied on assignment. For example:
[indent=4]
init
a:int = 2
b:int = a
b = 3
print( "a is still %i", a )
A reference type has the advantage that it can be easily copied, Genie simply keeps a count of the references made. So to copy a reference type the reference count is increased by one, but this means that changes to the underlying object will affect all variables that refer to it:
[indent=4]
init
a:ReferenceTypeExample = new ReferenceTypeExample()
a.field = 2
b:ReferenceTypeExample = a
b.field = 3
print( "a.field is not 2, but %i", a.field )
class ReferenceTypeExample
field:int = 0
In the working example below I have made Person
a value object by using readonly
properties:
[indent=4]
init
Intl.setlocale()
var group = new Group()
print "\n data input \n"
try
group.add_person( new Person( "Egon", "Meier" ))
group.add_person( new Person( "John", "Schneider" ))
group.add_person( new Person( "Erwin", "Müller" ))
except err:GroupError
print( err.message )
print( @"$group" )
class Person
prop readonly first_name:string = ""
prop readonly last_name:string = ""
construct( first:string, last:string )
_first_name = first
_last_name = last
exception GroupError
GROUP_FULL
class Group
_people_count:int = -1
_group:new array of Person
_max_size:int = 2
construct()
_group = new array of Person[ _max_size ]
def add_person( person:Person ) raises GroupError
_people_count ++
if _people_count > _max_size
_people_count = _max_size
raise new GroupError.GROUP_FULL(
"Group is full. Maximum is %i members",
_max_size + 1
)
_group[ _people_count ] = person
print( " " + _group[ _people_count ].first_name +
" " + _group[ _people_count ].last_name
)
def to_string():string
result:string = "\n data output \n\n"
if _people_count < 0
result += " empty group"
return result
for i:int = 0 to _people_count
result += " " + _group[i].first_name + \
" " + _group[i].last_name + "\n"
return result
Some details about the code:
readonly
an error will be given when you compile the program if it tries to change a detail of Person
. In your example, if you change the properties of data
to be readonly
then the Vala compiler will warn you are trying to re-write the current objectPerson
has its data values set in the constructor and then any attempt after that to change them is an errorPerson
the property first_name
has the backing field _first_name
and it is that field that is set in the constructoradd_person()
is used that takes a Person
as a parameter. This separates the concrete data from the abstract classadd_person()
method to make sure the array doesn't go beyond its limits. If more people are added to the group than are allowed then an exception is raisedadd_person()
calls in the init
block create the Person
as part of the method call. This means a reference to a Person
object is not kept in the init
blockUpvotes: 2