4 ms·
(get m :foo :not-found) Problem solved.
by blacktriangle 5y ago
(get m :foo :not-found)
Problem solved.
- didibus 5y agoI wouldn't say this totally solves it: (get m :fooo :not-found) Is still a bug that'll be hard to debug, because your code will most likely handle :not-found and believe that it is truly not-found for some reason, but it's not, you messed up the keyword.
- blacktriangle 5y agoNow you're getting at a much more fundamental issue. The issue here is that m is not a product type but an open map that allows for an arbitrary collection of keys. No static typing system will solve this either. If you're really that worried about typos and don't need an open map, Clojure has a solution as well in the form of defrecord and deftype. Now the compiler will catch the problem.
- didibus 5y agoYes, I don't really think any language solves this problem, just moves it around. It's just an issue in general whenever the happy path includes optionality as a possible result, how do you then distinguish the happy path of getting a missing value, which you expect is a possibility given the use case, versus a bug to have set the value or have been provided the value or have queried for the value? I think the only languages that reduce the scope of this problem are those where you can define non-nullable types. In that at least when you know for a fact your use case shouldn't have "missing" things, the compiler can catch those bugs. You can also handle this in Clojure with runtime assertions, albeit catching the bug a little later in development. But for the times when optional is a real possibility, you still have this issue. If you move to an explicit set of valid keys, it could be that something failed to assign them a value, etc. Edit: I guess maybe something where the language simply has no null ever could work. Like say a field not yet assigned a value would have the value :unset, and so if someone doesn't provide a value for the field, you'd still set it, but with the new value :missing. Now technically you could distinguish a bug as `:unset` versus actually missing as `:missing`. I'm not sure this would work for dynamic use cases though, where like you don't know the full range of possibilities in advance. But if you do, you could check that nothing is `:unset` and if it is, you know there is a bug, otherwise it should be `:missing` or some other value. Edit2: Ok, now that I played a bit more with what you said, I realized thay your solution is actually better then I thought, but it depends how you model things. (get {:foo :missing} :fooo :unset) ;> :unset (get {:foo :missing} :foo :unset) :> :missing If you model optionality as an explicit `:missing` value on a set key, like assoc the key `:foo` with value `:missing` to indicate that no value was provided for it. With the 3rd argument to `get`, you can now tell the difference between a bug or an actually missing value. It does seem to require a bit of care, and I don't know if its just.moving the issue somewhere else, but it could be an approach.