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