Feedback on avoiding duplicate text lookup values at compile time

I want to have lookup strings that are unique at compile time for the local package.

I have the following :

type Key int

const (
	txt Key = iota + 1
	greeting
	// can't add txt again here - **compile** will fail
	newKey // not yet used
)

var id map[Key]string

func init() {
	id = map[Key]string{txt: "txt", greeting: "greeting"}
	// can't add txt: "anything" since **compile** will fail
	// could add newKey: "txt" - but this requires **deliberate foolishness**

	library.NewBlockType("server.log", "misc", setup).Add(
		text.New("Log "),
		stringinput.New(id[greeting]).Empty("greeting"),
		// can't stop reuse of id incorrectly, e.g. by :
		// stringinput.New(id[greeting]).Empty("duplicate greeting"),
		// however the generated UI is visible so this should be very obvious
		text.New(" "),
		stringinput.New(id[txt]).Empty("message"))
}

Here Key is used to limit string lookup on the const values only

This offers some (but not all) detection of copy/paste errors on compilation.

Any thoughts/suggestions please :slight_smile:

I’m also interested if this is idiomatic code/pattern or seen/used elsewhere…

Hello there. Why not to use stringer?

1 Like

Nice idea - Stringer might well do - Thank you - Andy

In case anyone is interested in this - I haven’t used Stringer since it doesn’t fit my use case well. Instead I have gone down a different (painful) route of using reflect on a struct, so I now have a struct that defines the (unique) fields including some struct tags that I use as well, e.g.

type EveryDefn struct {
	TypeName struct{}                `_:"system.every"`
	Class    struct{}                `_:"misc"`
	_        text.Text               `txt:"Every " iconify:"true"`
	Secs     numberinput.NumberInput `empty:"seconds" min:"0" max:"999" width:"4" default:"1"`
	_        text.Text               `txt:"seconds"`
	Callback idinput.IdInput
}

This defines the unique field names (and also allows struct tags that I need). The disadvantage is that this may error on running rather than on go generate. The benefit is not having to run go generate.

In my case, I run this:

	every := &EveryDefn{}
	...New(every)

This creates a struct instance and then initializes the instance by reflecting through the fields accessing the struct tags, e.g. setting Secs.Empty = “seconds” and Secs.Min = 0 (int).

But as I said - specific to my use case :slight_smile: