JuliaDynamics / Agents.jl

Agent-based modeling framework in Julia
https://juliadynamics.github.io/Agents.jl/stable/
MIT License
717 stars 115 forks source link

Refactor signatures for overloading #915

Closed Tortar closed 9 months ago

Tortar commented 9 months ago

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

Datseris commented 9 months ago

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)?

Tortar commented 9 months ago

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!.

Datseris commented 9 months ago

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

Tortar commented 9 months ago

For the most part yes, but we need to take a closer look at the library to be sure. There will probably be some more instances. Also I'm still not totally sure that the previous way is not overradable (but tried a bit without success) so maybe analyzing a bit more also this can be a good thing.

Il Mar 7 Nov 2023, 08:41 George Datseris @.***> ha scritto:

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

— Reply to this email directly, view it on GitHub https://github.com/JuliaDynamics/Agents.jl/issues/915#issuecomment-1797969323, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQH6VXZ3BCIQJO44ZFHSWH3YDHQ3RAVCNFSM6AAAAAA677ZXQOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTOOJXHE3DSMZSGM . You are receiving this because you authored the thread.Message ID: @.***>