Hi, Paulo,
I think you're on the right track. The main thing to note is that the
IsInstruction method isn't that useful. A concrete implementation of
AsmEntry is an instruction if it implements the Instruction interface, so
you shouldn't need a separate method.

So the example you provided looks like you plan to do something like this
when visiting entries:

if entry.IsInstruction() {
    ins := entry.(Instruction)
    // do stuff with ins
}


But instead, use the dual-return form of type conversion:

if ins, ok := entry.(Instruction); ok {
  // do stuff with ins
}


So the interfaces are just for holding the shared methods that all concrete
types must implement. You don't need to add discriminator methods.

However, if you do want discriminator methods (useful for when a concrete
type *happens to *implement an interface, like if it has methods with
commonly overloaded/used signatures), you simply move the implementation
down to concrete types.

So instead of this, which you noted will note compile:

func (i Interface) IsInstruction() bool {
    return true
}


You would have this in various places:

func (i *SomeConcreteInstruction) IsInstruction() bool {
    return true
}

func (i *AnotherConcreteInstruction) IsInstruction() bool {
    return true
}

// etc


I hope that makes sense. ASTs for languages typically use this same
pattern, so they are often reasonable examples to look at.

Here's the AST for the Go language: https://godoc.org/go/ast
It has interfaces for Node, Decl, and Expression, each implemented by the
various kinds of concrete AST nodes.

And here's another:
https://github.com/jhump/protoreflect/blob/50b1762cd8f6881d9e0e2f806b1275022695ceb9/desc/protoparse/ast.go#L29
It's an AST for protocol buffers, implemented in Go. It has interfaces for
node, terminalNode, and various kinds of declarations. It also uses type
assertions for unnamed package variables
<https://github.com/jhump/protoreflect/blob/50b1762cd8f6881d9e0e2f806b1275022695ceb9/desc/protoparse/ast.go#L75>
to ensure that the various concrete types implement the expected interfaces
(this is a common pattern in Go, to make sure any change to a concrete type
to make it *not* implement a particular interface result in a compile-time
error).




----
*Josh Humphries*
jh...@bluegosling.com

On Mon, Nov 20, 2017 at 4:27 PM, 'Paulo Matos' via golang-nuts <
golang-nuts@googlegroups.com> wrote:

> Hello,
>
> I am trying to write a simple assembler file parser. I just started
> developing in Go so I have the wrong mindset. I am keen to understand the
> best way to write something like this in Go.
>
> An assembler file at first glance is a list of instructions, directives
> and labels. I know there are some other things but for the purposes of the
> example, that's enough.
>
> So I have
>
> type AsmFile list.List
>
> The elements of the list are the problematic part. It's well... a union.
> I have read on this and I have seen suggested an interface approach, where
> you can then cast to the right type.
>
> The entries of the list above are AsmEntry
>
> type AsmEntry interface {
> IsInstruction() bool
> IsLabel() bool
> IsDirective() bool
> }
>
> The problem is that I start then with:
>
> type Label string
>
> func (Label) IsLabel() bool {
> return true
> }
>
> func (Label) IsInstruction() bool {
> return false
> }
>
> -- same for IsDirective
>
> but then an instruction should be an interface since there could be
> ArmInstruction, IntelInstruction, etc
>
> type Instruction interface {
> GetMnemonic() string
> GetArgsLen() int
> GetArg(int) string
> }
>
> func (Instruction) IsInstruction() bool {
> return true
> }
>
> but this doesn't actually work because the receiver cannot be an
> instruction. This already looks like I am going on the wrong path.
> Any suggestions on how to design something like this with Go?
>
> Kind regards,
>
>
> --
> Paulo Matos
>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to