Up to Main Index                               Up to Journal for May, 2012

                      JOURNAL FOR SUNDAY 13TH MAY, 2012
______________________________________________________________________________

SUBJECT: Embedding interfaces & structs - Part 1
   DATE: Sun May 13 22:17:32 BST 2012

Quite a busy weekend, however I did manage to think alot about WolfMUD and how
to structure and implement things. One good thing about having other stuff to
do - you can walk away from a problem and just think for a while and idle over
some ideas. Even managed to sit down at a keyboard and try a few of the ideas
out.

Expanding from Friday's musings the interface naming does not really work
well:


  type Examinable interface { Examine() }
  type Edible     interface { Eat()     }
  type Gettable   interface { Get()     }


Why is this? Well if you put each into it's own package you end up stuttering
a lot:


  examinable.Examinable
  edible.Edible
  gettable.Gettable


So, looking through the Go sources for inspiration, using 'Interface' as the
name of the interfaces works much better:


  examinable.Interface
  edible.Interface
  gettable.Interface


Also when composing things by embedding a lot you don't necessarily need to
include all of the interfaces you are embedding. You only need to define the
specific interface details applicable to what you are defining. Consider my
reimplemented Thing:


  package thing

  type Interface interface {
    Name() string
    Description() string
  }

  type Thing struct {
    name        string
    description string
  }

  func (t *Thing) Name() string {
    return t.name
  }

  func (t *Thing) Description() string {
    return t.description
  }

  func New(name, description string) *Thing {
    return &Thing{
      name:        name,
      description: description,
    }
  }


This defines a basic thing from which other objects can be composed. Next we
define an examinable object which embeds Thing:


  package examinable

  import (
    "fmt"
    "thing"
  )

  type Interface interface {
    Examine()
  }

  type Examinable struct {
    *thing.Thing
  }

  func (e *Examinable) Examine() {
    fmt.Printf("You examine %s. %s\n", e.Name(), e.Description())
  }

  func New(name, description string) *Examinable {
    return Embed(thing.New(name, description))
  }

  func Embed(thing *thing.Thing) *Examinable {
    return &Examinable{Thing: thing}
  }


Notice the interface definition - we only specify Examine() and do not have to
embed thing.Interface. Why is this? Well we do embed the thing struct.
Interfaces only define behaviour. So an Examinable has Name() and
Description() pulled in through the struct embedding and as it implements
Name() and Description() it satisfies the thing.Interface automatically.

What would happen if we did embed the thing interface? Our interface would
have specified that an examinable MUST provide Name(), Description() and
Examine() to be an Examinable. However it only actually needs to implement
Examine().

There is also another oddity of embedding which is why we have the
examinable.Embed() function, but I'll leave that for 'Embedding Part 2' as
this is already quite long.

--
Diddymus


  Up to Main Index                               Up to Journal for May, 2012