<commit_before>---
layout: post
title: Why Take Ecstasy
date: 2018-01-28 11:11
comments: true
tags: haskell, dsl, design, type trickery
---

 [/u/Ahri][ahri] asked on reddit about [yesterday's post][starting],

[ahri]: https://www.reddit.com/user/Ahri
[starting]: http://reasonablypolymorphic.com/blog/starting-a-game-engine

> Perhaps you could explain a little bit about your choice to write [ecstasy][ecstasy]
> rather than to use apecs? I've not used apecs, I'm just interested as I had
> done some limited research into writing games in Haskell and apecs seemed to
> have traction.

[ecstasy]: https://github.com/isovector/ecstasy

That seems like a really good idea, and combined with the fact that I really
haven't published anything about [`ecstasy`][ecstasy] suggested I actually write
about it!


## What is an ECS?

So before diving in, let's take a look at the problem an entity-component-system
(ECS) solves. Let's say we're writing a simple 2D platformer, we'll have dudes
who can run around and jump on platforms.

The way I'd go about writing this before knowing about ECS would be to implement
one feature at a time, generally using the player character to test it as I
went. I write functions that look something like this:

```haskell
moveActor :: Controller -> Actor -> Actor
moveActor ctrl actor =
  actor & actorPos +~ movingDirection ctrl
```

and then provide some types to hold all of the world together:

```haskell
data Universe = Universe
  { _uPlayer       :: Actor
  , _uPlayerCtrl   :: Controller
  , _uCurrentLevel :: Level
  }

data Level = Level
  { _lActors :: [Actor]
  }
```

and finally write some glue code to lift `moveActor` over the universe.

```haskell
updateUniverse :: Universe -> Universe
updateUniverse u@Universe{..} =
  u & uPlayer %~ moveActor _uPlayerCtrl
    & uCurrentLevel . lActors . traverse %~ moveActor someCtrl
```

On the surface this feels good. We've reused the code for `moveActor` for both
the player and any other dudes on the level who might want to walk around. It
feels like we can build up from here, and compose pieces as we go.

Which is true if you're really patient, good at refactoring, or have spent a lot
of time building things like this and know where you're going to run afoul.
Because you're always going to run afoul in software.

The problem with our first attempt at this code is that it codifies a lot of
implicit assumptions about our game. For example, did you notice that it implies
we'll always have an `Actor` for the player? It seems like a reasonable
assumption, but what if you want to play a cut-scene? Or how about if you don't
want to always have control over the player? Maybe you've just been hit by
something big that should exert some acceleration on you, and you don't want to
be able to just press the opposite direction on the control stick to negate it.

All of a sudden, as you try to code for these things, your simple `moveActor`
function takes more and more parameters about the context of the circumstances
in which it's running. And what's worse is that often the rules of how these
behaviors should play out will change depending on whether its the player or
some enemy in the level. We're left with a conundrum -- should we build
ad-hoc infrastructure around the callers of `moveActor` or should we put all of
the logic inside of it?

As you can imagine, it pretty quickly becomes a mess.

In one of the few times I'll praise object-oriented programming, I have to say
that its inheritance-based polymorphism lends itself well to this problem. You
can build more complicated and specific behaviors out of your ancestors'
behaviors. Unfortunately, this approach bucks the OOP best-practice of
"composition over inheritance."

ECS takes what I consider to be the functional-programming-equivalent of this
OOP strategy. It's fundamental stake in the ground is that rather than
representing your universe of game objects as an array-of-structs, you instead
represent it as a struct-of-arrays. Conceptually, this is a cognitive shift that
means instead of looking like this:

```haskell
data GameObject = GameObject
  { position :: V2
  , velocity :: V2
  , graphics :: Picture
  , buffs    :: [Buff]
  , notAffectedByGravity :: Bool
  }

type Universe = [GameObject]
```

you instead model the domain like this:

```haskell
data Universe = Universe
  { position :: Array V2
  , velocity :: Array V2
  , graphics :: Array Picture
  , buffs    :: Array [Buff]
  , notAffectedByGravity :: Array Bool
  }
```

This has some profound repercussions. First of all, notice that we have no
guarantee that our `Array`s are the same length, which implies that not every
`GameObject` need have all of its possible components.

All of a sudden, we can pick and choose which components an entity has.
Entities, now instead of being explicitly modeled by a `GameObject` are
implicitly defined by an `Int` corresponding to their index in all of the
arrays.

From here, we can now write specific, *global* behaviors that should manipulate
the components of an entity. We can avoid a lot of our previous ad-hoc machinery
by essentially running a `map` that performs pattern matching on only the
components we want to care about. For example, we can say that we only want to
draw entities who have both a `position` and a `graphics`. We want to apply
gravity to all entities that have a `velocity`, but *don't* have the
`notAffectedByGravity` flag.


## apecs

With an understanding of what ECS brings to the table, we're now ready to take a
look at different ways of implementing such a system. We first turn our
attention to [apecs][apecs].

[apecs]: https://github.com/jonascarpay/apecs

If we wanted to model our above `GameObject` via `apecs`, it might look
something like this:

```haskell
newtype Position = Position (V2 Double)
instance Component Position where
  type Storage Position = Map Position

newtype Velocity = Velocity (V2 Double)
instance Component Velocity where
  type Storage Velocity = Map Velocity

newtype Graphics = Graphics Picture
instance Component Graphics where
  type Storage Graphics = Map Graphics

newtype Buffs = Buffs [Buff]
instance Component Buffs where
  type Storage Buffs = Map Buffs<commit_msg>reply<commit_after>---
layout: post
title: Why Take Ecstasy
date: 2018-01-28 11:11
comments: true
tags: haskell, dsl, design, type trickery
---

 [/u/Ahri][ahri] asked on reddit about [yesterday's post][starting],

[ahri]: https://www.reddit.com/user/Ahri
[starting]: http://reasonablypolymorphic.com/blog/starting-a-game-engine

> Perhaps you could explain a little bit about your choice to write [ecstasy][ecstasy]
> rather than to use apecs? I've not used apecs, I'm just interested as I had
> done some limited research into writing games in Haskell and apecs seemed to
> have traction.

[ecstasy]: https://github.com/isovector/ecstasy

That seems like a really good idea, and combined with the fact that I really
haven't published anything about [`ecstasy`][ecstasy] suggested I actually write
about it!


## What is an ECS?

So before diving in, let's take a look at the problem an entity-component-system
(ECS) solves. Let's say we're writing a simple 2D platformer, we'll have dudes
who can run around and jump on platforms.

The way I'd go about writing this before knowing about ECS would be to implement
one feature at a time, generally using the player character to test it as I
went. I write functions that look something like this:

```haskell
moveActor :: Controller -> Actor -> Actor
moveActor ctrl actor =
  actor & actorPos +~ movingDirection ctrl
```

and then provide some types to hold all of the world together:

```haskell
data Universe = Universe
  { _uPlayer       :: Actor
  , _uPlayerCtrl   :: Controller
  , _uCurrentLevel :: Level
  }

data Level = Level
  { _lActors :: [Actor]
  }
```

and finally write some glue code to lift `moveActor` over the universe.

```haskell
updateUniverse :: Universe -> Universe
updateUniverse u@Universe{..} =
  u & uPlayer %~ moveActor _uPlayerCtrl
    & uCurrentLevel . lActors . traverse %~ moveActor someCtrl
```

On the surface this feels good. We've reused the code for `moveActor` for both
the player and any other dudes on the level who might want to walk around. It
feels like we can build up from here, and compose pieces as we go.

Which is true if you're really patient, good at refactoring, or have spent a lot
of time building things like this and know where you're going to run afoul.
Because you're always going to run afoul in software.

The problem with our first attempt at this code is that it codifies a lot of
implicit assumptions about our game. For example, did you notice that it implies
we'll always have an `Actor` for the player? It seems like a reasonable
assumption, but what if you want to play a cut-scene? Or how about if you don't
want to always have control over the player? Maybe you've just been hit by
something big that should exert some acceleration on you, and you don't want to
be able to just press the opposite direction on the control stick to negate it.

All of a sudden, as you try to code for these things, your simple `moveActor`
function takes more and more parameters about the context of the circumstances
in which it's running. And what's worse is that often the rules of how these
behaviors should play out will change depending on whether its the player or
some enemy in the level. We're left with a conundrum -- should we build
ad-hoc infrastructure around the callers of `moveActor` or should we put all of
the logic inside of it?

As you can imagine, it pretty quickly becomes a mess.

In one of the few times I'll praise object-oriented programming, I have to say
that its inheritance-based polymorphism lends itself well to this problem. You
can build more complicated and specific behaviors out of your ancestors'
behaviors. Unfortunately, this approach bucks the OOP best-practice of
"composition over inheritance."

ECS takes what I consider to be the functional-programming-equivalent of this
OOP strategy. It's fundamental stake in the ground is that rather than
representing your universe of game objects as an array-of-structs, you instead
represent it as a struct-of-arrays. Conceptually, this is a cognitive shift that
means instead of looking like this:

```haskell
data GameObject = GameObject
  { position :: V2
  , velocity :: V2
  , graphics :: Picture
  , buffs    :: [Buff]
  , notAffectedByGravity :: Bool
  }

type Universe = [GameObject]
```

you instead model the domain like this:

```haskell
data Universe = Universe
  { position :: Array V2
  , velocity :: Array V2
  , graphics :: Array Picture
  , buffs    :: Array [Buff]
  , notAffectedByGravity :: Array Bool
  }
```

This has some profound repercussions. First of all, notice that we have no
guarantee that our `Array`s are the same length, which implies that not every
`GameObject` need have all of its possible components.

All of a sudden, we can pick and choose which components an entity has.
Entities, now instead of being explicitly modeled by a `GameObject` are
implicitly defined by an `Int` corresponding to their index in all of the
arrays.

From here, we can now write specific, *global* behaviors that should manipulate
the components of an entity. We can avoid a lot of our previous ad-hoc machinery
by essentially running a `map` that performs pattern matching on only the
components we want to care about. For example, we can say that we only want to
draw entities who have both a `position` and a `graphics`. We want to apply
gravity to all entities that have a `velocity`, but *don't* have the
`notAffectedByGravity` flag.


## apecs

*EDIT 2018-01-30*: [The author of apecs has replied to this post][reply]. It's
worth reading through, as it gives a useful perspective from the other side.

[reply]: https://www.reddit.com/r/haskell/comments/7tlwtl/why_and_how_i_wrote_my_own_entity_component_system/dtgzrab/

With an understanding of what ECS brings to the table, we're now ready to take a
look at different ways of implementing such a system. We first turn our
attention to [apecs][apecs].

[apecs]: https://github.com/jonascarpay/apecs

If we wanted to model our above `GameObject` via `apecs`, it might look
something like this:

```haskell
newtype Position = Position (V2 Double)
instance Component Position where
  type Storage Position = Map Position

newtype Velocity = Velocity (V2 Double)
instance Component Velocity where
  type Storage Velocity = Map Velocity

newtype Graphics = Graphics Picture
instance Component Graphics where
  type Storage Graphics = Map Graphics

newtype Buffs = Buffs [Buff]
instance Component Buffs where
  type Storage Buffs = Map Buffs
{'fraction_non_alphanumeric': 0.06162553057695331, 'fraction_numerical': 0.0036943876748938846, 'mean_word_length': 4.242274412855377, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 7, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1115519', 'n_tokens_mistral': 3620, 'n_tokens_neox': 3397, 'n_words': 1880}