Fork me on GitHub
#clojure
<
2020-10-09
>
nivekuil00:10:04

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

seancorfield00:10:42

@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.

seancorfield00:10:57

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?

nivekuil01:10:55

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

nivekuil01:10:18

it's a frequently useful distinction :)

seancorfield02:10:39

Thanks. Added to my reading list.

FL00:10:47

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)

hiredman01:10:22

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)

hiredman01:10:41

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

FL18:10:48

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

seancorfield01:10:37

@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.

FL18:10:05

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”.

arohner13:10:33

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?

arohner13:10:46

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

arohner13:10:24

oh, extend-via-metadata is an option now

vncz17:10:11

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!

hiredman17:10:35

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

hiredman17:10:15

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

hiredman17:10:32

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.

hiredman17:10:50

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

hiredman17:10:45

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

hiredman17:10:11

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

hiredman17:10:02

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)

andy.fingerhut17:10:04

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

hiredman17:10:27

I am getting to that

hiredman17:10:53

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

hiredman17:10:17

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

hiredman17:10:01

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

hiredman17:10:30

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

hiredman17:10:56

(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

hiredman17:10:01

(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

hiredman17:10:22

(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

hiredman17:10:39

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

hiredman17:10:14

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

hiredman17:10:26

with

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

andy.fingerhut18:10:38

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.

andy.fingerhut18:10:09

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.

andy.fingerhut18:10:45

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

hiredman18:10:06

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

hiredman18:10:21

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

hiredman18:10:11

so many languages exhibit the same kind of thing

hiredman18:10:29

~ % lua
Lua 5.4.0  Copyright (C) 1994-2020 , PUC-Rio
> function add(a, b)
>>    return a + b
>> end
>
> function sub(a, b)
>>    return a - b
>> end
>
> function partial(f, arg1)
>>    return function (arg2) return f(arg1, arg2) end
>> end
>
>
> f = add
>
> g = partial(f, 1)
>
> f = sub
>
> g(1)
2
>

hiredman18:10:35

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

andy.fingerhut19:10:52

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

andy.fingerhut19:10:57

Not ideal, I know.

andy.fingerhut19:10:25

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

Lennart Buit18:10:10

> 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 🙂

seancorfield23:10:05

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.

Vachi00:10:13

I haven't used it, but here is a talk about it https://www.youtube.com/watch?v=uwdtTQ2ky5Q , maybe you find it interesting

seancorfield00:10:59

Thank you -- added to my list.

dangercoder19:10:10

I watched the talk and it looks interesting

Zor12:10:28

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

dominicm13:10:29

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.

alexmiller13:10:29

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)

seancorfield15:10:00

@U716Q56R2 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...?" @U09LZR36F 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
alexmiller15:10:17

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

1
seancorfield15:10:07

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

seancorfield23:10:25

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