clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
nivekuil 2020-10-09T00:06:04.229200Z

style question: (when-not (= ...)) or (when (not= ...))?

kennytilton 2020-10-09T00:32:49.229400Z

I started on BASIC, so the Lisp REPL was like coming home 🏠 after years of COBOL and C in tall buildings 🏢

seancorfield 2020-10-09T00:51:42.230900Z

@kevin842 For me it depends on what semantics I'm trying to emphasize for the when block: it is a block that executes when a condition is false when-not; or is it a block that executes when a condition is true when.

seancorfield 2020-10-09T00:52:57.232200Z

So in the two specific examples you gave, the first says "avoiding executing this block when these things are equal" whereas the second says "execute this block when these things are not equal" -- does that semantic different make sense?

FL 2020-10-09T00:59:47.237900Z

Hi everyone, Is there a way to convert Java objects to Clojure data easily? We use a lot Java objects - pretty much every single ns - and parsing the data out of the Java objects adds a lot of unnecessary code and complexity. I was trying to use <ps://github.com/clojure/java.data|java.data>, but hit a wall pretty quickly, when I tried to define my hook to convert a field to Clojure data (by defining a defmethod on from-java, the library didn’t call my method, I probably got something wrong). Thanks in advanced. (Still quite new to Clojure and Java)

2020-10-09T01:27:22.242400Z

Usually I don't bother with "converting" clojure data is java objects and java objects can be passed around and used directly. If I do converting I often times lean heavily on the java reflection api and use it to generate all or most of the conversion code upfront (maybe a macro, but often just print out the clojure code and paste it in a file)

2020-10-09T01:28:41.243600Z

clojure.reflect is a thing, but I've always just used reflection directly

FL 2020-10-09T18:30:48.287600Z

Hey there, I’d take a look at both, thanks!

seancorfield 2020-10-09T01:40:37.244800Z

@franklai_slack happy to help with org.clojure/java.data since I'm the maintainer -- but as @hiredman says, it depends what you're trying to do: just using the Java objects through interop is often the best approach.

FL 2020-10-09T18:28:05.286300Z

Hello Sean, thanks for replying. I guess in some sense parsing the java object isn’t much different from parsing a clojure map - both can be arbitrarily deep and retrieve by “name”.

nivekuil 2020-10-09T01:58:55.246400Z

yeah the intuition makes sense. I think it's a difference in pragmatics rather than semantics, by the way, as in https://philpapers.org/browse/semantics-pragmatics-distinction

nivekuil 2020-10-09T01:59:18.246700Z

it's a frequently useful distinction :)

seancorfield 2020-10-09T02:51:39.247100Z

Thanks. Added to my reading list.

plexus 2020-10-09T09:56:20.256600Z

got an interesting question from a mentee, is there a particular reason why this yields a bigint?

(type (* (/ 1 3) 3))
;;=&gt; clojure.lang.BigInt

1
Flo 2020-10-09T10:07:32.257Z

(nominator (/ 1 3)) (as well as denominator) are BigInteger internally.

Flo 2020-10-09T10:08:00.257200Z

* of a BigInteger and a Long seems to be coerced to BigInt

Flo 2020-10-09T10:08:32.257400Z

these are just quick observations tho, I don't know about the specific backgrounds for these circumstances. 🙂

plexus 2020-10-09T10:10:28.258200Z

thanks! the nominator/denominator thing makes sense

plexus 2020-10-09T10:14:54.258800Z

also interesting, multiplying two big numbers will automatically promote to bigint, but multiplying multiple numbers will integer overflow

user&gt; (* 10000 10000000000000000000)
100000000000000000000000N

user&gt; (* <tel:1000010000000|10000 10000000> 1000000 100000)
Execution error (ArithmeticException) at user/eval41715 (REPL:202).
integer overflow

borkdude 2020-10-09T10:18:50.259Z

(* 10000 10000000000000000000 1000000000000000000 1000000000000)
100000000000000000000000000000000000000000000000000000N
Maybe this has to do with the reader automatically coercing big numbers into bigints

plexus 2020-10-09T10:19:09.259200Z

hmmm yeah that makes sense

telekid 2020-10-09T12:36:17.260600Z

whoa, that is subtle and unexpected

arohner 2020-10-09T13:33:33.261500Z

I have a reify. I would like to conditionally make the instance implement a second protocol. Is there a way to do that without either defmacro or defining two different reifies?

arohner 2020-10-09T13:33:46.261800Z

It looks like extend won’t work, because that wants a type rather than an instance

arohner 2020-10-09T13:35:24.262100Z

oh, extend-via-metadata is an option now

unbalanced 2020-10-09T15:10:34.267900Z

Does anyone happen to know if there is any prior art or papers that Rich based transducers on, or was this an "apple falling on the head" kind of thing?

alexmiller 2020-10-09T15:12:31.269300Z

He believes it is new and spent some time looking for independent invention in papers but didn’t find it

unbalanced 2020-10-09T15:28:22.270700Z

I believe it's new, too. It's kinda bannanas. Has he written any papers on them yet? And also is it accurate to say that they were first introduced to the world with Clojure 1.7 on June 30, 2015? Giving a talk about them soon and just trying to get my facts straight

schmee 2020-10-09T15:33:40.270900Z

not sure when they were first announced, but “the” talk on transducers is from Strange Loop Sep 2014: https://www.youtube.com/watch?v=6mTbuzafcII

schmee 2020-10-09T15:38:52.271200Z

can’t believe it’s been 6 years 😐

zilti 2020-10-09T15:39:06.271900Z

Weird, because it seems like such an obvious, "basic" thing, at least in hindsight 🙂

schmee 2020-10-09T15:40:44.272100Z

the key word here is “in hindsight” 😄

unbalanced 2020-10-09T16:02:08.272300Z

yeah. It's really getting me that these aren't bigger news... this seems like a fundamental advancement in computer science.

unbalanced 2020-10-09T16:04:23.272500Z

Oh, I guess it bears asking, I'm absolutely crediting Rich/Clojure with these but is there any licensing or anything that needs to be done or copyright acknowledgement that goes with them?

2020-10-09T16:20:16.272700Z

Are you asking about that for an independent implementation of transducers you are working on, or for copying and reusing Rich's code in another project?

2020-10-09T16:20:38.272900Z

If the latter, then Clojure's license allows that if the project copied into is also released under EPL 1.0, or some compatible license.

2020-10-09T16:21:19.273100Z

If you are working on an independent implementation of them, to my knowledge under US law that would only be an issue if they were patented, and I'm pretty sure they weren't (but not in a position to know for certain).

unbalanced 2020-10-09T16:36:07.274300Z

It's the former. Just want to give credit where credit is due in whatever way is appropriate.

unbalanced 2020-10-09T16:36:49.274500Z

As long as "independent implementation" means "direct ripoff in another language"

zilti 2020-10-09T16:42:04.274700Z

It isn't bigger news because it's not Go or JavaScript. Because that's the only two stations the dev hype train services these days.

😂 1
😭 1
alexmiller 2020-10-09T16:58:37.275700Z

Well we did also release impls in Java, Python, etc

unbalanced 2020-10-09T16:59:42.276Z

I get that and I realize it's not a buzzword or whatever but it is genuinely a new discovery in fundamental lambda calculus style work and I would think that the folks would be interested in knowing about it.

alexmiller 2020-10-09T16:59:51.276300Z

https://github.com/cognitect-labs/transducers-js

❤️ 1
unbalanced 2020-10-09T16:59:58.276600Z

Like for instance, if I didn't know about the concept of an "if" statement, I would hope someone would tell me.

unbalanced 2020-10-09T17:01:29.276800Z

whoaaaa what the hell!! I didn't know these were available

vncz 2020-10-09T17:15:11.280500Z

Hello people — I have been playing a bit with Clojure and Datomic, and I am trying to build a server that's just doing a query and store some data. I do have some questions and I'd also love to know if I'm going towards a good direction or not: 1. Is it ok to attach a Datomic Connection and Db Object directly on the request object? I have used the same methodology that's usually applied in Express https://github.com/XVincentX/clojure-playground/blob/10720f8/src/app/interceptors.clj#L18 — I was wondering whether it's a good idea and also — if I need both (I need a conn to transact and a db to query) 2. I am using the late symbol evaluation trick to be able to modify the code on the fly without having to restart the server per each change: https://github.com/XVincentX/clojure-playground/blob/10720f8/src/app/core.clj#L43 — Is that ok to leave it as it is in production or is it something I should really remember to remove when I am done? Is there a way to have the cake and eat it too? 3. I have a Spec for my data https://github.com/XVincentX/clojure-playground/blob/10720f8/src/app/data.clj#L31-L37 — but matching the keywords with a JSON Payload appears to be harder than I thought; right now I am manually reconstructing the object (https://github.com/XVincentX/clojure-playground/blob/10720f8/src/app/core.clj#L26-L30) but I was wondering whether there's a faster way. Also — if anybody sees anything weird while reviewing the code — be my guest! Thanks!

2020-10-09T17:20:35.281600Z

for #2 that isn't "the late symbol evaluation trick" that is var quote, and because you are calling handle-post inside a function (the #() form) it is not needed

unbalanced 2020-10-13T21:24:09.422Z

🍿 😮

2020-10-09T17:24:15.282300Z

every def creates a thing called a var, which is a little mutable cell, interned in a namespace, and given the value of the definition

2020-10-09T17:25:32.282500Z

when the compiler encounters a name like conj it (as long as the name isn't locally bound) generates code to look up the var and dereference it to get the value out of it.

2020-10-09T17:26:50.282700Z

and if a var with a given name already exists, def just updates its value

2020-10-09T17:28:45.282900Z

this is why redefinitions are possible. the top level names refer to mutable things, and when you redefine something the next time the mutable thing is consulted you get the new value

2020-10-09T17:31:11.283100Z

however if you do something like define you routes once, the var holding you handler will be dereference once when the routes are defined, and you won't see updates

2020-10-09T17:32:02.283300Z

which is why people use var quote there (vars besides being mutable cells are also functions that when invoked just invoke their values which is why this works)

2020-10-09T17:32:04.283500Z

Is the difference here due to using a Var name in a macro invocation, versus using it within a function definition?

2020-10-09T17:32:27.283700Z

I am getting to that

2020-10-09T17:35:53.283900Z

however, in the code in question, instead of using #'handle-post or handle-post in you route definition, you have a function, which will be invoked to handle every request, and every time it is invoked, a call to handle-post in its body will deref the var and get the new value

2020-10-09T17:36:17.284100Z

it isn't a macro thing, it is an argument evaluation thing

2020-10-09T17:37:01.284300Z

if you had a function create-route that takes a handler

2020-10-09T17:37:30.284500Z

you invoke create-route once and give the result to your webserver to handle requests

2020-10-09T17:38:56.284700Z

(create-route handler) the argument handler is going to be evaluated once, when create-route is called, which is once, which means you will never see changes to the value of the name handler

2020-10-09T17:40:01.284900Z

(create-route #'handler) passes the var to create-route instead of the value of the var, and every time the var is invoked as a function it uses the current value of the var

2020-10-09T17:41:22.285100Z

(create-route #(handler %)) passes an anonymous function to create-route, and every time that anonymous function is invoked (to handle a request presumably) the var #'handler is going to be deref'ed and the current value invoked

2020-10-09T17:42:39.285300Z

this is basically the same thing as the thing people trip over when using partial

2020-10-09T17:44:14.285500Z

user=&gt; (def f +)
#'user/f
user=&gt; (def g (partial f 1))
#'user/g
user=&gt; (def f -)
#'user/f
user=&gt;
given that, what is (g 1)

2020-10-09T17:47:26.285700Z

with

user=&gt; (def f +)
#'user/f
user=&gt; (def g  #(f 1 %))
#'user/g
user=&gt; (def f -)
#'user/f
user=&gt;
as the follow up

2020-10-09T18:27:38.286100Z

Is this in a published article somewhere, perhaps? Looking at the last example currently on https://clojuredocs.org/clojure.core/partial it seems that it addresses this issue, at least briefly.

2020-10-09T18:31:09.287900Z

I've just double-checked the code snippets in that http://Clojuredocs.org example, and it matches what I see, and appears to be describing the same issue you have above, so at least that is one reasonable place to point people at for some explanation of this.

2020-10-09T18:31:45.288100Z

It is a more general issue than partial, of course.

borkdude 2020-10-09T18:33:16.289400Z

There were some news items about transducers ending up in C++ (libraries?) as well at the time

2020-10-09T18:37:10.291100Z

> I was wondering whether it’s a good idea and also — if I need both You’d want to resolve one request with one database value, even if you do multiple queries to compute your response. So IMO, its good practice to have a database value in your context. Putting in only a connection, which we sadly did, means that there is no consistency guarantee if you need to do multiple queries W.r.t. updating, you probably want to make sure that one rest/graphql/… call does exactly one mutation (for atomicity), after which you can use the transactions db-after to resolve your response. So yeah, good idea, and you do need both 🙂

2020-10-09T18:38:06.291300Z

finding a place to hang this is tricky, because it is a consequence of state + the call by value lambda calculus

2020-10-09T18:39:21.291500Z

function arguments are evaluated once when a function is invoked, function bodies are evaluated every time a function is invoked

2020-10-09T18:45:11.291800Z

so many languages exhibit the same kind of thing

2020-10-09T18:45:29.292Z

~ % lua
Lua 5.4.0  Copyright (C) 1994-2020 <http://Lua.org|Lua.org>, PUC-Rio
&gt; function add(a, b)
&gt;&gt;    return a + b
&gt;&gt; end
&gt;
&gt; function sub(a, b)
&gt;&gt;    return a - b
&gt;&gt; end
&gt;
&gt; function partial(f, arg1)
&gt;&gt;    return function (arg2) return f(arg1, arg2) end
&gt;&gt; end
&gt;
&gt;
&gt; f = add
&gt;
&gt; g = partial(f, 1)
&gt;
&gt; f = sub
&gt;
&gt; g(1)
2
&gt;

2020-10-09T18:48:35.292200Z

sicp makes the distinction between the substitution model and the environment model of evaluation when it introduces assignment

vncz 2020-10-09T19:12:33.293Z

> W.r.t. updating, you probably want to make sure that one rest/graphql/… call does exactly one mutation (for atomicity), after which you can use the transactions db-after to resolve your response. @lennart.buit Thanks! Any chance you can elaborate more on this? Not too sure I am following

2020-10-09T19:14:49.293100Z

If you have a REST endpoint that updates some entities, you want to make sure to use (preferably) d/transact exactly once. If you were to use it multiple times, the first could succeed, and the second could fail, leaving your database in a inconsistent state. (Thats the first part of the sentence)

2020-10-09T19:16:20.293400Z

Datomic’s d/transact gives you a map which contains a db value (`:db-after`), that is guaranteed to include the changes you made in your transaction

2020-10-09T19:18:03.293700Z

Because this is just a database value, you can use the existing code paths you have for querying (say, GET requests in a REST endpoint), and use that to create your response for the update request

2020-10-09T19:18:10.293900Z

Does that help?

vncz 2020-10-09T19:22:29.294100Z

Hmm hold on, I'll re-read

vncz 2020-10-09T19:23:08.294300Z

Ok ok got it

vncz 2020-10-09T19:23:33.294500Z

1. Modify all your data all in once 2. Use the :db-after in case you need to require after a successful transaction — is that what you were trying to communicate? @lennart.buit

2020-10-09T19:24:07.294700Z

Yes!

vncz 2020-10-09T19:24:44.295300Z

Now I just need to resolve the Spec problem and I should be all set! 🙂

2020-10-09T19:26:37.295500Z

Concretely, if you spin out a function here: https://github.com/XVincentX/clojure-playground/blob/10720f8462611044945bdab20ef19eeb8b31dc77/src/app/core.clj#L17-L29 Say, get-person, that looks like this:

(defn get-person [db name]
  (ffirst (d/q '[:find (pull ?e [:person/name :person/surname])
                 :in $ ?name
                 :where
                 [?e :person/name ?name]]
                db name)
You can use it both with the db value in your context, or a :db-after value you get from transacting

2020-10-09T19:29:10.295800Z

For example, because you decide that your handle-post also needs to return the newly created person:

(defn handle-post [conn data]
  (-&gt; (d/transact conn {:tx-data
                       [{:person/name (get-in data [:person :name])
                         :person/surname (get-in data [:person :surname])}]})
      (:db-after)
      (get-person (get-in data [:person :name])))

2020-10-09T19:29:30.296Z

(There are some kinks to iron out here, I hope you get the idea 🙂 )

2020-10-09T19:31:38.296300Z

Like — it doesn’t fit perfectly in this example with this person name, I’m just trying to show you how you could create small functions that accept db values, and how you can reuse them across routes 🙂

2020-10-09T19:48:52.296500Z

Understood. Specifically for http://ClojureDocs.org, which is Var-based, not "topic" based, one approach is to pick one representative Var where the issue often arises (e.g. partial), then briefly mention that example from other Vars where it also often arises, e.g. comp

2020-10-09T19:48:57.296700Z

Not ideal, I know.

2020-10-09T19:49:25.296900Z

But it makes it more likely that someone looking there will come across the issue.

vncz 2020-10-09T20:04:36.297100Z

Yes, totally makes sense

seancorfield 2020-10-09T23:20:05.299Z

Just randomly stumbled across https://github.com/cognitect-labs/fern -- seems useful. Anyone using it? Feedback on it? I notice @alexmiller added a PR recently to address the unqualified lib names thing from the recent Clojure CLI updates, so I'm assuming it's still actively being used, at least by Cognitect.

dangercoder 2020-10-10T19:41:10.313300Z

I watched the talk and it looks interesting

2020-10-11T12:14:28.329300Z

It looks like it was developped for https://github.com/cognitect-labs/vase

dominicm 2020-10-13T13:42:29.397500Z

I'm a significant contributor to aero, so I made a contrast a little while ago. I really like fern, it addresses some pain points in an interesting way. Particularly I like the extensions mechanism that's suggested, as well as the partial keys that handle a good few problems in interesting ways. It lacks a significant set of useful things like environment readers. I don't think it handles "macro" style conditionals either, but there may be a subtlety above that, using the lazy keys system. I think it might have some legs though, I think it needs a little more progression to be useful out of the box.

alexmiller 2020-10-13T13:59:29.397900Z

I believe fern and vase were projects spearheaded by Michael Nygard who's not at Cognitect anymore but still tinkers with them. I'm unsure whether they ever got used on Cognitect consulting projects (although those are all winding down)

seancorfield 2020-10-13T15:07:00.412200Z

@zor Yup, that's what I said in the main channel after I asked about fern: "Looks like it was spun off from https://github.com/cognitect-labs/vase which is tied into Pedestal...?" @dominicm Thanks for the input. I probably ought to have another look at aero at some point. @alexmiller Thanks. It's hard to tell how widely-used some of the Cognitect OSS projects are and how many actually made it into production. I was mostly curious since I saw your (relatively) recent PR...

👍 1
alexmiller 2020-10-13T15:08:17.414500Z

that was just me finding and fixing things I have access to, so don't read anything into that

1
seancorfield 2020-10-13T15:09:07.416400Z

Yeah, I get lots of questions about random Contrib libs because folks see my commits (that were just updates to readme or contributing files!). 🙂

seancorfield 2020-10-09T23:21:25.299700Z

Looks like it was spun off from https://github.com/cognitect-labs/vase which is tied into Pedestal...?