style question: (when-not (= ...))
or (when (not= ...))
?
I started on BASIC, so the Lisp REPL was like coming home 🏠 after years of COBOL and C in tall buildings 🏢
@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
.
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?
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)
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)
clojure.reflect is a thing, but I've always just used reflection directly
Hey there, I’d take a look at both, thanks!
@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.
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”.
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
it's a frequently useful distinction :)
Thanks. Added to my reading list.
got an interesting question from a mentee, is there a particular reason why this yields a bigint?
(type (* (/ 1 3) 3))
;;=> clojure.lang.BigInt
(nominator (/ 1 3))
(as well as denominator)
are BigInteger
internally.
*
of a BigInteger
and a Long
seems to be coerced to BigInt
these are just quick observations tho, I don't know about the specific backgrounds for these circumstances. 🙂
@plexus The relevant line is probably here: https://github.com/clojure/clojure/blob/cbb3fdf787a00d3c1443794b97ed7fe4bef8e888/src/jvm/clojure/lang/Numbers.java#L893
thanks! the nominator/denominator thing makes sense
also interesting, multiplying two big numbers will automatically promote to bigint, but multiplying multiple numbers will integer overflow
user> (* 10000 10000000000000000000)
100000000000000000000000N
user> (* <tel:1000010000000|10000 10000000> 1000000 100000)
Execution error (ArithmeticException) at user/eval41715 (REPL:202).
integer overflow
(* 10000 10000000000000000000 1000000000000000000 1000000000000)
100000000000000000000000000000000000000000000000000000N
Maybe this has to do with the reader automatically coercing big numbers into bigintshmmm yeah that makes sense
whoa, that is subtle and unexpected
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?
It looks like extend
won’t work, because that wants a type rather than an instance
oh, extend-via-metadata is an option now
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?
He believes it is new and spent some time looking for independent invention in papers but didn’t find it
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
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
can’t believe it’s been 6 years 😐
Weird, because it seems like such an obvious, "basic" thing, at least in hindsight 🙂
the key word here is “in hindsight” 😄
yeah. It's really getting me that these aren't bigger news... this seems like a fundamental advancement in computer science.
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?
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?
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.
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).
It's the former. Just want to give credit where credit is due in whatever way is appropriate.
As long as "independent implementation" means "direct ripoff in another language"
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.
Well we did also release impls in Java, Python, etc
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.
Like for instance, if I didn't know about the concept of an "if" statement, I would hope someone would tell me.
whoaaaa what the hell!! I didn't know these were available
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!
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
🍿 😮
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
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.
and if a var with a given name already exists, def just updates its value
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
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
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)
Is the difference here due to using a Var name in a macro invocation, versus using it within a function definition?
I am getting to that
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
it isn't a macro thing, it is an argument evaluation thing
if you had a function create-route
that takes a handler
you invoke create-route once and give the result to your webserver to handle requests
(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
(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
(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
this is basically the same thing as the thing people trip over when using partial
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)
with
user=> (def f +)
#'user/f
user=> (def g #(f 1 %))
#'user/g
user=> (def f -)
#'user/f
user=>
as the follow upIs 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.
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.
It is a more general issue than partial
, of course.
There were some news items about transducers ending up in C++ (libraries?) as well at the time
> 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 🙂
finding a place to hang this is tricky, because it is a consequence of state + the call by value lambda calculus
function arguments are evaluated once when a function is invoked, function bodies are evaluated every time a function is invoked
so many languages exhibit the same kind of thing
~ % lua
Lua 5.4.0 Copyright (C) 1994-2020 <http://Lua.org|Lua.org>, 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
>
sicp makes the distinction between the substitution model and the environment model of evaluation when it introduces assignment
> 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
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)
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
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
Does that help?
Hmm hold on, I'll re-read
Ok ok got it
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
Yes!
Now I just need to resolve the Spec problem and I should be all set! 🙂
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 transactingFor example, because you decide that your handle-post also needs to return the newly created person:
(defn handle-post [conn data]
(-> (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])))
(There are some kinks to iron out here, I hope you get the idea 🙂 )
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 🙂
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
Not ideal, I know.
But it makes it more likely that someone looking there will come across the issue.
Yes, totally makes sense
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.
I watched the talk and it looks interesting
It looks like it was developped for https://github.com/cognitect-labs/vase
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.
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)
@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...
that was just me finding and fixing things I have access to, so don't read anything into that
Yeah, I get lots of questions about random Contrib libs because folks see my commits (that were just updates to readme or contributing files!). 🙂
Looks like it was spun off from https://github.com/cognitect-labs/vase which is tied into Pedestal...?