Skip to content
Snippets Groups Projects
Commit 577ff86d authored by xo30xoqa's avatar xo30xoqa
Browse files

Wrote `getproperty()` and `setproperty!()` for the Animal type

This allows us to get rid of the annoying `animal.traits["traitname"]`
syntax and replace it with the much simpler `animal.traitname`.
parent f6942e8b
No related branches found
No related tags found
No related merge requests found
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
Animal Animal
This is the generic agent type for all animals. Species are differentiated This is the generic agent type for all animals. Species are differentiated
by trait dictionaries passed by them during initialisation. by trait dictionaries passed by them during initialisation. (Note that each
trait variable can still be accessed as if it were a normal field name,
i.e. the trait `phase` can be accessed and modified with `animal.phase`.)
""" """
@agent Animal GridAgent{2} begin @agent Animal GridAgent{2} begin
#XXX is it (performance-)wise to use a dict for the traits? #XXX is it (performance-)wise to use a dict for the traits?
...@@ -22,11 +24,29 @@ by trait dictionaries passed by them during initialisation. ...@@ -22,11 +24,29 @@ by trait dictionaries passed by them during initialisation.
# to deepcopy the speciesdict. # to deepcopy the speciesdict.
traits::Dict{String,Any} traits::Dict{String,Any}
sex::Sex sex::Sex
age::Int32 age::Int
end
# Overloading the `getproperty` and `setproperty!` methods for `Animal` allows
# us to write `animal.property` instead of `animal.traits["property"]`.
# (This is inspired by Agents.jl in `model.jl`.)
function Base.getproperty(animal::Animal, s::Symbol)
if s in fieldnames(Animal)
return getfield(animal, s)
else
return animal.traits[String(s)]
end
end
function Base.setproperty!(animal::Animal, s::Symbol, x)
if s in fieldnames(Animal)
setfield!(animal, s, x)
else
animal.traits[String(s)] = x
end
end end
#TODO If I write a `getproperty` method for `Animal`, I could get around the ugly
# `animal.traits[property]` syntax (like Agents.jl does in `model.jl`).
""" """
animalid(animal) animalid(animal)
...@@ -34,7 +54,7 @@ end ...@@ -34,7 +54,7 @@ end
A small utility function to return a string with the species name and ID of an animal. A small utility function to return a string with the species name and ID of an animal.
""" """
function animalid(a::Animal) function animalid(a::Animal)
return "$(a.traits["name"]) $(a.id)" return "$(a.name) $(a.id)"
end end
""" """
...@@ -44,7 +64,7 @@ Update an animal by one day, executing it's currently active phase function. ...@@ -44,7 +64,7 @@ Update an animal by one day, executing it's currently active phase function.
""" """
function stepagent!(animal::Animal, model::AgentBasedModel) function stepagent!(animal::Animal, model::AgentBasedModel)
animal.age += 1 animal.age += 1
animal.traits[animal.traits["phase"]](animal,model) animal.traits[animal.phase](animal,model)
end end
""" """
...@@ -150,7 +170,8 @@ such phase, and the conditions under which the animal transitions to another pha ...@@ -150,7 +170,8 @@ such phase, and the conditions under which the animal transitions to another pha
animal is in the relevant phase. When it is called, it has access to the following animal is in the relevant phase. When it is called, it has access to the following
variables: variables:
- `animal` a reference to the animal itself. This provides access to `animal.age`, - `animal` a reference to the animal itself. This provides access to `animal.age`,
`animal.sex`, and `animal.traits` (a dict that gives access to all species parameters). `animal.sex`, and `animal.<trait>` (where <trait> is a variable that was defined
in the top part of the species definition body).
- `pos` gives the animal's current position as a coordinate tuple. - `pos` gives the animal's current position as a coordinate tuple.
- `model` a reference to the model world (an object of type `AgentBasedModel`). - `model` a reference to the model world (an object of type `AgentBasedModel`).
This allows access to `model.date` (the current simulation date) and This allows access to `model.date` (the current simulation date) and
...@@ -187,12 +208,7 @@ macro trait(traitname) ...@@ -187,12 +208,7 @@ macro trait(traitname)
# (i.e. outside of a @phase block). Although this is specified in the documentation, # (i.e. outside of a @phase block). Although this is specified in the documentation,
# it is unexpected and liable to be overlooked. Can we add a third clause to # it is unexpected and liable to be overlooked. Can we add a third clause to
# compensate for that? # compensate for that?
#TODO replace with `animal.traitname` syntax using `getproperty()`/`setproperty!()`
if traitname in fieldnames(Animal)
:($(esc(:animal)).$(traitname)) :($(esc(:animal)).$(traitname))
else
:($(esc(:animal)).traits[$(String(traitname))])
end
end end
""" """
...@@ -202,7 +218,7 @@ Switch this animal over to a different phase. This can only be used nested withi ...@@ -202,7 +218,7 @@ Switch this animal over to a different phase. This can only be used nested withi
""" """
macro setphase(newphase) macro setphase(newphase)
#XXX make this usable in the top part of a species definition? #XXX make this usable in the top part of a species definition?
:($(esc(:animal)).traits["phase"] = $(String(newphase))) :($(esc(:animal)).phase = $(String(newphase)))
end end
""" """
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment