Custom Agent constructors?

I’d like to preprocess the parameters that are passed to an Agent upon construction. How would I go about that?

A simple example of what I’d like to do:

function make_set(t::Union{Nothing, Symbol, Set{Symbol}})
  if t === nothing
    return Set{Symbol}()
  elseif t isa Symbol
    return Set([t])
  else
    return t
  end
end

@agent struct TestAgent(NoSpaceAgent)
   types::Set{Symbol} = make_set(types)
 end

But that doesn’t work. The code compiles fine but when I then execute:

TestAgent(id = 1, types = :test)

I get the following error:
ERROR: MethodError: Cannot convert an object of type Symbol to an object of type Set{Symbol}

Closest candidates are:
convert(::Type{T}, ::T) where T<:AbstractSet
@ Base set.jl:550
convert(::Type{T}, ::T) where T
@ Base Base.jl:84
convert(::Type{T}, ::AbstractSet) where T<:AbstractSet
@ Base set.jl:551

Is there a solution for this?

Thanks in advance,
Stef

Hi Stef.

Unfortunately, I’m not aware of a good way to achieve what you’re looking for. The closest I can manage is creating a helper function which calls your agent constructor as follows:

TestAgent_helper(; kwargs...) = begin
    types = get(kwargs, :types, nothing)
    TestAgent(; kwargs..., types=make_set(types))
end

You can check that the following calls work correctly

TestAgent_helper(; id=1, types=:test) # types will be Set([:test])
TestAgent_helper(; id=1) # types will be Set{Symbol}()

It’s still not clear to me why what you’re after would be desirable. Is there a reason in your use case why processing your types data before calling the constructor would be inconvenient? Perhaps there are other ways to address the issues you are facing without adding extra logic into or around the agent constructor.

You didn’t ask for an explanation of the error, but I’ll give one below just in case.

What your code does is set the default value of types to be make_set(types)
You get an error because when you pass in a value for types it is used instead of the default value, and it is not of the specified type. Your default value would also error if you called the agent constructor without specifying types since types is not defined anywhere else.

Hope this is useful. Regards,

Paolo

2 Likes

The main reason why I want to do this is to make it easier to use the code. Writing

TestAgent(types = :aType)

is just less cumbersome than having to write

TestAgent(types = Set([:aType]))

all the time :wink:

Thank you for the explanation. That definitely helps.

Kind regards,
Stef

1 Like