How do model a sub type that can fall under two different abstract types?

Suppose you’re building a medieval role playing game, you’re going to have weapons of different types, so you’ll create an abstract type called Weapon:

abstract type GameObject end
abstract type Weapon <: GameObject end

You decide that your charcters can cast spells, and spells also have different types, so you can do:

abstract type Spell <: Weapon end # Fireball, Freeze, etc...

The problem? Not every spell is considered a Weapon. Suppose you want a spell that manipulates nature, for example, a spell that makes a planet grow faster or a spell that makes spoiled food suddenly fresh again.

I could make Spell a direct sub type of GameObject, and then Nature and Defense

abstract type Spell <: GameObject end
abstract type Nature <: Spell # FreshFood, GrowPlant,etc...
abstract type Defense <: Spell # Fireball,Freeze, etc...

When you have a sub types that share attributes of different abstract types, how do you model it?

This brings to mind Eric Lippert’s Wizards and Warrriors series.

Just answered this in another thread: Why use subtypes instead of traits and duck typing? - #31 by Raf

You can do a kind of multiple inheritance with subtyped traits. Edit: But this is probably overcomplicating things normal traits are all you need here.

You could also use regular object composition and multiple dispatch.

2 Likes

My first response is to generally caution you about overusing complex type hierarchies. In
general, types should be used strictly for dispatch; until you have a function that you need
to dispatch differently for one set of types versus another, abstract parent types shouldn’t
be introduced.

But if you do need to control dispatch in a way where simple single-inheritance won’t work,
you can use a “Holy trait”:

struct HasMyTrait end
struct HasntMyTrait end

mytrait(_) = HasntMyTrait()

struct MyType end
mytrait(::MyType) = HasMyTrait()

myfunc(x) = _myfunc(x, mytrait(x))

_myfunc(x, ::HasntMyTrait) = ... # Behavior for types without trait
_myfunc(x, ::HasMyTrait) = ... # Behavior for types with trait

There are several packages that try to wrap this pattern into a macro to make it more
pleasant to use, but I’m not personally familiar enough with any of them to make a
recommendation.

3 Likes