clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
2021-03-04T02:34:41.048500Z

Clojure 1.10.1
user=> (identical? Double/NaN Double/NaN)
false
user=> (identical? ##NaN ##NaN)
true

raspasov 2021-03-04T06:53:09.048900Z

@andy.fingerhut so you’re saying that something like:

(= 
 (+ (+ 1.111 1.111) 1.111) 
 (+ 1.111 (+ 1.111 1.111)))
=> true

raspasov 2021-03-04T06:53:43.049200Z

… might return false, depending on the numbers involved?

simongray 2021-03-04T14:20:03.053800Z

I want to reuse some variadic keywords args that are destructured in one function - i.e. a map m - when calling another function f that also takes variadic keywords args. Is the idiomatic way to do this then

(apply f (mapcat identity m))
? Applying the map directly doesn’t work, so I have to flatten it somehow which I do using (mapcat identity m).

borkdude 2021-03-04T14:23:33.055100Z

yeah, this is an annoying problem that might be addressed in clojure 1.11 but over the years the community has moved towards an options map instead of keyword opts (at least, in my perception)

reefersleep 2021-03-10T08:43:37.406600Z

Count me as one of the community in this matter. Variadic keyword arg destructuring seem stunted, as demonstrated here.

Darin Douglass 2021-03-04T14:23:59.055300Z

^

simongray 2021-03-04T14:28:56.056100Z

gotcha

alexmiller 2021-03-04T14:38:28.057400Z

(will be addressed in 1.11 and there may be multiple reasons this pendulum will swing the other way)

👀 1
🤘 5
vlaaad 2021-03-04T14:42:17.057900Z

jokes on you, I use both at the same time already

borkdude 2021-03-04T15:05:29.059400Z

My Clojure goes to 11

roklenarcic 2021-03-04T16:01:01.061400Z

Are there a functions in clojure core that would behave like and and or but not a macro, a function and I don’t need the short circuit logic?

roklenarcic 2021-03-04T16:02:17.062Z

I find myself often in need of (map and seq1 seq2) and or version of such

borkdude 2021-03-04T16:07:07.062600Z

every? identity for example

enn 2021-03-04T16:07:18.063Z

or some identity for or

alexmiller 2021-03-04T16:07:30.063100Z

#(and %1 %2) for that case?

lilactown 2021-03-04T16:08:01.063600Z

I didn't realize that and and or aren't provided as fns along side their macro form

bronsa 2021-03-04T16:09:33.065Z

clojure doesn't have separate namespaces for fns and macros, a var is either a fn or a macro

bronsa 2021-03-04T16:09:47.065500Z

can't be both at the same time

roklenarcic 2021-03-04T16:10:01.065800Z

for instance something like:

(every? (fn [[x y]] (< x y)) [1 2 3] [3 4 5])

bronsa 2021-03-04T16:10:19.066300Z

(modulo definline stuff, but let's pretend that doesn't exist)

roklenarcic 2021-03-04T16:10:47.066900Z

so I tried doing (map < [1 2 3] [3 4 5]) but then there’s no elegant way to roll those booleans up

borkdude 2021-03-04T16:11:25.067300Z

reduce #(and %1 %2)

borkdude 2021-03-04T16:11:45.067800Z

or use (reduced ...) for short-circuiting

roklenarcic 2021-03-04T16:11:57.068300Z

yeh… that’s why I asked if there’s a function for that, I know I acan use anon function and call and in it

borkdude 2021-03-04T16:12:02.068500Z

but this is similar to (every? identity ...)

borkdude 2021-03-04T16:12:41.069200Z

that's only done for optimizations though

bronsa 2021-03-04T16:12:43.069400Z

yeah, cljs has a completely different compilation model than clj

bronsa 2021-03-04T16:13:00.069600Z

@borkdude not really, userspace code can do this freely afaict

borkdude 2021-03-04T16:13:26.070100Z

I mean, they are used for optimizations in cljs

borkdude 2021-03-04T16:13:48.070600Z

The occurrence of macros and functions for the same var

bronsa 2021-03-04T16:14:17.071500Z

the cljs impl uses this mechanism for optimisations, sure, but it's completely open

roklenarcic 2021-03-04T16:14:25.071800Z

thanks borkdude, I’ll guess I’ll use every?… but this same thing came up many many many times in various code, where and or or would be perfect as an argument to coll processing function and then I have to go #(and %1 %2)

borkdude 2021-03-04T16:14:34.071900Z

yes, I was speaking about clojurescript macro-functions specifically

borkdude 2021-03-04T16:16:27.072100Z

maybe the word "only" wasn't appropriate, sorry

borkdude 2021-03-04T16:17:06.072600Z

make a proposal in an ask.clojure issue :)

alexmiller 2021-03-04T16:17:32.072800Z

not going to add this

bronsa 2021-03-04T16:17:43.072900Z

tbh it should be only done for optimisations and limited to core.

bronsa 2021-03-04T16:18:16.073300Z

I'm not a fan of this working for user code at all

lilactown 2021-03-04T16:18:48.073600Z

to my mind macros are used for performance and the functions are provided to allow the semantics that roklenarcic is talking about (passing it into apply/map/etc.)

bronsa 2021-03-04T16:18:48.073800Z

but then, as I mentioned, clojure technically does have the same capability via the impl details of definline

bronsa 2021-03-04T16:19:04.074200Z

no, that's completely wrong

bronsa 2021-03-04T16:19:12.074400Z

macros are used for changing evaluation semantics

bronsa 2021-03-04T16:19:34.074600Z

it's incidental that in some cases controlling the evaluation semantics can lead to better performance hints to the compiler

lilactown 2021-03-04T16:19:53.074800Z

ok lol

borkdude 2021-03-04T16:19:54.075Z

In general yes, but e.g. the + macro is added for optimizations, while it's also a fn. this is what I was referring to

lilactown 2021-03-04T16:20:17.075200Z

I wasn't making a strong claim of "macros are ONLY used for performance"

bronsa 2021-03-04T16:20:21.075400Z

yes but that could be done (and imo, should be!) as an intrinsic to the compiler instead of as a macro

bronsa 2021-03-04T16:20:34.075600Z

clojure has similar optimisations baked into the compiler

bronsa 2021-03-04T16:20:39.075800Z

¯\(ツ)

borkdude 2021-03-04T16:21:10.076Z

cljs.user=> (macroexpand '(+ 1 2 3))
(js* "(~{} + ~{})" (cljs.core/+ 1 2) 3)
cljs.user=> (macroexpand '(apply + [1 2 3]))
(apply + [1 2 3])

bronsa 2021-03-04T16:21:31.076200Z

yeah I'm aware of how it's done in the cljs impl :)

bronsa 2021-03-04T16:21:50.076400Z

@lilactown no but it's wrong to say for example that " and as a macro is used for performance and then a fcuntion for semantics"

borkdude 2021-03-04T16:22:01.076600Z

ah so that is called an "intrinsic", now I get what those compiler people were talking about

1
bronsa 2021-03-04T16:22:20.076800Z

this can only be true for a very limited subset of "functions" that have function semantics

bronsa 2021-03-04T16:22:26.077Z

and doesn't have function semantics

lilactown 2021-03-04T16:22:26.077200Z

anyway, I've used this to effect in some libraries where I wanted to provided a macro - for some performance reasons - and also a function to allow function application and other more dynamic uses. I would be sad to lose that capability

borkdude 2021-03-04T16:22:52.077600Z

in Clojure we don't have this capability and I've never used it in CLJS

bronsa 2021-03-04T16:23:07.077800Z

eeeh we kinda do :) it's just not very known

borkdude 2021-03-04T16:23:13.078Z

(I went to some compiler-related conference last weekend)

borkdude 2021-03-04T16:23:25.078200Z

you mean (definline ...) ? ok, never used it

bronsa 2021-03-04T16:24:12.078400Z

user=> (defn foo {:inline (fn [x] (+ x 1))} [x] (- x 1))
#'user/foo
user=> (foo 2)
3
user=> (apply foo [2])
1

bronsa 2021-03-04T16:24:17.078600Z

close your eyes and forget you ever saw this

borkdude 2021-03-04T16:25:02.078800Z

ah that one, yes I knew it, but I usually roll a macro and just don't allow myself to use it as a fn when I want this ;)

bronsa 2021-03-04T16:25:25.079Z

@lilactown the capability is sound, other lisps have similar things -- I just don't think having this macro+fn hack is the way to do it, but whatever

lilactown 2021-03-04T16:25:49.079200Z

ok

lilactown 2021-03-04T16:27:45.079400Z

I don't really understand the what/why of some of the things you're saying. I am trying to participate in the discussion to explain my experience using macro+fn, and you tell me very bluntly that I'm "wrong"

bronsa 2021-03-04T16:28:18.079600Z

I was just referring to this statement to my mind _macros_ are used for performance

lilactown 2021-03-04T16:28:29.079800Z

ok

lilactown 2021-03-04T16:28:37.080Z

let me amend

lilactown 2021-03-04T16:28:56.080200Z

to my mind macros _are used sometimes for performance_

bronsa 2021-03-04T16:29:20.080400Z

ish :) but I don't want to nitpick

lilactown 2021-03-04T16:29:45.080600Z

I feel like I have spent a lot of energy very quickly here on an argument that we never needed to have

bronsa 2021-03-04T16:30:13.080800Z

I'm sorry you felt we were having an argument, not my intention

borkdude 2021-03-04T16:30:59.081Z

Macros are always a sensitive topic. ;)

borkdude 2021-03-04T16:31:56.081200Z

Like lisp-1, lisp-2, and why Clojure is not a true lisp-1, etc ;P

bronsa 2021-03-04T16:33:11.081400Z

I have a bit of a gripe with some unnecessary "extensions" to the evaluation model of cljs compared to clj, this is part of it

borkdude 2021-03-04T16:33:39.081600Z

So what other "extensions" are there?

bronsa 2021-03-04T16:37:54.081800Z

shoulda said changes rather than extensions but off the top of my head: type hints having different semantics (regardless of the absence of classes in js), clj/cljs namespace renaming, metadata evaluation being different, different arglists quoting, overuse of js* as an escape hatch in the impl

bronsa 2021-03-04T16:39:10.082Z

things that matter more from a lang impl/analysis tooling PoV than end-user experiene anyway

borkdude 2021-03-04T16:39:24.082200Z

I had an issue once with a macro that used try/catch with some code from cljs.spec (which is also macro-rich) but ran into the issue that the catch or finally clause was analyzed before the body of try

borkdude 2021-03-04T16:39:51.082400Z

and this wasn't considered an issue, so I had to come up with an ugly workaround

bronsa 2021-03-04T16:40:05.082600Z

ugh.

borkdude 2021-03-04T16:40:10.082800Z

the issue was that cljs.spec macros do side effects during macro-expansion

borkdude 2021-03-04T16:40:17.083Z

so the side effects happened at the "wrong" time

bronsa 2021-03-04T16:40:43.083200Z

lol, yeah, I wish we could have the invariant that macros aren't side-effectful

bronsa 2021-03-04T16:40:44.083400Z

but alas

bronsa 2021-03-04T16:41:12.083600Z

t.a.jvm has to take a non insignificant performance hit to handle this

borkdude 2021-03-04T16:41:22.083800Z

it's comparable to the ns macro, or def special form, it has the side effect of defining something in the runtime before the rest is analyzed

bronsa 2021-03-04T16:42:21.084300Z

yeah there's a bunch of macros in the wild that do that

bronsa 2021-03-04T16:42:38.084500Z

whatever's the name of that testing framework, also does it in clj

borkdude 2021-03-04T16:42:38.084700Z

I remember slipset suggesting an optimization for this related to eastwood, right?

bronsa 2021-03-04T16:42:50.084900Z

yeah it's the ns-safe-macro check

borkdude 2021-03-04T16:42:55.085100Z

clojure.test?

bronsa 2021-03-04T16:42:59.085300Z

nah the ugly one :)

bronsa 2021-03-04T16:43:02.085500Z

non core

borkdude 2021-03-04T16:43:03.085700Z

midje?

bronsa 2021-03-04T16:43:06.085900Z

there it is

bronsa 2021-03-04T16:43:10.086100Z

we don't speak its name

borkdude 2021-03-04T16:43:18.086300Z

you said ugly, that rang a bell ;P

bronsa 2021-03-04T16:43:22.086500Z

haha

borkdude 2021-03-04T16:44:20.086700Z

honestly I have no experience with this framework, so I don't want to say anything bad of it, I've only heard some people (e.g. circleci blog) complain about it

2021-03-04T16:48:32.088Z

@alexmiller I seem to recall CLJ-2590 came up many years ago and the sticking point was a Windows limit on the length of a fully qualified class name

Elso 2021-03-04T16:59:21.092400Z

I think this is a fairly trivial thing to achieve, but I'm kind of lost how to do this without any state atm I have a bunch of maps which I group with group-by and then I need to map over the map and add an id from a lazy seq of ids to each of the maps in the respective groupings however when I do this with (repeatedly (rand-int 1000)) and (take (count grouped-maps) ids) I have the issue that all records get ids from the same starting point I mean, I could of course modify the id sequence, but I'd like to know how to do this idiomatically So somewhat like this: (->> stuff (group-by :some-key) (map (fn [[k v]] [k (map (fn [[m id]] (assoc m :id id)) v ids)])))

alexmiller 2021-03-04T17:00:38.092600Z

and?

alexmiller 2021-03-04T17:01:08.092800Z

not sure what the question is

p-himik 2021-03-04T17:21:46.093500Z

It can be exactly almost like this if you replace [[m id]] with just [m id]. map can accept any number of collections to map over.

flowthing 2021-03-04T17:26:32.093700Z

Do you need to group before adding :id? It's much easier if you group afterwards:

(def ids (iterate inc 1))
(def things [{:a 1 :b 2} {:a 1 :b 3} {:a 2 :b 4}])
(group-by :a (map (fn [id thing] (assoc thing :id id)) ids things))

👍 1
➕ 1
✅ 1
wombawomba 2021-03-04T17:49:25.094400Z

What OIDC client library should I be using in a Clojure project?

2021-03-04T19:39:55.095200Z

also consider mapcat seq or apply concat in place of mapcat identity

2021-03-04T20:42:17.097200Z

Does anybody have link to a good example repo for JWT authentication using Buddy that they can share? https://github.com/funcool/buddy I'm trying to follow along with the example code here: https://github.com/funcool/buddy-auth/blob/master/examples/jws/src/authexample/web.clj Although it isn't quite complete enough to see the whole process (authenticate with username and password, generate token, pass token back to web client, authenticate protected routes using token)

borkdude 2021-03-04T22:14:54.099600Z

Can you have in general a defrecord/deftype or reify that implements two different interfaces / protocols with clashing method names?

borkdude 2021-03-04T22:16:25.100Z

or can you uniquely identify the interface / protocol by the method name?

alexmiller 2021-03-04T22:23:22.100200Z

no

borkdude 2021-03-04T22:24:52.100400Z

no to which question?

2021-03-04T22:26:36.100500Z

CLJ-2590 is the question and I think the answer was, If we 'fix' it by composing internal class names from symbols instead of numbers then the resulting increase in class name length will cause some code that currently works in Windows to not work any more.

2021-03-04T22:27:47.100700Z

I think it was discussed on the Google group.

ghadi 2021-03-04T22:28:58.101Z

the second one

ghadi 2021-03-04T22:29:30.101600Z

IIRC the JVM doesn't take into account in the interface in the method definition

borkdude 2021-03-04T22:30:17.102200Z

What I mean is: can you construct a reify with two method names from different interfaces?

ghadi 2021-03-04T22:30:43.102600Z

two identical names? no

borkdude 2021-03-04T22:30:48.102900Z

two identical yes

ghadi 2021-03-04T22:30:50.103100Z

they'll be the same impl for both interfaces

ghadi 2021-03-04T22:31:50.104200Z

(assuming the args & return type are all the same, too)

borkdude 2021-03-04T22:32:05.104500Z

what if the arities are different (not sure if Clojure supports types in the signature of those?)

ghadi 2021-03-04T22:33:14.105100Z

you could REPL it

borkdude 2021-03-04T22:35:03.105400Z

yeah, trying it

borkdude 2021-03-04T22:36:54.105900Z

So I've got this:

user=> (definterface Foo (foo [_]))
user.Foo
user=> (definterface Bar (foo [_ _]))
user.Bar
user=> (def x (reify Foo (foo [_ _] :foo) Bar (foo [_ _ _] :bar)))
#'user/x

ghadi 2021-03-04T22:37:04.106100Z

user=> (definterface One (foo [x]))
user.One
user=> (definterface Two (foo [x y]))
user.Two
user=> (def r (reify One (foo [_ x] :one) Two (foo [_ x y] :two)))
#'user/r
user=> (.foo r 42)
:one
user=> (.foo r 42 42)
:two

ghadi 2021-03-04T22:37:12.106500Z

lol, are we twins? 🙂

borkdude 2021-03-04T22:37:58.107100Z

user=> (.foo x 1)
:foo
user=> (.foo x 1 2)
:bar 
Ok, that answers my question, thanks!

p-himik 2021-03-04T22:48:00.107200Z

Why JWT in particular - can't regular session IDs be used?

2021-03-04T22:59:16.107600Z

I've got to authenticate across multiple domains, and as I understand it JWT is the way to go when that's the case.

p-himik 2021-03-04T23:00:46.107800Z

You mean, like SSO? So you login to example1 and you would be automatically logged into example2?

p-himik 2021-03-04T23:05:21.108Z

JWT might be needed when you have a stateless backend or a distributed backend where it's unfeasible to share the state between all the instances. In all (or perhaps almost all) other situations regular session IDs are not only sufficient but also better. They're as simple as it can get and yet can provide all the security you will need.

p-himik 2021-03-04T23:11:15.108200Z

Here's a nice article on JWT: http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/