user7450201
user7450201

Reputation: 11

array of objects in genie

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

Answers (1)

AlThomas
AlThomas

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:

  • By changing the properties to be 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 object
  • Person has its data values set in the constructor and then any attempt after that to change them is an error
  • For a simple property Genie generates an automatic backing field that starts with an underscore. For example in Person the property first_name has the backing field _first_name and it is that field that is set in the constructor
  • Instead of including the people's names in the method itself, a method called add_person() is used that takes a Person as a parameter. This separates the concrete data from the abstract class
  • Checks have been added to the add_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 raised
  • The add_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 block

Upvotes: 2

Related Questions