beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
West 2021-02-25T02:22:24.342700Z

So I’m looking for a GUI framework to use on desktop, something with minimal boilerplate. I think I can store my state in flat edn files.

West 2021-02-27T11:13:43.473500Z

Nevermind. Got tabs working just fine.

borkdude 2021-02-27T11:44:49.478300Z

I usually end up with a DB anyway even if I start with flat files. You can try datalevin if you want to use datalog. Else an embedded db like sqlite or hsqldb might also work well.

West 2021-03-01T21:08:36.029300Z

How exactly does something like Datalevin work? Does it create a file? If so, what file? What format? Is there a default location?

borkdude 2021-03-01T21:09:44.029600Z

I think you should compare it to sqlite: do you care in which format sqlite stores its db?

West 2021-03-01T21:13:32.029800Z

I more so want to be able to find it. Like I care if it’s a dotfile or stored in /tmp/ or something like that.

borkdude 2021-03-01T21:17:24.030Z

I just took a look at the datalevin binary.

borkdude 2021-03-01T21:17:33.030200Z

$ dtlv --help

  Datalevin (version: 0.4.9)

Usage: dtlv [options] [command] [arguments]

Commands:
  exec  Execute database transactions or queries
  copy  Copy a database, regardless of whether it is now in use
  drop  Drop or clear a database
  dump  Dump the content of a database to standard output
  load  Load data from standard input into a database
  stat  Display statistics of database

Options:
  -a, --all        Include all of the sub-databases
  -c, --compact    Compact while copying.
  -d, --dir PATH   Path to the database directory
  -D, --delete     Delete the sub-database, not just empty it
  -f, --file PATH  Path to the specified file
  -g, --datalog    Dump/load as a Datalog database
  -h, --help       Show usage
  -l, --list       List the names of sub-databases instead of the content
  -V, --version    Show Datalevin version and exit

Omit the command to enter the interactive shell.
See 'dtlv help <command>' to read about a specific command.

borkdude 2021-03-01T21:19:19.030400Z

In the code you will refer to the db file as (def conn (d/get-conn "/var/datalevin/mydb" schema))

borkdude 2021-03-01T21:19:25.030600Z

so it's pretty clear where it stores the data

West 2021-03-01T21:25:00.030800Z

Ah I see. Thank you for your help. Imma try understanding and implementing it now.

az 2021-02-25T02:25:02.342900Z

https://github.com/day8/re-com

πŸ‘€ 1
az 2021-02-25T02:26:08.343200Z

@c.westrom - This one looks promising

West 2021-02-25T02:27:54.343400Z

I think a reagent based tookit will be good as I’m quite comfortable with hiccup.

West 2021-02-25T02:29:14.343800Z

Was also checking out electron.

2021-02-25T02:29:45.344Z

I'm confused - if you're looking for desktop gui, why not use Swing

phronmophobic 2021-02-25T02:29:52.344200Z

Some of the options on desktop are: β€’ https://github.com/JetBrains/skija/ (no event handling afaik) β€’ https://github.com/cljfx/cljfx clojure library on top of JavaFX β€’ https://github.com/clj-commons/seesaw clojure library on top of swing β€’ any cljs lib + electron β€’ https://github.com/phronmophobic/membrane Obviously, I'm biased towards the last one (membrane)

πŸ‘ 1
West 2021-02-25T02:36:27.344700Z

Ok, maybe I don’t care about boilerplate too much. I could go with electron because it’s what I know and I have access to node for more flexibility.

πŸ‘ 1
phronmophobic 2021-02-25T02:37:20.345Z

I've used electron before and it works well

West 2021-02-25T03:03:34.345200Z

Anyone try using proton native with cljs?

pez 2021-02-25T07:24:17.345600Z

Been there! πŸ˜ƒ

pez 2021-02-25T07:24:36.345800Z

Also, 1 is not a prime. πŸ˜ƒ

em 2021-02-25T07:38:18.346Z

@qmstuart Your solution seems to be the fastest by far out of all the ones posted so far though!

em 2021-02-25T07:40:00.346200Z

just for fun, a (relatively) faster version with transients

(defn sieve-mask [n]
  (let [upper (inc n)
        mask (transient (vec (repeat upper true)))]
    (loop [p 2
           mask mask]
      (if (< n (* p p))
        (persistent! mask)
        (if (get mask p)
          (recur (inc p) (reduce #(assoc! %1 %2 false) mask (range (* 2 p) upper p)))
          (recur (inc p) mask))))))

(defn sieve [n]
  (let [mask (map vector (range (inc n)) (sieve-mask n))]
    (->> (filter second mask)
         (mapv first)
         (drop 2))))

(time (sieve 1000000))
;; => "Elapsed time: 485.8439 msecs"
Probably poorly optimized, would be interested to see how fast we could push this

pez 2021-02-25T07:57:28.346400Z

I don’t know how fast it can be pushed, but know it can be pushed quite a bit beyond that nice piece, @eagonmeng

pez 2021-02-25T07:58:48.346600Z

You can probably win some millisecs by starting with 3 and adding the 2 at the end.

Audrius 2021-02-25T10:51:11.347200Z

how would you merge list of maps into a map? :thinking_face:

2021-02-25T10:57:07.348700Z

(apply merge [{:a 1} {:b 2}])  => {:a 1 :b 2}

πŸ’ͺ 1
2021-02-25T10:57:38.349Z

@audrius are you looking for something like this

audrius 2021-02-25T11:03:21.349100Z

You could replay in a thread. That would remove a need to tag specific person and prevent from common mistake - tagging wrong person πŸ˜‰

🍻 1
πŸ˜„ 1
2021-02-25T11:11:49.349300Z

Sorry audrius, keep that in mind πŸ’‘

adam-james 2021-02-25T12:34:50.350Z

Hi everyone. I'm working on an SVG library and am wondering about idiomatic use of spec. I found myself creating a few predicate functions from my specs using s/valid? but wonder if this is actually a good way of using spec?

(defn pt2d? [a] (s/valid? ::pt2d a)) 
(defn pts? [s] (s/valid? ::pts s)) 
(defn element? 
   "Checks if `elem` is an SVG element." 
   [elem] 
   (s/valid? ::svg-element elem))
I use these functions (and specs) for :pre validation, but also inside conditionals from time to time.
(defn translate
  {:pre [(s/valid?
          (s/or :one (s/coll-of :svg-clj.specs/svg-element)
                :many (s/cat :elems (s/coll-of :svg-clj.specs/svg-element))) elems)
         (s/valid? :svg-clj.specs/pt2d [x y])]}
  (let [elem (first elems)
        elems (rest elems)]
    (when elem
      (cond
        (and (specs/element? elem) (= 0 (count elems)))
        (translate-element [x y] elem)
        (and (specs/element? elem) (< 0 (count elems)))
        (concat
         [(translate-element [x y] elem)]
         [(translate [x y] elems)])
        :else
        (recur [x y] (concat elem elems))))))
I have a hard dependency on spec in my library, and I don't know if that's a good idea, or if it's advisable to re-work things and make it unnecessary. I have an open issue on the project related to this question. https://github.com/adam-james-v/svg-clj/issues/2 Any advice is greatly appreciated :)

borkdude 2021-02-25T12:37:28.350600Z

I don't see a problem with your usage of spec right now. Except that you maybe might want to add some explain output if things are not valid

πŸ‘ 1
adam-james 2021-02-25T12:39:56.351100Z

Ya, I noticed while I was using it that I still asked "but why did that fail?" s/explain should help with that at least.

borkdude 2021-02-25T12:43:04.351400Z

@adam.james It might also be interesting to look at malli, which is a more data driven approach to data validation. I am considering adding that to babashka if people are in favor of this. It's not an either/or between spec, but spec is still in development, whereas malli is already out of the alpha stage.

adam-james 2021-02-25T12:45:47.351900Z

Hmmm... I'll give that a look/experiment a bit. The original thinking for spec was to 'use the official tools'. It's also why I stick primarily with deps.edn vs lein. But it's not a strongly held opinion of mine, so I'm willing to change. Thanks for the tip!

borkdude 2021-02-25T12:47:22.353100Z

The official things aren't always better than community things, but it is a benefit that something is built-in.

Jim Newton 2021-02-25T12:48:03.353900Z

What is the correct way to control the clojure random number generator. I see the functions https://clojuredocs.org/clojure.core/rand-int and https://clojuredocs.org/clojure.core/rand ? But I don't see the discussion of how to get and set the random seed, how to reset the generator to a previous state (e.g., for reproducing errors in functions which use random numbers), and how to assure (or whether it is assured) that new processes get their seed set the same way.

borkdude 2021-02-25T12:50:31.354900Z

@jimka.issy It's probably better to use a library like clojure.data.generators or clojure.test.check for this

borkdude 2021-02-25T12:50:46.355100Z

or raw Java interop

2021-02-25T13:10:19.355200Z

In particular, class java.util.Random provides an explicit method to set the seed, and a variety of methods to get different distributions/types of randomly generated values from such a generator.

borkdude 2021-02-25T13:11:15.355600Z

There is also SecureRandom

Jim Newton 2021-02-25T13:32:17.355800Z

Sorry, to help me understand. are you suggesting I should avoid rand, rand-int and rand-nth, and in stead use the java Random interface? Or are you suggesting that rand, rand-int, and rand-nth promise to use the java Random interface, so I can mix and match them freely?

borkdude 2021-02-25T13:34:53.356Z

the first, if you need seed

1
2021-02-25T13:37:35.356200Z

I believe that the JVM methods used by the Clojure function rand has no way of setting a seed explicitly.

2021-02-25T13:37:50.356400Z

That is the reason for suggesting the former, if you want to explicitly assign seed values.

1
NoahTheDuke 2021-02-25T16:10:43.364900Z

sometimes i run a lein run command and after completion, the process doesn't exit, so I have to CTRL-C to exit

NoahTheDuke 2021-02-25T16:10:52.365200Z

anyone know why this happens or how I can prevent it?

blak3mill3r 2021-02-25T16:27:58.367Z

@nbtheduke that depends entirely on the code that's being run, but a couple things you might check for are https://www.baeldung.com/jvm-shutdown-hooks and https://stackoverflow.com/questions/8695808/clojure-program-not-exiting-when-finishing-last-statement

blak3mill3r 2021-02-25T16:29:54.368Z

if the code ever uses pmap for example, there are going to be non-daemon threads running (which prevents the JVM from shutting down)

alexmiller 2021-02-25T16:33:59.369Z

https://clojure.org/guides/faq#agent_shutdown

NoahTheDuke 2021-02-25T16:35:36.369700Z

Thanks! I'm not using pmap anywhere, but I do call require instead of using :require in the ns macro. i'll poke around to see what i'm missing

NoahTheDuke 2021-02-25T17:03:44.372Z

turns out I had a call in another file that was doing somthing like that. thanks for the heads-up to both of you!

πŸŽ‰ 1
ivar 2021-02-25T17:54:35.373800Z

q: does anyone have a recommendation for clojure friendly jvm instrumentation ? Something like newrelic or dynatrace

blak3mill3r 2021-02-25T18:04:01.375800Z

https://github.com/kumarshantanu/preflex

πŸ‘€ 1
blak3mill3r 2021-02-25T18:04:06.376100Z

Instrumentation for what purpose? Profiling? Perhaps this can be useful:Β https://github.com/jgpc42/jmh-clojureΒ (edited)

ivar 2021-02-25T18:04:55.376400Z

hmm. I'm looking to get metrics on our app's performance and to capture errors

pyry 2021-02-25T18:08:55.376700Z

There are obviously a number of choices; Elastic APM has worked fine for me. Quite easy to write your own simple wrapper around the Java agent API. Or I guess you can also take a wrapper such as https://github.com/Yleisradio/clojure-elastic-apm, provided to you by the Finnish national public broadcasting company.

πŸ‘ 1
seancorfield 2021-02-25T18:14:29.377300Z

@ivar We'll been using New Relic in production for years with Clojure and we've been very happy with it. A couple of caveats: if you're using a "non-standard web server", such as http-kit, New Relic doesn't support that very well (we switched back to Jetty to address this); adding Trace metadata is a bit of a pain -- I blogged about that some years ago on https://corfield.org/blog/2013/05/01/instrumenting-clojure-for-new-relic-monitoring/ (and see also https://corfield.org/blog/2016/07/29/clojure-new-relic-slow-startup/ which may have been addressed in a later New Relic release but I think we still have that config in place).

πŸ‘ 1
ivar 2021-02-25T18:29:54.382900Z

ok, I'm familiar with newrelic from my days as a rails dev, so I think I'll start exploring that now that I know it's viable.. Thank you everyone for your feedback - very much appreciated!

Eric Ihli 2021-02-25T18:38:43.384800Z

Thoughts on this idea? I'm trying to turn a Trie data structure that is represented in Clojure as a HashMap (`{"D" {"O" {"G" {:val "DOG"} "T" {:val "DOT"}} :val "DO"}}`) into a "https://www.aclweb.org/anthology/W09-1505.pdf" which is just a raw array of bytes in a particular order. To work with that trie-as-a-byte-array data structure, I need some help navigating around the byte array. I was thinking some type of "cursor". It has a reference to the byte array, but all the iteration protocols are implemented by adjusting the location of the cursor. Something like this...

(defprotocol IByteArrayCursor
  (loc [_])
  (jump [_ loc] "Moves location of cursor to specified index.")
  (forward [_] [_ n])
  (backward [_] [_ n])
  (slice [_ end])
  (ba= [_ other-ba]))

(deftype ByteArrayCursor [ba loc]
  clojure.lang.Indexed
  (nth [_ i]
    (if (and (>= i 0)
             (< i (count ba)))
      (ByteArrayCursor. ba i)
      (throw (ex-info "Index out of bounds."))))
  (nth [self i not-found]
    (if (and (>= i 0)
             (< i (count ba)))
      (ByteArrayCursor. ba i)
      not-found))

  IByteArrayCursor
  (loc [_] loc)
  (jump [_ loc] (ByteArrayCursor. ba loc))
  (forward [_ n] (ByteArrayCursor. ba (+ loc n)))
  (backward [_ n] (ByteArrayCursor. ba (- loc n)))
  (slice [_ n]
    (loop [i 0 r []]
      (if (or (= i n)
              (>= (+ loc i) (count ba)))
        (ByteArrayCursor. (byte-array r) 0)
        (recur (inc i) (conj r (aget ba (+ i loc)))))))
Is this reasonable? Am I overlooking a simpler alternative? Am I not seeing any particular "gotchas"? Thanks for any thoughts anyone has.

dpsutton 2021-02-25T18:42:38.385300Z

i think you're making a zipper. i'd check out that

seancorfield 2021-02-25T18:43:14.385800Z

Feel free to DM me with Qs if you run into issues with New Relic and Clojure @ivar

πŸ™ 1
2021-02-25T18:43:17.386100Z

It seems odd that a 'cursor' implements a slice operation like that. If the cursor is really just an index into a byte array ...

ivar 2021-02-25T18:49:09.386600Z

thanks - the project I'm instrumenting uses aleph, so I have a feeling it fits in the 'non-standard' category

2021-02-25T18:49:26.386800Z

http://recurial.com/pldi19main.pdf may be up your alley

Eric Ihli 2021-02-25T18:50:09.386900Z

That's a good point. I might not need it. I'm basically doing a lot of packing and unpacking bytes. So I'll read one byte that says "The next 20 bytes make up that value you want to decode.". Then I'll take a 20 byte slice and send it to the decode function. That decode function also makes use of the cursor functionality. But it eventually reads all the way to the end of whatever its given. I guess another type of interface that would give me the functionality of being able to read from the start to the end of some bytes in the middle of a byte array would be a "view" rather than a "slice".

seancorfield 2021-02-25T18:51:07.387500Z

Definitely. I was able to get some way with http-kit by explicitly telling New Relic to instrument certain classes/methods via configuration. Not sure if I still have that on hand but I can search our repo history for it if needed.

2021-02-25T18:51:11.387800Z

are you aware of java.nio.ByteBuffer?

2021-02-25T18:51:33.388100Z

(it is super mutable, which is meh)

2021-02-25T18:52:07.388400Z

but it basically does all those things

robertfw 2021-02-25T18:52:26.388500Z

My thought when seeing spec wrapped up in :pre/:post is that you may want to look at using s/fdef in concert with either clojure.spec.test.alpha/instrument (which will verify that that function arguments match your spec) or the orchestra library which does similar but also checks that function outputs are what you specify

robertfw 2021-02-25T18:52:59.388700Z

You may want to drop into #clojure-spec if you want to discuss in more detail

robertfw 2021-02-25T18:54:27.389200Z

I just tried out the clojure-metrics library the other day for the first time, it may have some useful tools for you. https://github.com/metrics-clojure/metrics-clojure/

πŸ‘€ 1
Eric Ihli 2021-02-25T18:55:06.390Z

Oh interesting. That looks like a great idea. I think a wrapper around ByteBuffer will be nice.

seancorfield 2021-02-25T19:05:09.391100Z

We just recently migrated from New Relic's old plugin architecture (and their ancient metrics Java lib) to the new Telemetry SDK stuff which provides access to their Metrics API as well as Logging API and a couple of other APIs. Apart from the resolutely Java-focused API design, it was pretty easy to get it all integrated and working. We publish a lot of custom application metrics. (I ranted about this SDK on Twitter recently because of the custom types it uses to try to encapsulate what could just be a regular hash map!)

Scott Starkey 2021-02-25T19:22:59.397600Z

Hi there, folks. I’m trying to sort a map with an initial decreasing numeric sort and a tie-breaker alphabetical sort.

[{:name "Andy", :score 22} {:name "Charlie", :score 25} {:name "Bruce", :score 25} {:name "Xerxes, :score 7}]
This should sort to be:
[{:name "Bruce", :score 25} {:name "Charlie", :score 25} {:name "Andy", :score 22} {:name "Xerxes, :score 7}]
The tie of β€œ:score 25” is resolved alphabetically by the :name field. I’ve looked at sort-by and it shows examples of tie-breaker sorts. I see examples of https://clojuredocs.org/clojure.core/sort-by#example-542692cbc026201cdc326c2c with juxt, and examples of overriding with https://clojuredocs.org/clojure.core/sort-by#example-57ae5e86e4b0bafd3e2a04f1 with >. However, I’m having problems finding examples that combine the two. Can someone help? Thanks in advance!

seancorfield 2021-02-25T19:24:34.398300Z

@scotto (juxt (comp - :score) :name) is probably good enough for your needs here?

seancorfield 2021-02-25T19:25:27.399200Z

Although your data seems to have a string for the :score for "Andy" -- is that true? (that scores can be strings or numbers)

seancorfield 2021-02-25T19:27:11.400900Z

If you have to deal with potential strings sorting as the number they represent, you'll need a helper function in there, something like (fn [s] (if (string? s) (Long/parseLong s) s)) -- which can go in the comp between - and :score

Scott Starkey 2021-02-25T19:30:12.401300Z

Oops, I did not mean a string for Andy’s score. πŸ™‚ Thanks for the catch

ivar 2021-02-25T19:32:06.401500Z

looks like I have the go-ahead to change our webserver from aleph to jetty, so that's step one. I'm hoping it's as straightforward as it seems 🀞

2021-02-25T19:37:41.402500Z

speaking of Andy https://clojure.org/guides/comparators is a guide for writing and using comparators in clojure, which is another way to do this

πŸ‘ 1
Scott Starkey 2021-02-25T19:39:18.402800Z

I’ll check it out.

Scott Starkey 2021-02-25T19:43:49.403400Z

Wow @hiredman - That page is excellent and thorough! Thanks!

Scott Starkey 2021-02-25T20:04:23.406800Z

Also, I had to scratch my head a while about the minus sign in @seancorfield’s example above. I think the minus sign is a negative-making function, so sorting by the scores negatively sorts them descending. That’s a nice little trick! Thanks!

seancorfield 2021-02-25T20:15:48.407600Z

(comp - :score) = (fn [data] (- (:score data))) or (fn [data] (- 0 (:score data)))

seancorfield 2021-02-25T20:16:10.407900Z

There's also clojure.core/unchecked-negate

dev master 2021-02-25T22:43:14.408600Z

is it possible to load a clojure script file from java, and then execute a function from that clojure file?

2021-02-25T22:46:34.409Z

if you mean a clj file, yes it's pretty easy https://clojure.org/reference/java_interop#_calling_clojure_from_java

2021-02-25T22:47:13.409500Z

one call to require the ns, another to lookup the function, then you can invoke it