I’m translating some Python code to Julia and am trying to figure out how to map the usage of class methods to Julia. See below for a Python-style outline of what I’m porting. There’s a single abstract class with one or more concrete subclasses. Each concrete subclass implements an action that is applied to a state (it’s code from a game simulation). One particular thing is that each subclass can generate actions of its type from the current game state, which is what generate() does. It returns a list of one or more actions that can later be applied to a state by calling execute() on the instance, passing the state to apply to.
ACTION_CONCRETE_A = 1
ACTION_CONCRETE_B = 2
...
class AbstractAction:
    def __init__(self, type, ...):
        # Hold some general fields
        self.type = type
        ....
        
class ConcreteActionA(AbstractAction):
    @classmethod
    def generate(cls, state, ...):
        # Returns a list of one or more instances
        # of ConcreteAction possible in this state
        return [ConcreteActionA(...), ...]
        
    def __init__(self, ...):
        AbstractAction.__init__(self, ACTION_CONCRETE_A, ...)
        # Action specific fields
        ...
        
    def execute(self, state):
        # Apply the action to a state
        ...
state = <game state>
actions = ConcreteActionA.generate(state)
# Pick a random action and execute it
action = random.choice(actions)
action.execute(state)
Porting the class structure doesn’t seem to be too hard (apart from the composition versus forwarding choice), including the constructor and execute() method, something like this:
@enum ActionType
    ACTION_CONCRETE_A
    ....
end
abstract type AbstractAction end
mutable struct ConcreteActionA <: AbstractAction
    type::ActionType
    # ...more action-specific fields
    function ConcreteActionA(...)
        obj = new(ACTION_CONCRETE_A)
        # Initialize other fields....
        return obj
    end
end
function execute(action::ConcreteActionA, state::State)
    # ....
end
But what’s a good way to port generate()? Ideally I would be able to call
actions = generate(ConcreteActionA, state)
but I’m having trouble figuring out how to dispatch on a struct type (in contrast to a struct value), as I have many different forms of generate(), one for each action type. I looked into symbols to see if those could be usable here (e.g. :ConcreteAction), but I’m not clear whether that is a good method.
Any hints?
