|
|
|
|
|
by jzwinck
849 days ago
|
|
If you don't like returning an interface because the caller can't tell what it does, why is accepting an interface any better? Don't you end up in the same conundrum of not knowing whatever it is that you need to know about foo.IssueReceipt() if someone passed foo into your function? |
|
One is call-site flexibility - if I have a function that takes an interface, I can call it without an explicit cast with either an interface or a concrete value. If it returns a concrete value, I can assign that to an interface or a concrete value. So far so good. But both taking a concrete value, or returning an interface, force the call site to match the decision.
Another reason is that you usually read the call site first, then you go inside the function to look at it in detail, so you already know what concrete values is being passed, even if the function only sees an interface.
Finally, it's a local change to change an API to accept a concrete type after it has been accepting an interface, but changing an API that used to return an interface to return a concrete value could potentially involve a refactor of the whole codebase. (In fact, one such refactor motivated this rule.)
Of course it's not a hard-and-fast rule. Go style also has you return error, which is an interface, and the standard library passes around io.Writer and os.Stat all the time. But for business logic, I think it's the right rule 95% of the time.