This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-08-01
Channels
- # 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) - true
, 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 true
, false
, and 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 :invalid-argument
keyword?
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 :sufficient
(funds) :insufficient
and :no-account
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.
Right - that's exactly my question.
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 isa?
https://github.com/symphonyoss/clj-symphony/blob/master/src/clj_symphony/user.clj#L136
Nah - I greatly dislike protocols, though I'm not entirely sure why. 😉
The two fns in question are same-pod?
and cross-pod?
.
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)))
so use 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! 👍
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
Nope - (user ...)
can return nil
.
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.
(e.g. (user ...)
)
👍 Anyhoo this has been very useful - thanks @dpsutton ! 👍