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