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.