Generic interface catastrophe

Hey there! I’m writing a genetic algorithm library for Go and it seems generics are an excellent fit for the use case, however, I’ve run into mishaps.

The repository is over at github by the name “soypat/mu8”, The interfaces the user has to implement to use the library are these mu8/mu8.go at main · soypat/mu8 · GitHub.

Maybe you’ve noticed a problem by looking at the last link: The interface’s methods are type parametrized, which is a huge load on the user. So that’s one thing I noticed is a big no-no. I’d ideally want to use the library as shown in this example mu8/mu8_test.go at main · soypat/mu8 · GitHub. genomeimpl is the individual in the population which implements Genome. So at the moment the example does not compile because I need to generify genomeimpl, which is practically impossible without ending up with something horrid.

It seems that however I choose to move generics around to fix , I’ll end up having to type cast and whatnot, defeating the purpose of generics… and if I choose to just use interfaces with Gene interface I’ll also have to cast interfaces at Splice method… or I’d have to settle on a bigger interface at Gene.

I feel like there’s no reasonable compromise without overhauling the whole library. I’m thinking maybe starting from the genetic.Population type and making that generic… What do?

So I refactored a bunch of it and lo and behold, got to something that works and is not that bad. I have replaced old changes so old links will be broken, but that’s OK since there was no way of making that form of generics work. There’s still some type casting going on on the user side (some of it is on API side which is not that bad I guess).

For Posterity here is the repo at the time of first posting this issue GitHub - soypat/mu8 at e28df1dd27e04822a542f26e0a07f2fa3559a3c2

1 Like

I think I had the opportunity to see your code before and after your changes. I don’t know the first thing about genetics so I didn’t comment because I had nothing helpful to provide, but I wanted to comment now and say that I applaud you for using generics, then seeing how it complicated the code that your library consumers would have to write, and after removing generics from your Genome and Gene types, it reduced the code that your users would have to write.

I don’t mean to be a stick in the mud against generics, but I can appreciate how you used at a new feature, recognized a problem, and then you weren’t afraid to stop using it to make the code simpler. Kudos!

P.S.: I recognize that posts in forums can fail to convey genuineness, so I wanted to say explicitly that I also don’t mean to sound patronizing!

2 Likes

@skillian Yes! You’re comment describes exactly what happened! I recoiled when I started to think about how I’d have to refactor the code I wrote presuming it would work by just implementing the interface without generics. If this issue proposal: Go 2: spec: add `self` type for use within interfaces · Issue #28254 · golang/go · GitHub had been accepted and implemented I wouldn’t have had to remove genericity from the interfaces using the self keyword… but then I wouldn’t have arrived at the design as it is today, which is arguably SO clean, 3 methods for Genome and 3 for Gene! And no type casting on the user side! Who woulda thunk!

I am ecstatic with how the design turned out! Thanks for your words skillian, they resonated with me.

1 Like