This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-21
Channels
- # announcements (1)
- # aws (18)
- # babashka (5)
- # beginners (72)
- # biff (2)
- # calva (38)
- # cider (2)
- # clj-commons (6)
- # clj-yaml (2)
- # clojars (7)
- # clojure (41)
- # clojure-austin (5)
- # clojure-europe (78)
- # clojure-nl (1)
- # clojure-norway (18)
- # clojure-uk (3)
- # clojurescript (13)
- # component (9)
- # cursive (37)
- # datahike (3)
- # datomic (7)
- # fulcro (7)
- # graphql (3)
- # holy-lambda (2)
- # honeysql (8)
- # introduce-yourself (1)
- # jobs (1)
- # kaocha (1)
- # leiningen (19)
- # lsp (104)
- # malli (5)
- # nbb (8)
- # off-topic (60)
- # polylith (22)
- # portal (2)
- # reagent (24)
- # reveal (1)
- # shadow-cljs (126)
- # test-check (11)
- # tools-build (39)
- # vim (23)
- # xtdb (10)
I tried to mock a function map with a field, that should not be accessed, so I used
(constantly (throw (Exception. "NOPE")))
This immediately throws an exception, but when I use
(fn [& args] (throw (Exception. "NOPE")))
It works.
Do I see correctly, that this is because constantly
is a function, but fn
is a macro?
It feels weird nevertheless...That's correct.
In the latter case, (throw ...)
is the body of the created function - it's not executed right there.
In the former case, (throw ...)
is an argument to an already existing function, constantly
.
I just noticed, that using (constantly (throw ...)) doesn't really work for my case. It will literally only work if the encapsulated map (the throwing fn) is used as a function object, like key lookups. Doesn't work using it as a seq
, like with reduce or map.
any suggestions how to realize something like that? Maybe a smarter approach to check if a key is accessed?
First of all, why do you need something like that in the first place? That's very unusual and I'm willing to bet pretty much nobody does that.
I'm unsure what you're trying to achieve? Are you trying to create an object that will throw an exception if you get
a key that's not in a special list?
@U2FRKM4TW well, the use case is a conditional branching (very rough example): HR doesn't need to access the employee if they are an external worker. So my goal is to write an appropriate test that makes sure, the code on that conditional branch never touches that area. And yes, the kv has to stay. @U0P0TMEFJ kind of, it's a map which mustn't be accessed, neither by get, nor by seq. Think stack canary on a key.
I often feel like when the need to reach for a "mock" appears it highlights a design problem ... can you be more specific?
Feel like you're trying to apply a pattern from Java to Clojure, TBH. But I don't have a good advice here except for "don't do it".
> Feel like you're trying to apply a pattern from Java to Clojure, TBH I agree. That's why I'd like to see a wider context of the problem that's being solved. I expect that there's a different way that would address the issue.
Design problems are neither my responsibility, nor my goal to fix right now. So I really don't care about that atm. I rather intend to constrain what is given, so that it can't be misused any further. The context given is pretty much that: you have a map with 2 keys, the key :employee in question points to another map object, and the access to that object is to be generelly constrained, both access, and further processing. If k1 :type says :external, :employee is not to be accessed (like a "Key canary") Only that there are like hundreds of nested maps under certain keys, that decide whether or not that should be accessed, and one decision to make: access or not.
so you have a function that controls access to these bits of data? maybe something like:
(defn get-employee-for-hr [data]
(when-not (-> data :type (= :external))
(:employee data)))
(comment
(let [data [{:employee {} :type :external}
{:employee {} :type :internal}]]
(mapv get-employee-for-hr data))
)
and you can easily write a test for that function that solves your problem?That is a possible solution iff the access to that data structure is not clustered across thousands of LoC. This is why I need the Data struct to alert, when it is accessed.
does grep -rHi "employee"
identify all these places? ... and presumably at some point you'll need to write tests for all of these places where the decision is made and decide if the answer to can-hr-access?
should be yes or no?
if you really need to do this you could do it on the level of the map. see https://blog.wsscode.com/guide-to-custom-map-types/
if you want a value that you can pass to a function that will explode when you ask for a key you can use proxy
or reify
to create one.
(let [sup {:a 1 :b 2}
mok (proxy [clojure.lang.ILookup] []
(valAt
([k] (or (get sup k) (throw (ex-info "err" {:access :illegal}))))
([k nf] (or (get sup k) (throw (ex-info "err" {:access :illegal}))))))]
(:qqq mok))
Or try a function with a case statement inside
Thank you guys. The idea of using a proxy
is quite useful, I think. But instead of implementing everything with a throw
I would rather do an empty map implementation, that only implements type
. That way it would basically throw a RuntimeError (or similar) on seq
and reduce
, yet basic schema validation still works.
To be honest, I observe this argument "design problem" a lot here. Sure there is a design problem, but just "shouting" that doesn't fix a problem. You can't just rebuild anything whenever someone brings that up. We are in the process of doing that, but everyone is aware of that, which is why I said it's not my concern for this particular issue. @U0P0TMEFJ
What is the most idiomatic way to call remove
when the predicate is supplied? Any improvements over (remove (or pred (constantly false)) coll)
?
If its when pred could be nil then you can do
(cond->> coll
pred (remove pred)))
Sort of like wrapping it with an if, but if pred is falsey you'll just get the unaltered collection back.(filter (complement pred) coll)
is equivalent to (remove pred coll)
but not as clear. it's basically a demorgan of the remove
version
it seems like a condition on the pred, like what @U0CLLU3QT wrote, is expressing the ides best
I am having an issue where when I run the clj
command or rlwrap clojure
if I type in a form and hit enter, the form is evaluated successfully, but where I typed it in, the form gets kind of mangled, sort of the last paren in the form is replaced with the form again
for example
Clojure 1.11.1
user=> (+ 1 2)(+ 1 2)
3
user=>
I just typed in (+ 1 2) and hit enter, the second (+ 1 2) appears to have been added by rlwraplooks like https://ask.clojure.org/index.php/10025/have-prompts-previous-lines-command-started-disappearing again, or at least the fix there fixes it
Yeah, have been seeing some reports of this on latest
Might find something helpful in this thread. https://clojurians.slack.com/archives/C053AK3F9/p1665434326857759?thread_ts=1665434326.857759&cid=C053AK3F9