3
\$\begingroup\$

I have very basic principle. I have multiple types of entities with some shared functionality. Some of this functionality is highly customizable and you want to be able to swap it out even for a single type.

For example, I have an "Entity" type and subtypes "SmartAgent" and "Agent".

Their instances may or may not have the same functionality for movement and therefore movement has multiple implementations. If I was using OOP, I would just pass each one an instance of movement implementation, which does this for me. For example, one object could be given "just fly there, ignore obstacles", and others be given "move using waypoints" or "use pathfinding and then move".

This is the concept I am trying to implement in Julia (just starting with this language) and this is as far as I got. The entity type has get_movement() method, which returns Movement type and that one is used for multiple dispatching in function movement(entity::Entity, movement_type::Movement).

What I especially don't like:

  • Movement (and subtypes) don't have any fields and can be singletons.
  • Its value makes no sense and is never read.
  • I have to redefine fields and "getters" for Entity type in its subtypes, but I learned this is just how it goes in Julia.

There are also likely other design mistakes in the code as I am a Julia noob (like the usage of typing); please comment on that too.

using Test

abstract type Entity
end

abstract type Movement
end

struct MoveByMomentum <: Movement
end
struct NoMovement <: Movement
end

mutable struct Agent <: Entity
    position::AbstractArray{AbstractFloat}
    momentum::AbstractArray{AbstractFloat}
    movement::Movement
end

mutable struct SmarterAgent <: Entity
    position::AbstractArray{AbstractFloat}
    momentum::AbstractArray{AbstractFloat}
    movement::Movement
end

function get_position(entity::Entity)
    return entity.position
end

function get_momentum(entity::Entity)
    return entity.momentum
end

function get_movement(entity::Entity)::Movement
    return entity.movement
end

function update_position(entity::Entity, position::AbstractArray{AbstractFloat})
    entity.position = position
end


function move_by_momentum(entity::Entity)
    position = get_position(entity)
    momentum = get_momentum(entity)
    new_position::AbstractArray{AbstractFloat} = position + momentum
    update_position(entity, new_position)
end

function no_movement(entity::Entity)
    # we don't move
end

function movement(entity::Entity, movement_type::Movement)
    error("unimplemented")
end

function movement(entity::Entity, movement_type::MoveByMomentum)
    move_by_momentum(entity)
end


function movement(entity::Entity, movement_type::NoMovement)
    # we don't move
end

function move(entity::Entity)
    movement(entity, get_movement(entity))
end


@testset "Agents that move by their momentum" begin
    agent = Agent([0, 0], [1, 1], MoveByMomentum())

    @test agent.position == [0.0, 0.0]
    move(agent)
    @test agent.position == [1.0, 1.0]        
end

@testset "Agents that cannot move" begin
    agent = Agent([0, 0], [1, 1], NoMovement())

    @test agent.position == [0.0, 0.0]
    move(agent)
    @test agent.position == [0.0, 0.0]
end
\$\endgroup\$
3
  • \$\begingroup\$ @J_H The comment you provided is a good start to an answer. \$\endgroup\$
    – pacmaninbw
    Feb 3, 2023 at 14:39
  • \$\begingroup\$ "There are also other mistakes in the code" If the code not woking, it´s off topic. \$\endgroup\$
    – convert
    Feb 5, 2023 at 22:09
  • 1
    \$\begingroup\$ Code is executable and working as expected, mistakes are in nature of design and idiomacy. \$\endgroup\$
    – K.H.
    Feb 5, 2023 at 23:19

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.