JuliaDynamics/Agents.jl

Refactor signatures for overloading

Closed this issue · 4 comments

This thread made me realize that some functions are not easy to overload e.g. in 5.17 there was

move_agent!(agent::A, pos::ValidPos, model::ABM{<:ContinuousSpace{D},A}) where {D, A<:AbstractAgent}

which I wasn't able to find a way to overload with invoke.

In 6.0 it is instead

move_agent!(agent::AbstractAgent, pos::ValidPos, model::ABM{<:ContinuousSpace})

which I understood how to overload.

Maybe it is a problem of understanding, but it seemed impossible to overload that signature. So I think that changing the signatures for easier overloading can be useful.

cc. @Datseris

I am sorry, I didn't understand the problem... :D

What does "overload" mean? Does it mean to add a new signature to the function move_agent? If so, why does it matter what are the previous signatures it has?

Why is the second call signature easier to overload? I understand that it is a simpler signature, but what makes it easier to be "overloaded" (what this means not clear to me yet)?

this means to have this kind of behaviour:

# works in dev version, not in 5.17
using Agents

abstract type AbstractTurtle <: AbstractAgent end

@agent Turtle ContinuousAgent{2} AbstractTurtle begin end

function Agents.move_agent!(turtle::Turtle, pos::Agents.ValidPos, model::ABM{S}) where {S <: ContinuousSpace}
    start = turtle.pos
    invoke(Agents.move_agent!, Tuple{AbstractAgent, Agents.ValidPos, ABM}, turtle, pos, model)
    println("Turtle started at $start, ended at $(turtle.pos)")
end

model = AgentBasedModel(Turtle, ContinuousSpace((50, 50)))
agent = add_agent!(model, (1, 0))
move_agent!(agent, (1,1), model)
walk!(agent, (2.0, 2.0), model) # even if I didn't touch walk!, it calls the new move_agent!

so in this case you can change all the methods calling move_agent! in one shot (clearly you must know what you are doing though: https://docs.julialang.org/en/v1/base/base/#Core.invoke). The user in that thread gave a good enough motivation for the usefulness of such a feature in my opinion.

When you ask why is the second signature is easier to overload I'm not entirely sure but it seems to me that the signature in 5.17 is at the same level of specificity of a user definable function as above which means that Julia can't understand which one you want to use when calling move_agent!.

Okay, but isn't this issue solved in v6?