This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-02
Channels
- # announcements (37)
- # babashka (9)
- # beginners (172)
- # calva (7)
- # cestmeetup (28)
- # chlorine-clover (27)
- # clj-kondo (2)
- # cljs-dev (45)
- # cljsrn (8)
- # clojure (185)
- # clojure-dev (27)
- # clojure-europe (6)
- # clojure-finland (3)
- # clojure-nl (5)
- # clojure-uk (13)
- # clojuredesign-podcast (4)
- # clojurescript (54)
- # conjure (19)
- # core-typed (1)
- # cursive (40)
- # datomic (9)
- # emacs (5)
- # figwheel-main (34)
- # fulcro (238)
- # graphql (14)
- # hugsql (3)
- # leiningen (4)
- # malli (6)
- # off-topic (12)
- # pedestal (5)
- # portkey (19)
- # protorepl (8)
- # rdf (2)
- # re-frame (23)
- # reagent (3)
- # reitit (16)
- # shadow-cljs (29)
- # spacemacs (12)
- # sql (1)
- # xtdb (15)
I am trying to use Testcontainers for my current projects’ integration tests, and I have a question about the form. If I use Java Interop and set up the fixtures myself, it looks like this:
does GenericContainer have side effects on construction?
I believe not on Construction. It only interacts with docker upon .start and .end
Of course the builder pattern used by the lib manipulates the instance with every call
I figured this is a lot of boilerplate code, so I thought about creating a macro which creates the def
with the provided label, sets up the fixture and wraps the testcontainer object so its properties can be accessed with keywords. Maybe it will allow overriding the use-fixtures method, too, for more flexibility. I don’t have much experience with Macros, so what do you think of the idea? Will this come back and bite me after some time? Is there a more idiomatic way to solve this? Or should I just write a small testcontainers wrapper and keep the definition and the fixture separate for more readability?
dear all, how to put a vector of maps to a single map, with each key as the key in maps and value as a vector of values? Thanks!
@U011J2CQT0F Mayhaps, you are looking for reducing with https://clojuredocs.org/clojure.core/merge-with ?
something like this:
[{:name "A"
:age 11}
{:mame "B"
:age 12}]
=>
{:name ["A" "B"]
:age [11 12]}
(merge-with
(fn [v1 v2]
(let [v1' (if (vector? v1) v1 [v1])]
(conj v1' v2)))
{:name "A" :age 11}
{:name "B" :age 12}
{:name "C" :age 13})
=> {:name [“A” “B” “C”], :age [11 12 13]}Well… 🙂 we assumed they are strings initially… if you have such irregular data, that’s a problem in itself I would say… I would make sure my inputs are consistent (if I have control over it)
(apply
merge-with
into
[{:name ["A"] :age [11]}
{:name ["B"] :age [12]}
{:name ["C"] :age [13]}])
=> {:name [“A” “B” “C”], :age [11 12 13]}A generic solution based on the code of merge-with
:
(defn merge-into-vecs [maps]
(when (some identity maps)
(let [merge-entry (fn [m e]
(let [k (key e) v (val e)]
(update m k (fnil conj []) v)))
merge2 (fn [m1 m2]
(reduce merge-entry m1 (seq m2)))]
(reduce merge2 {} maps))))
Maybe identical?
will help you? https://clojuredocs.org/clojure.core/identical_q
The valid use cases for identical?
are pretty unusual in Clojure, since =
is often what you want. But I won't belabor the point if you know you need identical?
for some reason.
Is there a preferred way to create a map from a seq of key-value pairs? I use both (reduce conj {} collection)
and (into {} collection)
but I'd like to settle on whatever is more popular. I checked the clojure style guide but haven't found an entry on the subject.
pretty sure everyone uses into {}
now that I see the question on the screen and out of my head it all makes sense. I feel a bit silly now 🙂
Hi, I am trying to create a map of ngram frequencies from a decent text file. The code I wrote emits an OutOfMemory. While the same thibg can be easily done with Python and C++ code, with less than 20% of the memory that Clojure needs. Following I will post parts of the code. Can anyone tell me how to get better on memory use?
Clojure uses more memory by design, but not that much more. I can go over the code if you post it.
Thank you very much for your reply. I have posted the code the uestion already. Here it is again.
Hi, I am trying to create a map of ngram frequencies from a decent text file. The code I wrote emits an OutOfMemory. While the same thibg can be easily done with Python and C++ code, with less than 20% of the memory that Clojure needs. Attached is my code. Could anyone, please, tell me how to get better on memory use?
I don't see anything obviously wrong here. One thing that might help is skipping the joining of the ngrams
(defn ngrams [n N sent]
(let [s (str/split sent #"\s+")]
(for [i (range n (inc N))]
(partition i 1 s))))
(defn ng-count [n N filename]
(with-open [rdr (io/reader filename)]
(->>(line-seq rdr)
(mapcat (partial ngrams n N ) )
(map frequencies )
doall)))
Every JVM string object has an overhead of about 40 bytes, regardless of its length, so representing N-grams as vectors of N strings, rather than creating a new string, might save memory. There is still some memory allocated for each vector object, too, so those two approaches might end up near the same memory, after all.
Thank you very much for your replies, Chrisblom and Andy. That is very helpful. I actually tried many values for -Xmx from 1000 to 2000.
I noticed something else, which I have no clear information of. I noticed that the program runs in multithreaded manner. Are the threads created for the processing executed by the program or they are rather Java's utilities to handle internal tasks?
There are multiple different garbage collection methods that modern JVMs implement. Some of them use separate threads, and can take advantage of separate CPU cores from those that execute your main code, to perform garbage collection.
Determining whether that is what is happening in your case is possible, with appropriate examination of the JVM's operation, e.g. using some kind of JVM profiler tool that can attach to a running JVM.
You can also type Ctrl-\ in a terminal from which the JVM was started to cause it to dump out info about all threads, maybe more detailed than you would like, which might help you discover what the threads are called, at least, and a snapshot of what their current stack trace is for the code they are executing.
@U015D447PSL took a stab at your question and only now realized that Slack showed me a 7 day old thread. 🙂 Anywho, it may still be relevant - I think you can save a lot on memory, by not creating so many temporary thunks and using transducers. Here's a gist as an example. Probably some things could be even more elegantly described, but hopefully this gives you some ideas: https://gist.github.com/pithyless/44ce8908cee196fd3f5ace685b8db2f4
not sure is it more idiomatic or not, but that is the form that I’m using a lot
Needing this function might indicate you are doing https://stuartsierra.com/2015/06/10/clojure-donts-heisenparameter
I’m trying to define a function in a macro, where the function name depends on one of the values that gets passed to it:
(defmacro foo [m] `(defn ~(symbol (:k m)) [])
(let [arg {:k "foo"}] (foo arg)) ; => IllegalArgumentException
How can I get this to work?@wombawomba macros are passed their arguments unevaluated, so foo
is invoked with the literal symbol arg
in that case.
Right. Is there a way to evaluate it before defining the function?
Macro expansion happens before code evaluation. The let
hasn't been evaluated when foo
is macroexpanded.
you can do this without a macro:
(defn define-function [m]
(intern *ns* (symbol (:k m)) (fn [])))
(let [arg {:k "foo"}] (define-function arg))
Okay yeah that makes sense. Are you saying I should be using a regular function here?
@smith.adriane thanks! What if I want to use schema.core/defn?
using define-function
as above probably isn’t a good idea. do you have little more information about what you’re trying to do?
I'm trying to autogenerate a bunch of functions from a data structure
is there a reason the functions need to be interned into the namespace?
Well, I want them to act as regular functions in a particular namespace
what's the benefit of putting them in the namespace?
I mean, if the names are generated like that, how does the caller even know what they are
often the solution is to define a top level hash-map, and put the functions in there
Wouldn't knowing what the keys are in the hash map cause the same problem?
you can iterate hash-maps, you can ask for the keys, etc. - they are meant to be used as data
Either way, I wouldn't worry about the caller :) I'm more concerned about getting this to work
treating a namespace that way is clumsy, less efficient, and more brittle
data-structure-like operations are added to namespaces to make them more useful / extensible, but they still aren't as useful or extensible as data structures are
Yeah got it, although I still think doing it this way is appropriate for me.
I mean, it's not really that clear-cut – after all, what I'm doing here is almost the same thing as what defn does, only one level up
And surely there's a reason that people prefer to use defn over a top-level hashmap of fns
if you really wanted to intern a variable, you can probably use schema’s schematize-fn
it’s a lower level api that schema.core/defn
relies on
ymmv, but based off your use case description so far, it does seem like you’d want to use something like a top-level hashmap of some sort
Well, the main thing I'm after is the regular compile-time guarantees of the function calls
As well as the regular documentation etc with codox et al
Is there a way to get those with a hash map?
I'll look into schematize-fn, thanks :)
there are ways to have a toplevel hashmap work with docs and compile-time checks. do you have an example of the hashmap you’d be using to generate code from?
the compile guarantees yes, you won't get compatibility with eg. codox without adding :doc
metadata (and I'm not for sure that always works)
Not really, although if you pointed me in the right direction I would be able to figure it out
For the compile-time guarantees, how can I be sure that somebody calling ((:my-fn my-ns/my-hashmap)) doesn't have a typo in ':my-fn'?
where is this :my-fn coming from?
you don't, but you also don't have any guarantee when they use resolve
, and if they don't need resolve
than you already have the hard coded function list somewhere
It's just an example of one of the functions I'd be using
Yeah I'm not going to be designing for anybody to use resolve :)
if you already have the hard coded list you can just use defn
Sure, I could do that
But it'd be a whole lot of extra work, and possibly a pain to maintain
So I'd prefer not to
So will programmers be manually typing calls to automatically generated functions?
Also while we're on this topic, is there a way to get autocomplete in e.g. nrepl to work the same way as for a regular functioning if I use a top-level hashmap?
I'd also like for clojure.repl/source to work
ok, sounds good. without knowing where this hashmap that is being used to generate specs and intern vars is coming from, then it’s hard to give more specific advice. if you’re autogenerating functions based off some server schema file that’s used by multiple servers and languages, then that could make sense. if you’re autogenerating functions based off of a hashmap that’s defined in a let statement, then there’s probably an easier, more flexible way.
Yeah it's more like the former :) not really multiple languages, but both cljs and clj at least
I could skip the let and put the 'generated' fn name in the macro call, which I guess would help me avoid this, but I want to enforce a one-to-one mapping between the things I'm iterating over and the functions.
if the autogenerated data source is still clj(s), then simply having code in cljc should allow you to have more straightforward approach than autogenerating functions
it’s also worth noting that intern
is not available in cljs, so that approach will not work
Right
So returning to my original question, is there no way to compute a symbol and then call def(n) with that symbol?
via eval (not available in cljs)
or a macro, in limited cases
Which limited cases?
ones where the symbol is a compile time literal
Hmmm okay. Guess I'm not completely sure what constitutes a compile time literal. What's an example (of a compile-time literal that can be built through a computation)?
there might be some workaround, but it’s very difficult to provide more specific advice since it would depend on the use case. I’m not sure how to suggest more things to try without some example code of what you’re trying to do
Well, I'm basically trying to do the exact thing I typed up in the original question, but in a loop
(at the top level of a particular namespace)
I suppose one thing I could do is manually spell out all all the bindings, then have some separate compile-time logic that verifies that those bindings are an exact match for the data structure I'd be generating them from.. but that seems a bit inelegant to me
it sounds like you want some type of instrumentation and validation. here are some resources that might provide inspiration: • https://github.com/jeaye/orchestra • https://clojure.org/guides/spec#_instrumentation • https://github.com/clojure/core.typed • https://clojure.org/guides/spec#_using_spec_for_validation
clojure isn’t all in on compile time checking. however, clojure does have other facilities for verification, validation, catching errors before production, etc.
I guess if it is interesting, I might as well go into a bit more detail about what I’m doing. Basically I have a somewhat complex HTTP API that’s defined via reitit (https://github.com/metosin/reitit) routes, and that I’m calling in multiple different projects (both clj and cljs). I want to generate bindings for all these routes such that: 1. I can use them as regular fns in a clj(s) repl. 2. I get compile-time guarantees that they’re being used correctly in my clj(s) code. 3. I get compile-time guarantees that there are no bindings missing, and there are no ‘extra bindings’ (e.g. if a route is removed). 4. I get nice autogenerated documentation for them.
Not sure if this helps but:
(defmacro foo [m]
`(defn ~(symbol (:k m)) [] (+ 1 1)))
(defmacro doseq-foo [a-macro & args]
`(do
~@(map (fn [arg] `(~a-macro ~arg)) args)))
Yeah that’s pretty close to what I want to do
I agree with other though that there’s probably a simpler way to achieve whatever you’re trying to do…
The problem I guess is that the route data actually looks more like:
["/foo"
["/bar" ...]
["/baz" ...]]
…and I need to ‘flatten’ it before defining the functions.Yeah, agree
I don’t see another way to get the stuff I listed above though
If you know of one I’d be all ears
@U055NJ5CC okay cool thanks, I was actually trying to do something like that
specifically I’m trying to do this:
(doseq [[path data] (reitit.impl/resolve-routes my-routes (reitit.core/default-router-options)),
:let [path-params (get-in data [:parameters :path])]
[method spec] (dissoc data :parameters)]
(defn-my-binding path method spec))
I guess your suggestion is cleaner though 🙂
either way, my problem of “how do I actually define the bindings” is still kind of unsolved
Not sure if this helps it:
(defmacro doseq-foo [a-macro args]
`(do
~@(map (fn [arg] `(~a-macro ~arg)) args)))
Now you can do:
(doseq-foo
foo
[{:k "f40"}
{:k "f41"}
{:k "f42"}])
But unless you have the
[{:k "f40"}
{:k "f41"}
{:k "f42"}]
“ready” at compile time… it won’t work… I believeHmm yeah, the thing is that I do have all the routes at compile-time, so I suppose maybe it could work?
does it matter if the vars are available in both clj/cljs or is it mostly for convenience at the clj repl?
Well ideally I'd like to use the bindings in both cljs and cljs
If the repl experience isn't as good in cljs then that's fine
@wombawomba I believe the cljs macros need to be in .cljc file (not sure if you’ve dealt with that)
Yeah I do have all of this in cljc
if the routes are available at compile time. I would probably do something like
(def-routes-and-schemas-and-fns
;; routes
[[route-definition-1]
[route-definition-2]
...])
and have that macro generate all the stuff you need
Okay yeah that sounds like a good solution to me
I assume that'd work even if the args would actually be (flatten-routes (generate-routes))?
(the routes are defined as a tree, so I need to flatten them first)
macros allow for syntactic abstraction, so I would just describe the routes however is most appealing and have the macro figure out how produce the right code (flattening/etc)
the way I like to think about it, is use whatever form I would use if I was writing pseudo code on paper or at the whiteboard and then create the macro to match that syntax
fun stuff:
(defn fn->sym [fn]
(when-let [[_ str] (->> fn
class
.getName
Compiler/demunge
(re-matches #"^([^/]*?/[^/]*?)(--\d\d\d\d)?$"))]
(symbol str)))
(fn->sym assoc) => clojure.core/assoc
(fn->sym inc) => clojure.core/inc
Clojure.spec.alpha has this function. My codebase too I use to test if some functions are defined in the right namespace (naming conventions etc'..)
just be aware that demunge is best effort and will not work in all cases (importantly both - and munge to and demunge can't know which is right)
there may be other cases that don't work
(also, spec 2 no longer has this function because specs are always resolved in terms of symbols, not as function objects)
changes may need to be made in the future wrt to mappings from fns to classes (class names can get too long for the filesystem due to nesting) and at that time, this hack will also stop working for those classes
as long as you understand all those caveats, have at :)
ser=> (fn->sym (fn foo []))
nil
user=> (-> (fn foo []) class .getName)
"user$eval208$foo__209"
OK - just saying, it does have a name
your code doesn't use resolve
but your use case is to be able to resolve and thus see new definitions?
Guys, how many libs we have to support gRPC on clojure?
before you go for gRPC, make sure you really can explain why you need it; in my little experience with it, it doesn’t work well with the Clojure philosophy of doing things; it’s more of a Golang tool
I do not know how many, but one named protojure shows up in a Google search for "clojure grpc". There are also several examples of using Java interop from Clojure to call Java gRPC methods, which for some Java libraries is a very reasonable thing to do in a Clojure program.
just to know, in my company we're having a discussion to know if it's possible to adopt gRPC and I was suggesting some red flags, I saw that only had protojure and java API integration.
Clojure is hosted on the JVM as a design choice, not an accident, specifically to make it straightforward to take advantage of the huge number of Java libraries that exist.
yup, but not too much stuff are made in Java using gRPC
That I have no knowledge to share.
and I thought that gRPC was not a good choice, maybe some day Avro?
but thanks @U0CMVHBL2 @U050KSS8M 😃
I don't know if that is much of a minus, if the Java support works, but I also have no experience reports to share with you, good or bad, in that regard. I mean, one of the purposes of gRPC of course is to have a language-independent data communication mechanism, but that doesn't mean that all languages support it equally well.
@U9ABG0ERZ no problem! If your company is mostly Clojure, I would stick with Clojure’s transit where possible
“it doesn’t work well with the Clojure philosophy of doing things” I disagree with this, gRPC is language independent and has a really solid way of defining service contracts. That being said I probably wouldn’t write a gRPC service in a non-statically typed language like Clojure, but a client would work just as fine.
@UDBM9Q0VC have you used gRPC from Clojure?
just as a consumer of a grpc service
I think the primary complaints I have heard (and some people really hate it) have been about the need to edit and re-generate the generated code. This is fundamentally because people are just wrapping the java libraries. From what I have read(and at one point I was thinking to implement a "native" protobuf library in clojure, so I have read a bit) there is nothing stopping an inherently more dynamic experience on clojure, just no one has done the work yet, so you likely will run into all the same annoyances as others
We have a home grown RPC library, based on HTTP and Avro - the lack of recompilation step is a huge win. I've looked at gRPC and it has a really big surface, requires ProtoBuf recompilation and if your frontend (js/cljs) has to call your API/RPC server - there is (was? ) no good answer apart from a half-baked proxy. Oh, and also - it requires using HTTP2, which might not work in your setup (for example AWS ELB (classic) doesn't support it)
Yeah, I totally agree the compilation step is a pain. And there are similar issues using protobuf outside of gRPC with Clojure or Java. But at the cost of having a really solid contract, it makes total sense for some use cases. In our case we were building out a replacement for an old https://docs.geoserver.org/latest/en/user/services/wfs/reference.html that traditionally uses RPC and XML. I think there are some great use cases for it but at the same time I could understand the frustration of using it when there are simpler more popular solutions.