I am trying to get suggestion from the community in order to make the best practices. Please bear with me, with the following example:
Suppose that you work with half open intervals, that is, something that you know when it starts.
For example
HalfOpenInterval
restricted to a day. Example: you say "from 1:00 pm afterwards" (until the end of the day). Let's call it ClockIntervalHalfOpenInterval
restricted to the existence of universe. Example: you say "from 9 of july of 1810 we declare the indepedency" (until the end of the cosmos.. hypothetically). Let's call it PeriodFor both entities types: you work with a collection of them, so you usually have slices
of clocks and periods in your code.
So now comes the problem: you must find the enclosing interval for a given time (func FindEnclosingHalfOpenInterval
) for both clocks and periods, so you start writing the code...
And well, i get into this matter... how i should organize the code in order to write only once the common func. (func FindEnclosingHalfOpenInterval
).
So i get into this code: https://play.golang.org/p/Cy7fFaFzYJR
But i keep wondering if there is a better way to define common behaviour for collection of slices.
Please reader you shall realize that i need to do an "element by element" conversion for each type of slice (and i have a type of slice for each type of concrete HalfOpenInterval i define). So i wonder if there is there any way that allows me to introduce new types of HalfOpenInterval
without having to do some adjustement and "automatically" gets the abilitiy to use the func FindEnclosingHalfOpenInterval
?. Perhaps my rich-oo-java-based mind is not the correct way to face the problems in the simplistic-straight-ahead-go-world. I'm all hears, to any suggestion.
The key Problem here is you need to convert a slice from one type to another type.
The correct way to do this is to create a new slice and loop over it converting every single item. You can do this fast(er) if you create the array beforehand:
func ToIntervalsFromClockIntervals(clockIntervals []ClockInterval) HalfOpenIntervals {
intervals := make(HalfOpenIntervals, 0, len(clockIntervals))
for _, clockInterval := range clockIntervals {
intervals = append(intervals, clockInterval)
}
return intervals
}
Apart from that composition is another way you could solve the problem that you want to write the GetEnclosingInterval
function only once. I'm not saying it is better: it has other advantages and disadvantages. What fits better depends on how else you use the slices apart from what you posted here.
Here my refactored suggestion (and fixed): https://play.golang.org/p/Ko43hJUMpyT (TehSṕhinX you forgot to make the mutable method baseIntervals.add
with pointer recievers
instead ofvalue recievers
(or whatever is the name for non-pointer recievers
))
The HalfOpenIntervals
does not exist any more. Instead you have two different types for CLockIntervals
and PeriodIntervals
and both have the sorting and GetEnclosingInterval
function implemented via a common base struct.
For convenience I added a Add
function and a New...
function for each of them. This is where the disadvantages come in: Since CLockIntervals
(and PeriodIntervals
) is not a slice any more but a struct you will need convenience functions to work with the inner slice from the outside.
-- edit --
Coming from a oo-oriented background myself I know the drive to avoid duplicated code at all costs.
Writing go code for more than 2 years now on a full time basis I learned that this is not always the best approach in go. Duplicating code in go for different types is a common thing I do these days. Not sure if all would agree with this statement, though.
I think maybe this is overcomplicated. Define FindEnclosingHalfOpenInterval as a standalone function, and then for functions which need to work with HalfOpenInterval structs, make then accept an interface that has a EnclosingHalfOpenInterval method which usually just calls FindEnclosingHalfOpenInterval. That way you can do any kind of edge case data encapsulation without changing the signature.
And that's really all there is to it. FindEnclosingHalfOpenInterval is already shared because it's not explicitly part of any struct.