I agree with you 100%. One thing I run into a lot is the state strategy pattern, where you want to conditionally generate the right implementation for an interface. This may begin with e.g. a case statement, but once you extract that, your function necessarily returns an interface. If the “accept structs, return interfaces” rule is taken to the absolute, then this isn’t acceptable.
I’ve also seen general resistance to large interfaces. I wonder if this may be a misapplication of a principle. If a function accepts an interface with five methods, but only uses two of them, you might want to think about making a sub-interface with just those two methods, to both clarify what the function actually needs, and allow greater flexibility in what concrete types it can accept. But if the function ultimately requires, say, 10 methods on the object (e.g. because it orchestrates passing that object around to several other functions), then there’s nothing inherently bad about creating an interface with 10 methods. Would you agree? Here’s an example of an interface in the HM9000 library with 21 methods.
Thanks. Great post.