beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
sova-soars-the-sora 2021-04-01T00:12:31.336200Z

awesome

sova-soars-the-sora 2021-04-01T01:23:42.336800Z

I have a collection of maps, I want to find the maximum :timestamp across all elements...

sova-soars-the-sora 2021-04-01T01:31:26.337800Z

something like (first (sort-by val > :key map)) gets the result...

aratare 2021-04-01T01:31:51.338300Z

(apply max-key :timestamp your-coll-of-maps)

sova-soars-the-sora 2021-04-01T01:32:43.339Z

Neat! Can you explain how to think about the problem to get that solution?

aratare 2021-04-01T01:34:48.340600Z

well from your description, it’s like max but you want some way to get that inner timestamp, so you can use max-key to supply that

sova-soars-the-sora 2021-04-01T01:40:43.341200Z

yep that's exactly right. i don't really get how max-key works, but i will stare at it more

sova-soars-the-sora 2021-04-01T01:41:20.341400Z

that's very clean 😄

sova-soars-the-sora 2021-04-01T01:41:47.341800Z

Ah I think I get it. max-key is like max and get-in smashed together

sova-soars-the-sora 2021-04-01T01:42:21.342100Z

but we need apply... because why?

aratare 2021-04-01T01:43:01.343100Z

because max-key takes a number of args when you call it

aratare 2021-04-01T01:43:21.343700Z

again, it’s like max

aratare 2021-04-01T01:43:38.344100Z

you’d call (max 1 2 3), not (max [1 2 3])

sova-soars-the-sora 2021-04-01T01:43:45.344300Z

Ah i see

sova-soars-the-sora 2021-04-01T01:43:51.344500Z

righteous. thank you

aratare 2021-04-01T01:44:42.345400Z

just think of max-key as max, but you can supply a function to calculate the value which it’ll use to find the maximum

aratare 2021-04-01T01:45:20.346200Z

(= (max 1 2 3) (max-key (fn [v] v) 1 2 3) (max-key identity 1 2 3))

sova-soars-the-sora 2021-04-01T01:46:17.346500Z

very illustrative example and REPL'able! thank you

👍 1
aratare 2021-04-01T01:48:12.347300Z

I missed a paren at the end so if you ran it, it may not return 😅

sova-soars-the-sora 2021-04-01T01:50:21.347700Z

😄 i noticed but took it as a friendly exercise to the reader

sova-soars-the-sora 2021-04-01T01:50:58.348100Z

you solve the problems i balance the parens everyone feels smart 😛

😅 2
sova-soars-the-sora 2021-04-01T01:54:28.350Z

thanks a lot. if you're interested in what i'm tinkering with right now, i'm trying to apply this "send over only database deltas :since-timestamp" principle, so every so often the client says "i have up to timestamp ts-val" and the server checks the database of entries and returns things newer than that. pretty simple. i got the idea from @tonsky, "For dataset sizes up from few hundred kilobytes you start to feel need to transfer deltas instead of entire value." https://tonsky.me/blog/datomic-as-protocol/

👍 1
aratare 2021-04-01T01:58:14.351600Z

I’m also playing around with datomic at the moment. Seems really cool.

R.A. Porter 2021-04-01T02:07:01.351800Z

You might - if you’re not married to Datomic - also want to take a look at Crux. It’s a bitemporal database that might fit your specific need well.

aratare 2021-04-01T04:03:18.353500Z

Hi there. I’m stumbling across something and I’m not sure what’s going on. I have this block of code:

(case (class (OffsetDateTime/now))
    java.time.OffsetDateTime "a"
    String "b"
    false)
and somehow that’s evaluated to false even though I’m expecting it to be true. Am I doing something wrong here? Thanks in advance.

2021-04-01T04:09:03.353700Z

case takes unevaluated constants

2021-04-01T04:09:40.353800Z

String and java.time.OffsetDateTime are symbols that evaluate to classes

phronmophobic 2021-04-01T04:09:53.354Z

The test-constants are not evaluated. They must be compile-time literals, and need not be quoted
...
All manner of constant expressions are acceptable in case, including numbers, strings,symbols, keywords, and (Clojure) composites thereof.

phronmophobic 2021-04-01T04:10:27.354600Z

the short answer is you need something like cond or condp along with instance?

aratare 2021-04-01T04:48:41.355300Z

Ah I see. I’ve always thought classes themselves are constants. Thanks @hiredman @smith.adriane

👍 1
alexmiller 2021-04-01T04:50:04.355900Z

classes are not constants (and not even unique in the JVM - every classloader can potentially load their own version)

👍 1
alexmiller 2021-04-01T04:51:25.356500Z

case on class name is occasionally useful

alexmiller 2021-04-01T04:51:42.356900Z

(assuming you have a finite set of concrete classes to check)

aratare 2021-04-01T04:56:07.358700Z

Thanks @alexmiller. condp gives me the expected behaviour so things are finally working for me now 😅

Endre Bakken Stovner 2021-04-01T07:55:50.359800Z

Can I type hint a keyword? What is the incantation? I've tried ^clojure.lang/Keyword kw

Endre Bakken Stovner 2021-04-01T07:57:31.360300Z

Same question for {}. I've tried ^java.util.Map.

raspasov 2021-04-01T08:00:36.360400Z

(let [^clojure.lang.PersistentHashMap m {}]
  (assoc m :a 42))

Endre Bakken Stovner 2021-04-01T08:01:45.360700Z

Thanks 🙂

👍 1
raspasov 2021-04-01T08:03:01.361Z

(let [^clojure.lang.Keyword k :a]
  k)

Endre Bakken Stovner 2021-04-01T08:03:29.361200Z

Uh-oh: java.lang.IllegalArgumentException: Unable to resolve classname: clojure.lang/PersistentHashMap. Might there be something wrong with my setup?

Endre Bakken Stovner 2021-04-01T08:04:01.361500Z

No. I wasn't using all dots.

Endre Bakken Stovner 2021-04-01T08:04:06.361700Z

Why the difference?

raspasov 2021-04-01T08:06:06.361900Z

It’s a Java class; forward slashes are for accessing static methods

raspasov 2021-04-01T08:06:20.362100Z

(System/currentTimeMillis)

raspasov 2021-04-01T08:06:36.362300Z

Why exactly do you need to type hint?

raspasov 2021-04-01T08:06:44.362500Z

Generally, it shouldn’t be necessary

raspasov 2021-04-01T08:07:01.362700Z

It’s needed mostly for performance reasons.

Endre Bakken Stovner 2021-04-01T08:08:27.362900Z

The below function will - worst case - be called umpteen gazillion times:

(defn to-path [^String file ^clojure.lang.Keyword rule ^clojure.lang.PersistentHashMap wildcards]
  (let [rulename (name rule)
        wc (zipmap (map name (keys wildcards)) (vals wildcards))
        wc (->> wc sort flatten (clojure.string/join "/"))]
    (clojure.string/join "/" [rulename wc file])))
So I am hoping type-hinting will improve the performance a little.

raspasov 2021-04-01T08:11:50.363100Z

Also, to be “correct” type hint in all cases, use clojure.lang.APersistentMap:

(instance? clojure.lang.PersistentHashMap {})
=> false
(instance?
  clojure.lang.PersistentHashMap
  (into {} (comp (partition-all 2) (map vec)) (range 100)))
=> true
(instance?
  clojure.lang.APersistentMap
  {})
=> true
(instance?
  clojure.lang.APersistentMap
  (into {} (comp (partition-all 2) (map vec)) (range 100)))
=> true

raspasov 2021-04-01T08:12:25.363300Z

(type {}) => clojure.lang.PersistentArrayMap

raspasov 2021-04-01T08:12:40.363500Z

PersistentArrayMap is an optimization for small maps;

🙏 1
raspasov 2021-04-01T08:13:59.363800Z

I wouldn’t bother with such things unless you’re really chasing performance; if you really care about performance, use YourKit (but it’s a paid tool); you can almost never guess where your bottleneck is; it’s probably where you least expect it.

Endre Bakken Stovner 2021-04-01T08:16:27.364Z

But this is a cheap optimization (in terms of readability and programmer effort) which might matter a lot.

🙂 1
Aron 2021-04-01T09:57:08.366200Z

I think I know the answer, but would be nice to know definitely: if I have map with unqualified keywords, can I write a spec for those values mapped by those unqualified keywords? Or if I want values to be validated I need to put them in maps with qualified keywords?

2021-04-01T10:01:51.366300Z

(s/keys :req-un [::alias/foo] :opt-un [::alias/bar]) with (s/def ::alias/foo …) and (s/def ::alias/bar …) will be able to validate maps like this {:foo … :bar …}

Aron 2021-04-01T10:18:49.366500Z

Thanks, not sure why I missed this when reading the docs, I could find it now easily.

rafalw 2021-04-01T11:45:48.369200Z

Hi, I have java lib with constructor which i have to use, and this constructor requires instance of java's ExecutorService as an argument, what wil be the best way to use this lib from clojure?

alexmiller 2021-04-01T12:13:56.369600Z

You shouldn’t need to do so

alexmiller 2021-04-01T12:15:18.370400Z

Those type hints won’t do anything

alexmiller 2021-04-01T12:17:22.372800Z

Type hints are only useful in turning an ambiguous java interop call into an unambiguous one (to avoid reflection). There are no interop calls in this method, so those type hints are useless and ignored

Endre Bakken Stovner 2021-04-01T12:18:59.374800Z

Had no idea! Thanks

alexmiller 2021-04-01T12:19:29.375400Z

you generally never should make an interop call on types that are part of Clojure (you should use normal Clojure invocations to interact) and thus it’s very unusual to type hint Clojure classes

alexmiller 2021-04-01T12:20:36.377200Z

If you were to type hint a Clojure map, the correct interface is IPeraistentMap (not the APersistentMap abstract class - not all maps extend from that)

👍 1
👆 1
🙏 1
Endre Bakken Stovner 2021-04-01T12:34:15.377500Z

Thanks! I should start looking at the Clojure internals someday.

raspasov 2021-04-01T12:58:58.377700Z

re: interfaces, thanks for correcting my ignorance 🙂 @alexmiller

arielalexi 2021-04-01T13:52:38.381900Z

Hi 🙂 I want to use browse-url function on a windows OS in order to rederact to diffrent page. Is it possible to convert <http://java.net|java.net>.URL to clojure.java.browse ?

2021-04-01T13:56:23.382200Z

(str …) ?

✅ 1
arielalexi 2021-04-01T13:57:29.382500Z

yes that worked. (browse-url (str (<http://clojure.java.io/as-url|clojure.java.io/as-url> test-meow))) tnx :)

2021-04-01T15:07:51.386600Z

As far as I know, there’s no function like partial that can return a function given all of the arguments so I’m using def with an anonymous function like this:

(def fancy-now #(str "the time is now " (new java.util.Date)))
  (fancy-now)
Is this the right way to do this? Like the example, my function is an “action” in that it depends on external conditions.

2021-04-01T15:09:47.386700Z

I know it works, I’m just wondering if it’s idiomatic or if I’m missing a bigger picture idea.

agile_geek 2021-04-01T15:21:35.386900Z

Can’t you just define a fn that takes no args and then invoke it?

(defn fancy-now []
  (str "the time is now " (new java.util.Date)))

agile_geek 2021-04-01T15:25:48.387200Z

Or if you want to define it in-line:

(defn my-fn-that-uses-now []
  ....
  (str "the time is now " (new java.util.Date))
  ....)

agile_geek 2021-04-01T15:27:20.387400Z

Or if you want to you can ‘store’ the result in a var in a let:

(defn my-fn-that-uses-now []
  (let [now (str "the time is now " (new java.util.Date))]
     (fn-needing-now now)
     ....)

agile_geek 2021-04-01T15:32:18.387600Z

As an example say you have a fn that returns a map that needs to include the results of that str you might do something like this:

(defn my-fn-that-uses-now []
     ....
     {:name name
      :age 23
      :now (str "the time is now " (new java.util.Date))})

2021-04-01T15:42:47.387800Z

ok, my example wasn’t complex enough for what I’m doing but your comments helped me sort it out. It’s more like the following (which I can now use partial for): (defn fancier-now [greeting time] (str greeting "the time is now " time)) (def fanciest-now (partial fancier-now "Hello, ")) (fanciest-now (new java.util.Date)) In my real use-case, I can’t pass in (new java.util.Date) because I’m actually doing this for dependency injection and I don’t want fanciest-now to need to know about java.util.Date.

agile_geek 2021-04-01T15:52:03.388100Z

I don’t think I understand why you need the def for fanciest-now or the context of the invocation of fanciest-now so hard to give advice. Also dependency injection is not something we really do in Clojure. Tend to just use fn’s passed around in data if required. However, not sure if it’s useful but you can define a high order fn that returns a fn if required like so:

(defn fancier-now
  [greeting]
  (fn [time]
    (str greeting  "the time is now " time)))
(let [fanciest-now (fancier-now "Hello, ")]
  (fanciest-now (new java.util.Date)))

agile_geek 2021-04-01T15:55:38.388300Z

I used the let there simply to define the var for the anonymous fn returned from fancier-now but I could have used a def like you did i.e. (def fanciest-now (fancier-now "Hello, "))

agile_geek 2021-04-01T15:56:38.388500Z

I think there are probably more idiomatic ways to accomplish what you are trying to do but I don’t have enough context to suggest any.

2021-04-01T16:54:22.388800Z

Sorry for the slow replies, I have to think about the suggestions and my use case. The context seems somewhat complex to me so I didn’t want to trouble anyone with it but here’s as short as I can describe it: • I’m interfacing a chip via i2c to read environment data • I’m waiting for interrupts to know something changed which I read via gpio • when there’s a gpio interrupt, I read the i2c chip for data • I have a namespace for using gpio to information-hide those details • I have a namespace for i2c to information-hide those details • Since this is all asynchronous in nature, I have to run this all from an async/go routine So the code goes something like this: (def chip-context (chip/setup-chip …)) (async/go (gpio/handle-events chip/event-handler chip-context deserializer event-channel …)) So when I say I’m “injecting dependencies” I only mean I’m passing in functions and data to the handler. This whole question is oriented around how I can pass the handler function and chip-context data in a way that seems coherent. I was taking the approach of partially applying the handler to already have the chip context, deserializer and output channel but maybe a map is better.

2021-04-01T17:10:15.389800Z

Is there some trick to get in macro in which stage it been used?

(defmacro foo []
  (cond
    cljs? 'cljs.core.async
    clj? 'clojure.core.async))
something like this ^

2021-04-01T17:11:00.390400Z

maybe stage is the wrong term here 🤷 but I don’t know the right one

2021-04-01T17:16:15.391300Z

so far I found the difference in &amp;env between clj and cljs but not sure if this is something that I can rely on

NoahTheDuke 2021-04-01T17:31:58.392Z

are you looking for reader conditionals? https://clojure.org/reference/reader#_reader_conditionals

#?(:clj     Double/NaN
   :cljs    js/NaN
   :default nil)

2021-04-01T17:35:35.394Z

not really, I have macro.clj where I define some macro and app.cljc where I want to use it. But the code generated by the macro should be different depending on target of compilation (clj or cljs)

2021-04-01T17:36:34.394600Z

so far I added this

~(if (contains? &amp;env :js-globals)
   'cljs.core.async/go-loop
   'clojure.core.async/go-loop)
but it looks too ugly

2021-04-01T17:37:27.395500Z

and I think the fact that there is :js-globals in &env is not really reliable

dpsutton 2021-04-01T17:40:10.395700Z

<https://github.com/cgrand/macrovich> can help with lots of this stuff

dpsutton 2021-04-01T17:40:22.396Z

and you can read the source to just implement in that manner or use the helpers

2021-04-01T17:41:37.396400Z

https://github.com/cgrand/macrovich/blob/master/src/net/cgrand/macrovich.cljc#L23-L28 looks like it is doing exactly the same thing )

2021-04-01T17:41:46.396700Z

thanks!

2021-04-01T21:56:22.398500Z

Could someone point me to where I can find the difference between &lt;! and &lt;!! in core/async? I'd google it myself but its kind of hard to get google to not ignore that syntax.

2021-04-01T21:56:40.399100Z

And the api seems to be identical except the workd parking and blocking.

seancorfield 2021-04-01T21:56:42.399200Z

One is blocking, the other is not.

2021-04-01T21:57:32.400300Z

@seancorfield But the 'non-blocking' one says: "Will park if nothing is available."

seancorfield 2021-04-01T21:57:39.400500Z

Parking is not blocking.

seancorfield 2021-04-01T21:58:05.401200Z

Blocking will block a thread. Parking just switches to another go block to continue executing something else.

2021-04-01T21:58:19.401500Z

Okay, what is parking? (I was under the impression that parking was like blocking but for green-threads.)

2021-04-01T21:59:15.402200Z

> Blocking will block a thread. Parking just switches to another `go` block to continue executing something else. Hmm...so what happens then when it comes back to the original task that 'parked', and still didn't have something available?

2021-04-01T21:59:25.402700Z

doesn't*

seancorfield 2021-04-01T21:59:34.402900Z

It won’t unpark until there is something to take.

seancorfield 2021-04-01T21:59:49.403300Z

go blocks are “collaborative” in that sense.

2021-04-01T22:00:42.404900Z

Ah, wait, by parking, vs blocking, are you meaning: "parking = freezing a go-thread" and blocking = freezing an os thread"?

seancorfield 2021-04-01T22:01:04.405700Z

No. Parking doesn’t freeze anything.

2021-04-01T22:01:15.406100Z

And if so, then it seems like clojurescript wouldn't have &lt;!! , at least not without webworkers, since there would be only one os-thread.

seancorfield 2021-04-01T22:01:48.406800Z

Well, if all your go blocks are parked, then it “freezes” (until another thread changes the state of the channels in a way that something can unpark).

seancorfield 2021-04-01T22:02:11.407400Z

The TL;DR is that core.async is really hard to use correctly and can be a pit of vipers for beginners 😐

Franco Gasperino 2021-04-01T22:03:33.407500Z

There is an implied event loop, which is effectively a big queue of functions which are cooperatively yielding control to the thread driving the event loop

Franco Gasperino 2021-04-01T22:04:01.408500Z

the go macro is similar to the javascript await, python await, etc

2021-04-01T22:04:07.408900Z

> Well, if all your `go` blocks are parked, then it “freezes” (until another thread changes the state of the channels in a way that something can unpark). I mean, that sounds an awful lot like blocking to me. I suspect I'm missing something here.

ghadi 2021-04-01T22:04:17.409200Z

blocking == a thread is tied up

Franco Gasperino 2021-04-01T22:04:25.409500Z

execute to <here>, then yield control from this current execution back to the event loop so something else can run

ghadi 2021-04-01T22:05:03.410300Z

parking == no thread tied up (there is a callback attached to a channel; when the callback fires, the go block is resumed)

ghadi 2021-04-01T22:05:21.410700Z

by thread I mean a real java.lang.Thread

Franco Gasperino 2021-04-01T22:05:30.410900Z

the "park" is similar to "yield execution control back to the event loop. wake me up when something on the other side of the park operation has placed something in that channel i'm waiting on, and wake me up after that"

2021-04-01T22:05:32.411300Z

@ghadi Okay, so then ya.

2021-04-01T22:05:45.411700Z

For clojurescript you wouldn't ever use &lt;!! without webworkers.

seancorfield 2021-04-01T22:05:47.411800Z

I’m pretty certain ClojureScript does not have &lt;!! or &gt;!! @leif

2021-04-01T22:05:58.412300Z

(And parking is blocking for green-threads.)

2021-04-01T22:06:04.412700Z

(Which are cooperative threads.)

2021-04-01T22:06:14.413100Z

Or at least I'm meaning that.

seancorfield 2021-04-01T22:07:42.414800Z

I think it’s misleading to think of core.async even as “green threads”. It doesn’t have lightweight threads of any description (in ClojureScript): it has collaborating sequential processes (CSP of old).

seancorfield 2021-04-01T22:08:00.415300Z

(in the Clojure version, go blocks run in their own small thread pool as I recall)

2021-04-01T22:08:02.415400Z

AH, okay, this makes sense.

2021-04-01T22:08:21.415600Z

@saeidscorp That also makes a lot of sense.

2021-04-01T22:08:43.416Z

Mmm...fair.

2021-04-01T22:09:19.416400Z

Okay, I think I have my answer now though, thanks. ^.^

Franco Gasperino 2021-04-01T22:09:28.416700Z

the main benefit is that in either concurrent async or parallelism threading mode, you are using a queue idiom that works the same on both

2021-04-01T22:09:35.417Z

TLDR, use &lt;! in clojurescript, as its the only option. 🙂

2021-04-01T22:09:53.417400Z

Because it only has one os thread (again, sans webworkers)

2021-04-01T22:10:08.417700Z

you can use take!, but you have to pass it a callback

Franco Gasperino 2021-04-01T22:10:20.417800Z

with the channel (chan) being the queue

2021-04-01T22:11:07.418700Z

Ah, well given that my goal is to await on a function that takes a callback, probably not quite what I want.

2021-04-01T22:11:35.419300Z

(I'd use &lt;p!, but its not a promise, its just a CPSed function.

alpox 2021-04-01T22:39:34.419400Z

Is it a javascript ES7 await that you need? In that case you could go with plain-js and use the promise constructor to turn the function taking a callback into a javascript promise that you can await.

2021-04-01T22:58:55.419800Z

@alpox Using something like Promise.resolve?

alpox 2021-04-01T23:18:53.419900Z

That would create a promise that instantly resolves with a value. I was talking about https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise the constructor

2021-04-01T23:20:45.420300Z

Ah, okay.

alpox 2021-04-01T23:27:28.420600Z

The pattern for wrapping a callback function would look about something like this:

(defn do-something-async [param-1]
  (js/Promise.
    (fn [resolve reject]
      (my-fn-with-callback
        param-1
        (fn [err result]
          (if err
            (reject err)
            (resolve result)))))))

👁️ 1