Also check out type switches: https://golang.org/ref/spec#Type_switches


On 21 November 2017 at 08:18, 'Paulo Matos' via golang-nuts
<golang-nuts@googlegroups.com> wrote:
> 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.

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