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
Branches
Tags
No related merge requests found
......@@ -13,7 +13,9 @@
Animal
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
#XXX is it (performance-)wise to use a dict for the traits?
......@@ -22,19 +24,37 @@ by trait dictionaries passed by them during initialisation.
# to deepcopy the speciesdict.
traits::Dict{String,Any}
sex::Sex
age::Int32
age::Int
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`).
# 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
"""
animalid(animal)
A small utility function to return a string with the species name and ID of an animal.
"""
function animalid(a::Animal)
return "$(a.traits["name"]) $(a.id)"
return "$(a.name) $(a.id)"
end
"""
......@@ -44,7 +64,7 @@ Update an animal by one day, executing it's currently active phase function.
"""
function stepagent!(animal::Animal, model::AgentBasedModel)
animal.age += 1
animal.traits[animal.traits["phase"]](animal,model)
animal.traits[animal.phase](animal,model)
end
"""
......@@ -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
variables:
- `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.
- `model` a reference to the model world (an object of type `AgentBasedModel`).
This allows access to `model.date` (the current simulation date) and
......@@ -187,12 +208,7 @@ macro trait(traitname)
# (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
# compensate for that?
#TODO replace with `animal.traitname` syntax using `getproperty()`/`setproperty!()`
if traitname in fieldnames(Animal)
:($(esc(:animal)).$(traitname))
else
:($(esc(:animal)).traits[$(String(traitname))])
end
:($(esc(:animal)).$(traitname))
end
"""
......@@ -202,7 +218,7 @@ Switch this animal over to a different phase. This can only be used nested withi
"""
macro setphase(newphase)
#XXX make this usable in the top part of a species definition?
:($(esc(:animal)).traits["phase"] = $(String(newphase)))
:($(esc(:animal)).phase = $(String(newphase)))
end
"""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment