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.