Josh,

Thanks for the quick and clear reply. I was not aware of the dual return
form of type conversion.

Paulo Matos

On 21/11/17 00:05, Josh Humphries wrote:
> 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 <mailto:jh...@bluegosling.com>
> 
> On Mon, Nov 20, 2017 at 4:27 PM, 'Paulo Matos' via golang-nuts
> <golang-nuts@googlegroups.com <mailto: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
>     <mailto:golang-nuts+unsubscr...@googlegroups.com>.
>     For more options, visit https://groups.google.com/d/optout
>     <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
> <mailto:golang-nuts+unsubscr...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout.

-- 
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.

Reply via email to