This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # beginners (41)
- # boot (25)
- # cider (34)
- # cljs-dev (221)
- # cljsrn (1)
- # clojure (191)
- # clojure-dusseldorf (4)
- # clojure-hamburg (1)
- # clojure-italy (8)
- # clojure-poland (1)
- # clojure-russia (22)
- # clojure-spec (27)
- # clojure-uk (91)
- # clojurescript (101)
- # core-async (11)
- # cursive (33)
- # data-science (9)
- # datascript (3)
- # datomic (30)
- # emacs (4)
- # events (4)
- # garden (6)
- # jobs (3)
- # leiningen (8)
- # luminus (39)
- # lumo (2)
- # off-topic (158)
- # om (13)
- # onyx (1)
- # parinfer (22)
- # planck (2)
- # protorepl (5)
- # re-frame (7)
- # reagent (10)
- # remote-jobs (1)
- # ring (1)
- # ring-swagger (20)
- # unrepl (92)
- # vim (11)
G'day gurus - I have a couple of hopefully simple questions on style:
I have a little fn (basically a predicate) that has three possible outcomes (return values) -
false, and "the argument you provided is invalid" (which can happen through no fault of the caller's, since the argument is used to lookup a shared mutable data source). Right now I'm using
nil to identify these three cases, but the use of
nil has me feeling a bit uncomfortable (due to nil punning etc.). What would you suggest?
FWIW I'm very reluctant to use exceptions (this is not an "exceptional" situation, and they're a pain to handle), but I'm not sure what else would be idiomatic - perhaps an
Related: right now my fn has a name with a
? at the end, since it's basically a predicate, but I'm a little concerned about this third state it might return. Should I be ditching the
? suffix in the interests of clearly communicating intent?
ie, if you were looking up if a check could clear you could return
The use case here is the question "is this user (identified with an id of some kind) in my company or not".
then handle the three cases. you could then have an easy predicate based on these with
(defn is-sufficient? [check account] (= (clear-check check account) :sufficient) or whatever your domain needs
The issue is that "user identified by id" part - it's entirely possible for an identifier to no longer be valid.
I also have an inverse fn "is this user not in my company", and it also returns nil for that third case.
It seems "wrong" to me to have two fns that should be logical not, not actually be so in some cases (i.e. when the user identifier is invalid)
then change your question? But if the question is "this id is an employee in our company" has two answers to me
Right - in fact the fn (deliberately) can't tell the caller why the identifier is invalid, just that it is.
The trick here is that the identifier is "resolved" via a multi-method that can take all sorts of types.
In some of those cases, it's not possible for the identifier to be invalid (i.e. the identifier is, in fact, the object we're looking up, having previously been loaded from the data source).
does the object satisfy a protocol or record or anything? can you ask some type of
And here's the multimethod underpinning the identifier resolution: https://github.com/symphonyoss/clj-symphony/blob/master/src/clj_symphony/user.clj#L76-L115
(defn same-pod? "Returns true if the given user is in the same pod as the authenticated connection user, or nil if the user doesn't exist." [connection user-identifier] (let [them (if (:company user-identifier) user-identifier (user connection user-identifier)) me (user connection)] (same-company? me them)))
them if its already the object (which seems to be identified by having a
:company keyword entry or else look it up
Yeah - that's a nice optimisation on not looking up the user details if we already have them! :+1:
Though it doesn't answer my original question about having a "predicate" that returns three states, and whether using
nil is appropriate for the third state.
oh i thought this worked around that. I understood nil would come up when you had the object you were already looking up. So my goal was to collapse this down into a true predicate
but my suggestion would be figure out how to use two states or get a type that has three values. In other words, only use boolean types if you have boolean states. if you have three make your own descriptive keywords for the state
and if you do that you can return a map that includes the reason why something is invalid along with the fact that it is invalid
Yeah I wasn't planning on providing any information on why the identifier is invalid - as you said above that can be provided by some other fn.