9

I am a beginner in Go. I maybe thinking too traditional coming from years in other languages, but here is what I want to do in Go. Assume the following use case

  1. I have interface I. This interface has functions, start() and stop()
  2. There are many structs implementing the interface. struct A, struct B, struct C
  3. When the application starts, I want to call start() on structs A, B and C
  4. Similarly, when the application terminates, I want to call stop() on the A, B, C structs.
  5. I do not want to hard code struct A, B and C anywhere in the code to call the start/stop functions. This is so that when I add struct D later (also implements interface I), the code will automatically work without modification.
  6. In order to achieve this, I need to be able to say "Hey Go, give me all the types that implement interface I".
  7. If I get back a slice of A, B and C, I can simply loop through and call the right methods at the right time.

Doable in Go?

WW.
  • 23,793
  • 13
  • 94
  • 121
sat
  • 5,489
  • 10
  • 63
  • 81
  • You still need a value of each struct in order to call the method (the value can be `nil`). Calling a method on a type ( `StructA.start()` ) is not possible. So, do you want this loop to create a nil-value of the struct type and then call the method `start()`? – ANisus May 09 '14 at 05:23
  • I do not mean calling on the struct itself, but an instance of the struct. So maybe the ask of Go is "give me all known instances of interface I that you know of" and we get a slice of those. Not sure if there is a way. – sat May 09 '14 at 05:27

1 Answers1

8

The short answer is: No, that is not doable

Go is a strictly typed language. This allows the linker to leave out type definitions, methods and functions not used by the application.

That means, unless a type (such as struct A) are referenced and used somewhere, it will be omitted.

But in your comment, you mentioned you don't want the types but rather the currently existing instances of any type that implements the interface.

This is not possible either.

Alternative

My suggestion is to create a global map (or slice):

var instMap = map[string]StartStopper

And have each struct add an instance to that map with an init function that will automatically be called at the start of the application:

type A struct {}

func init() {
    instMap["A"] = new(A)
}

Then when you want to start all the instances, just iterate over the map and call Start()

Edit

And if it is not a one-instance-per-type situation but rather multiple instances for each type, then you will have to add to the map (or slice) whenever a new instance is created. And you would have to remember deleting the instance from the map when it is not to be used anymore, or else it won't be handled by the Garbage Collector.

ANisus
  • 74,460
  • 29
  • 162
  • 158
  • Not what I was hoping for - I was thinking of more declarative style. A struct implements an interface and somewhere else in the program, I can do the book keeping dynamically. With the approach of the Map, now there is a very tight coupling between the init functions and a Map which it has nothing to do with. – sat May 09 '14 at 13:35
  • Just curious, I am unaware of any language that lets you find all instances of a type arbitrarily created by code. What's an example of one? – David Budworth May 10 '14 at 09:26
  • 1
    @DavidBudworth I believe the OP is angling for a dependency injection approach. i.e he is not necessarily interested in a particular in-memory instance of a type, but rather wants to scan for the types and instantiate based on some criteria. For example, think of a command line app with tasks/verbs etc. – Amir Abiri Sep 27 '14 at 13:34
  • 1
    @DavidBudworth trivial to implement with reflection in a language like C# or Java. Example: https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface – Tyson Mar 24 '18 at 22:41
  • This does not work. The init() function is called only if the related file is referenced – alonana Feb 05 '20 at 09:50
  • @alonana All `init()` functions in all files are called as long as the package they belong to is imported. You can use the [blank identifier](https://golang.org/ref/spec#Blank_identifier) when importing, if needed. – ANisus Feb 05 '20 at 13:20