This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-28
Channels
- # announcements (11)
- # aws (2)
- # babashka (35)
- # beginners (173)
- # calva (3)
- # chlorine-clover (2)
- # cider (17)
- # clara (2)
- # clj-kondo (28)
- # cljs-dev (11)
- # cljsrn (53)
- # clojure (178)
- # clojure-argentina (1)
- # clojure-europe (12)
- # clojure-germany (5)
- # clojure-italy (4)
- # clojure-nl (5)
- # clojure-spec (25)
- # clojure-uk (88)
- # clojurescript (109)
- # conjure (34)
- # cursive (2)
- # data-science (35)
- # datomic (15)
- # emacs (6)
- # events (1)
- # fulcro (28)
- # graphql (15)
- # helix (21)
- # hoplon (7)
- # jobs (4)
- # jobs-discuss (1)
- # joker (15)
- # lambdaisland (1)
- # lein-figwheel (4)
- # local-first-clojure (1)
- # malli (8)
- # meander (17)
- # off-topic (33)
- # parinfer (2)
- # rdf (16)
- # re-frame (3)
- # reagent (21)
- # reitit (14)
- # remote-jobs (5)
- # ring (8)
- # rum (1)
- # shadow-cljs (184)
- # sql (2)
- # testing (1)
- # tools-deps (23)
I'm using java.lang.constant.Constable
in some of my test cases of my project. This runs find in the interactive session using cider. However, it fails in the gitlab CI pipeline. The pipeline effectively has the following expression:
(and (symbol tag) (resolve tag) (class? (resolve tag)))
which gets evaluated during the testing with tag =the symbol java.lang.constant.Constable
What do I need to do to make sure that symbol resolves using the `resolve` function?
when I run lein test
it works. all the tests pass, but when I run this in the docker image it fails. i.e. that expression (and (symbol tag) (resolve tag) (class? (resolve tag)))
returns false.
do I need to add something to my ns :require
clause to make sure java.lang.constant.Constable
is available ?
What JDK version are you running on the system where it works, versus the one where it does not? I do not know when that class was added to the JDK, but it might not be until JDK version 12.
good clue.
[geminiani:~/Repos/scalain_e] jimka% java --version
java 14 2020-03-17
Java(TM) SE Runtime Environment (build 14+36-1461)
Java HotSpot(TM) 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)
[geminiani:~/Repos/scalain_e] jimka%
You can find out from inside of a running Clojure program with (System/getProperty "java.version"))
so it sounds like I need to find other classes which serve the same purpose for testing but are available pre-jdk 12
yea, it returns "14" as a string
It seems to at least partly depend upon what JDK versions you want your code to work on. JDK 8 is still fairly widely used, and the other most common one is likely JDK 11
great. i refactored my tests and just pulled the java-14 specific tests into different test cases which are "optioned out" if (resolve 'java.lang.constant.Constable)
returns false
tests pass in the docker image as well. happy camper here.
excellent
What do I need to do to make sure that symbol resolves using the resolve
function?
I remember seeing a variant of let
that returns all bindings in a map. Can't seem to find it at the moment.
But I don't thing it's worth it TBH. If there are so many bindings you don't want to write them as a map, you're better off propagating them as a map through all the levels. Is there a particular snippet that sparks the desire for something like this?
For an inline function call, I don't need to spread the call over multiple lines if the caller code is succinct.
If I have a function with a keyword argument, how can I make its default value to be false
(defn dfa-to-dot
"docstring"
[dfa & {:keys [title view abbrev]
:or {title "no-title"
abbrev true
view false}}]
...)
If I make the default value of abbrev true
then I can call the function with :abbrev true
or :abbrev false
, however if I make the default false, then calling it with :abbrev true
or :abbrev false
seem to work exactly the same.For this function, what can i do to make the default value be true
and have :abbrev false
still work? The following unfortunately returns true
, even though I passed false
at the call site.
((fn [& {:keys [abbrev] :or {abbrev true}}] abbrev) :abbrev false)
no, it doesn't?
user=> ((fn [& {:keys [abbrev] :or {abbrev true}}] abbrev) :abbrev false)
false
hey! your'e right. there must be something else wrong my code. I've never had a bug before 🙂
My problem was that my function made a recrusive call to itself, and didn't pass along the :abbrev variable in the call. 😞
hi everyone, I have a question about an atom inside another atom
(do
(def parent-atom (atom {}))
(swap! parent-atom merge {:a (atom 1)})
(def child-atom (:a @parent-atom))
(reset! parent-atom {})
(prn (deref child-atom)))
Why (deref child-atom)
returns 1
?var parent = {}
var child;
parent = {a: {val: 1}}
child = parent.a
parent = {}
child.val
// -> 1
so, when the child is created, it creates a new value from the value of the parent, not a reference to that value ?
No. You have a reference to an object. Resetting parent does not remove your reference to that object.
What does the :pre for the function arguments do? I think it is for limiting the viable arguments of the function but just wanted to get it verified
it allows design by contract, you can use :pre and :post to check the input values and output values that matches a predicate
nice I don't think I've used a language that lets u check the value for the output before
It causes the compiler to insert an assertion. It’s equivalent to:
(assert (and (pos? x) ...))
:pre
assertions get run before your code. :post
assertions get run on your return value.
Hello everyone, if i want to add a optional argument on my function i need to use a &
right? I'm using it and getting a error when i do not fill this function.
for example
(create-table-sql [this table cols])
I want to add a optional argument
(create-table-sql [this table cols & extra-specs])
Try this approach:
(defn create-table-sql
([this table cols] (create-table-sql this table cols [])
([this table cols extra]
(do-something-with-args ,,,)))
That works well if you know you’re going to have at-most-one extra argument, and the &
version works well when you’re going to have 0 .. n additional arguments
Also from your example, it’s not clear if you’re using the &
in the defn
or if you’re using it when you call the function. You need to use the &
in the defn
that defines your function.
On my case, i'll have more than one argument.
I'm using it in the defn.
Can you post a gist of your code and the error you’re getting?
java.lang.IllegalArgumentException: No single method: create_table_sql of interface: dn.migrate.ddl.Ddl
found for function: create-table-sql of protocol: Ddl
Ok, protocols are adding some extra complexity here then. I’m not that well versed in protocols, so I should let someone else give you a more reliable answer.
protocols don't support varargs
That would explain it. 🙂
you have to define the method multiple times with different arities
protocols internally are making java interfaces and that's drives some of this
So if you need 0 .. n optional arguments, you can just wrap them inside a vector as a workaround, right?
(create-table-sql this table cols [some more extra stuff])
you could, although you'd still have to pass that always
right
Thank you folks
i'm figure out another way
I create another arity trying to call the same implementation. I appreciate the help
Are protocols what Clojure has instead of CLOS kinda? Some of the concepts seem related.
I do not know CLOS in depth enough to compare them in details, but Clojure also has quite general multimethods: https://clojure.org/reference/multimethods. Nothing in Clojure I am aware of tries to achieve what CLOS's MOP (Meta Object Protocol) does. I would not be surprised at all if CLOS enables solving "the expression problem" in a similar way that Clojure protocols are intended to do: https://www.ibm.com/developerworks/library/j-clojure-protocols/
Oh that looks like an interesting read. Thanks. (Thanks also for the good resources I recognise your name from Andy)
Yes, it was the function-centric polymorphism/multimethod stuff that struck me as similar, I have yet to comprehend MOP 🙂
there's a similarity / compromise between what defmulti does and what clos does for multimethods
in clojure you could absolutely use (fn [& args] (map type args))
as your method dispatch to do what clos does
but instead of MOP for fully parameterized object system where you can redefine inheritance, method lookup, etc. you just get a per method option for a custom dispatch
(I wonder if that's fully compatible though - would defmulti be able to use each element of (map type args) to look for supers - that might not actually be possible)
so I guess you can kind of fake it, but without subclassing, which kind of misses the point, so I take it back - it's only vaguely similar if you squint, and not really the same
this reminds me of the docs for cut
in scheme claiming that it implements currying :D
hey guys, i’m trying to read in a CSV file that has a header and then ultimately end up with a list/vector of maps containing keywords and the correct type
I use org.clojure/data.csv for handling lots of csv fiels
you're often going to need some glue for stuff like date/time
I believe with data.csv you always get strings for field values, and it is up to you to convert those to the type that you wish.
the java.time libraries can do anything kind of date/time parsing you need
(defn str->keyword-concat-and-lowercase
"turn a string into lower cased concat keyword"
[raw_string]
(as-> (name raw_string) $
(string/replace $ " " "_")
(string/lower-case $)
(keyword $)))
;; (defn convert-various-types
;; "Convert Balance, Amount, Currency Rate to number
;; Convert Date to date"
;; [csv-record]
;; (-> csv-record
;; (update :amount #(bigdec %))
;; (update :balance #(bigdec %))
;; (update :currency_rate #(bigdec %))
;; (update :date #(clojure.instant/read-instant-date %))))
;; ;; (update :date #(.parse (java.text.SimpleDateFormat. "MM/dd/yyyy" %)))))
however also frustratingly i thought there would be a better way than 4 updates to convert the types
I would probably merge
into the record for something like this
(merge csv-record {:amount ... , :balance ... })
I think you've got the args slightly off on the date thing
(update :date #(.parse (java.text.SimpleDateFormat. "MM/dd/yyyy" %)))
->
(update :date #(.parse (java.text.SimpleDateFormat. "MM/dd/yyyy") %))
that should work, your % was just an arg in the wrong place
merge just merges N maps, last one wins
then the overridden keys will replace
then merge them and ensure the correct types are that 1 map and are put last in the (merge )
I'm just talking about in the function above which is just on a single record
(defn convert-various-types
"Convert Balance, Amount, Currency Rate to number
Convert Date to date"
[{:keys [amount balance currency_rate date] :as csv-record}]
(merge csv-record
{:amount (bigdec amount)
:balance (bigdec balance)
:currency_rate (bigdec currency_rate)
:date (.parse (java.text.SimpleDateFormat. "MM/dd/yyyy") date)}))
thinking out loud - what about an approach like (reduce-kv (fn [m k translation] (update m k translation)) input {:amount bigdec :balance bigdec ... ...})
and handy enough, that just translates to (reduce-kv update input {:amount bigdec :balance bigdec ... ...})
since update already has the right arg list
that looks significantly harder to read/maintain to me, but I'm dumb :)
oh, yeah - thats' why I split it in two, but it's still weird
yes, you can make some sort of general transformation framework out of stuff like this
in general, I find the result is rarely worth the effort
esp if you're doing it once
quick question about the destructured solution as this would have never come to my mind
am i correct to say that it would be much more code on each line to get the right key from csv-record
Yeah, that's right.
really, a large percentage of clojure functions look like this :)
is there a fn like doseq
or for
that short circuits evaluating the rest of the sequence if any body expr throws an error?
I wonder if you could make for stop at an excption though (in terms of the sequence returned)
yep, it seems like I was using ex-info
incorrectly within a doseq block. an ex-info
call without a cause argument wasn’t causing a breakout of the doseq for some weird reason
ex-info is just a constructor, it doesn't throw anything
user=> (type (ex-info "foo" {:a 0}))
clojure.lang.ExceptionInfo
yep, that explains it! seems like if there’s a cause
added to the constructor it’ll get caught by a catch
block without calling throw
, otherwise not so much
there's a potential for confusion, because the way an ex-info object prints in a repl
no, that is not how anything works
you need to call throw, (or else maybe create the ex-info incorrectly, so that the attempt to create it throws... - which works accidentally)
even if you provide the cause arg, it's still just an object, which doseq would silently ignore
user=> (type (ex-info "foo" {:a 0} (Exception. "bar")))
clojure.lang.ExceptionInfo
yes you’re correct. I understand. I was looking at something in the repl from a previous execution
Hello everyone. I am fairly new to Clojure. I've been learning about Clojure since I read this article a little less than a year ago: http://blog.cleancoder.com/uncle-bob/2019/08/22/WhyClojure.html. I was fascinated, and as I have studied have loved how Clojure works. I'm eager to be here and to learn more.
Hi. When I start the repl with the 'clojure' command in Macos terminal, I am getting weird characters when pressing the arrow keys ^[[A etc. Is there a way to fix this ?
clojure
isn't meant for interactive usage, use clj
which has readline (clj and clojure are both installed with the http://clojure.org setup)
those "weird characters" are what arrow keys actually emit, and they will come through when you use programs that are not meant for interactive input