4 ms·
Sure; the higher-order callers should do that. I love wrapping errors. But the issue is that the source of the problem is in lower-level code which made the th
by 015a 3y ago
Sure; the higher-order callers should do that. I love wrapping errors.
But the issue is that the source of the problem is in lower-level code which made the theoretically correct decision to be specific what you return and generic in what you accept. That lower-level code cannot guarantee that its higher-order callers will wrap the errors it returns. So; the lower-level code has to remain generic.
Obviously my example is contrived; but the problem is not. It is allowed, but essentially never safe to communicate to the compiler the error types your function returns. Its ok to use custom error types; you just can't tell the compiler about them. This is a problem that is so deep in the language it has influenced how error types and functions are designed in the standard library. I'm aware of one production outage related to this problem (yeah yeah, blame bad reviews and bad testing, I get it, it still happened). I've caught it a dozen times in code reviews (especially after that happened).
Its a real problem. People don't write perfect code.
- randomdata 3y ago> but essentially never safe to communicate to the compiler the error types your function returns. It is safe as long as you don't write too much code for no reason. The problem in the example is that DatabaseError needlessly defined an Error method. It serves no purpose other than to allow the issue to arise. Remove said method, which has no reason to exist, and the program will fail to compile. > Its a real problem. People don't write perfect code. Okay, sure. It is possible that a programmer may, for whatever reason, leave out entire blocks of logic that the program needs. Imagine not adding billing logic to your storefront software – I'm sure it has happened to someone before! Making interfaces more intuitive does not solve that problem, though.
- burnished 3y agoWhy are you complaining that this person wrote a clear and small example that demonstrates what they are talking about? It is painfully rude; a description and a couple lines of code that runs is the gold standard for starting a programming conversation.
- kubanczyk 3y ago> It is safe as long as you don't write too much code for no reason. var errConcrete *strconv.NumError = nil var err error = errConcrete err != nil // true Please fix this one.
- kubanczyk 3y ago> the theoretically correct decision to be specific what you return and generic in what you accept Yet another case of that old pitfall. Untyped nil uses the same keyword as typed nil, when they are not equal. It's an unfortunate contradiction within the language. And it means that the entrenched practice of err != /* untyped */ nil is an overly specific check (nil error is harmless whether it contains the type information or not). Someone, somewhere has thrown at us a principle ("the theoretically correct decision") and someone else has thrown at us a conflicting principle ("err != nil is a universal idiom"). The problem: these are not principles! Both of these are decisions with tradeoffs. Who is making these decisions? Some blog authors or conference speakers? No: the team that owns the code. So, either: - have a linter that catches *ErrX return declarations automatically, - or, have a linter that prevents err != nil (generally: interface != nil) Since the latter is impractical today, one needs to decide the former. Solved, isn't it?
- kubanczyk 3y agoThe latter possibility connects closely to TFA, because if we have `^` notation, it can magically check for a typed nil.