Up to Main Index                          Up to Journal for December, 2014

                    JOURNAL FOR MONDAY 22ND DECEMBER, 2014
______________________________________________________________________________

SUBJECT: Complicating the simple
   DATE: Mon 22 Dec 14:55:10 GMT 2014


NOTE: Due to one thing and another this post wasn't uploaded until Wednesday
      24th December even though it was written on Monday 22nd December :(


I've been spending a lot of time recently on WolfMUD-mini[1] with the intent of
using it to improve the main WolfMUD code. As you may remember from last time
things were going quite well. I could walk around examining things, get and
drop items and containers were working.

Since then I added a readable type. This is where things got a little sticky.
Initially I created a simple readable - a plaque - that could be read. Then I
thought to myself that this should be usable with other things and wanted to
put some writing onto the mug used in the previous example. Originally the mug
was defined as:


  MUG is a THING is an ITEM is an INVENTORY is a CONTAINER

  type container struct {
    *inventory
    *item
  }


For a readable container this becomes:


  MUG is a THING is an ITEM is an INVENTORY is a CONTAINER is READABLE

  type container struct {
    *inventory
    *item
    *readable
  }


Things were getting ugly fast :( Before I had had things like containers and
readable containers and with Go's embedding this became very easy and I could
do things like 'if r.(is.Readable) {}'. However I was ending up with things
like:


  type container struct {
    *inventory
    *item
    *readable
  }

  func (c *container) Get{}
  func (c *container) Drop{}
  func (c *container) Put{}
  func (c *container) Examine{}
  func (c *container) Read{}

  type Readable interface {
    Read()
  }

  type Examinable interface {
    Examinable()
  }

  type Gettable interface {
    Get()
  }

  type Dropable interface {
    Drop()
  }


I was just tagging types with interfaces and the logic was going into the
parser as something like:


  if x, ok := x.(is.Readable); ok { ... }
  if x, ok := x.(is.Examinable); ok { ... }
  if x, ok := x.(is.Gettable); ok { ... }
  if x, ok := x.(is.Dropable); ok { ... }


This felt very ugly. Also I should be able to make a container - or anything
else - readable without having to create a new type for it.

It was at this point that I hit another issue. If you have an embedded readable
type you want to display something like:


  You read a plaque. It says: Please do not read the plaques!


However the reading is done by the readable type:


  func (r *readable) Read() { ... }


When using an interface value as a receiver the type passed is the type of the
receiver. In other words you are just passing the embedded readable and nothing
else. In this case we cannot display 'You read a plaque' because 'a plaque'
comes from calling Name() on the embedded *thing type - which we now don't
have a reference to because we just have the readable type :( Embedding
references to all the other embedded types in each type seems very messy and
very wrong - so what to do? *sigh*

An idea I am playing with now is to have 'things' made up of a slice of
behaviours. The only requirement of a behaviour would be to have a SetParent
method. This would be a pointer to the whole slice itself allowing all
behaviours to access each other for a 'thing'. One immediate issue here would
be finding the right behaviour - you would need to loop over the slice and do
a type assertion on each behaviour to see if it implemented the interface you
are looking for, and this would need to be done for each 'thing' you are
interested in.

So glad I wrote WolfMUD-mini to play with these ideas - a fundamental rewrite
can be done in an hour or so to try out these different approaches :)

--
Diddymus

  [1] See 11.html


  Up to Main Index                          Up to Journal for December, 2014