EDIT: I have updated the below code samples to better illustrate the problem.
Let's say I have 2 field-only structs that do not need any functionality.
Assume that they represent 2 types of similar data from a Database:
type Boy struct {
Name string
FavoriteColor string
BirthDay time.Time
}
type Girl struct {
Name string
FavoriteFlower string
BirthDay time.Time
}
I write a function for the Boy
struct that prints a greeting based on the given date and the boy's information.
Assume that this is a placeholder for a much more complicated function that does something based on a time.Time
field, and returns an int
that will be used elsewhere in the application:
func CheckBirthDayBoy(date time.Time, boy Boy) int {
numDays := 0
if date.Before(boy.BirthDay) {
// Greet how many days before birthday
numDays = int(boy.BirthDay.Sub(date).Hours() / 24)
fmt.Println("Hi, " + boy.Name + "! Only " + strconv.Itoa(numDays) + " days until your birthday! I hear your favorite color is " + boy.FavoriteColor + "!")
} else if date.Equal(boy.BirthDay) {
// Greet happy birthday
fmt.Println("Happy birthday, " + boy.Name + "! I brought you something " + boy.FavoriteColor + " as a present!")
} else {
// Greet belated birthday
numDays = int(date.Sub(boy.BirthDay).Hours() / 24)
fmt.Println("Sorry I'm " + strconv.Itoa(numDays) + " days late, " + boy.Name + "! Here is something " + boy.FavoriteColor + " to cheer you up!")
}
return numDays
}
Now, since Go is a strongly-typed language, and does not have Generics, I end up having to write a duplicate function just for the Girl
struct:
func CheckBirthDayGirl(date time.Time, girl Girl) int {
numDays := 0
if date.Before(girl.BirthDay) {
// Greet how many days before birthday
numDays = int(girl.BirthDay.Sub(date).Hours() / 24)
fmt.Println("Hi, " + girl.Name + "! Only " + strconv.Itoa(numDays) + " days until your birthday! I hear your favorite flower is a " + girl.FavoriteFlower + "!")
} else if date.Equal(girl.BirthDay) {
// Greet happy birthday
fmt.Println("Happy birthday, " + girl.Name + "! I brought you a " + girl.FavoriteFlower + " as a present!")
} else {
// Greet belated birthday
numDays = int(date.Sub(girl.BirthDay).Hours() / 24)
fmt.Println("Sorry I'm " + strconv.Itoa(numDays) + " days late, " + girl.Name + "! Here is a " + girl.FavoriteFlower + " to cheer you up!")
}
return numDays
}
Is there a way to avoid code duplication for simple structs like the ones above? I do not want to duplicate my function for each new struct that I want to implement it for.
Interfaces are not an option here because both structs do not have any Functionality to speak of (and adding dummy functionality for the sake of satisfying an Interface sounds like a backwards solution to me).
EDIT: After considering the solution I accepted, I now believe that Interfaces are also a valid solution to this problem. Thanks to @ThunderCat for bringing it up!