This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-05-18
Channels
- # announcements (2)
- # asami (20)
- # aws (4)
- # babashka (35)
- # beginners (47)
- # calva (65)
- # cider (19)
- # clj-kondo (63)
- # clojure (177)
- # clojure-austin (2)
- # clojure-europe (27)
- # clojure-nl (1)
- # clojure-uk (4)
- # clojurescript (13)
- # community-development (5)
- # conjure (5)
- # css (2)
- # data-oriented-programming (9)
- # datalevin (13)
- # datascript (15)
- # datomic (4)
- # devcards (6)
- # duct (4)
- # emacs (8)
- # funcool (1)
- # gratitude (2)
- # helix (3)
- # hyperfiddle (3)
- # introduce-yourself (1)
- # jobs (4)
- # jobs-discuss (26)
- # lambdaisland (2)
- # lsp (20)
- # malli (2)
- # meander (2)
- # mid-cities-meetup (5)
- # missionary (15)
- # music (4)
- # off-topic (37)
- # reagent (3)
- # reitit (2)
- # releases (2)
- # ring (18)
- # shadow-cljs (70)
- # specter (4)
- # sql (20)
- # timbre (3)
- # tools-build (43)
- # tools-deps (11)
- # vim (29)
- # xtdb (61)
Is there shorter way of creating a hash-map from a collection and function, where the original elements become the keys and the result of apply the function to the elements becomes the values. I plan to do it with (zipmap coll (map f coll))
, which to be fair, is pretty concise.
Thanks! I guess I was wondering if there was a clojure.core
function that does what I wanted that I overlooked.
I guess that's way too specific to be included in the core.
It reminds me a bit medley.core/index-by
(or more general group-by
) but here it's reversed - mapping from item
to (f item)
rather than mapping from (f item)
to item
So this would be a complicated way to do it too 🙂
(->> [1 2 3]
(medley.core/index-by str)
(clojure.set/map-invert))
;; => {1 "1", 2 "2", 3 "3"}
(conj clojure.lang.PersistentQueue/EMPTY some-item)
. Just like any other immutable collection in Clojure, with the only difference being the way you create an empty queue. Other common operations would be peek
and pop
.
Looking at the medley lib, seems not many killer functions. Maybe only the deep-merge
count as one http://weavejester.github.io/medley/medley.core.html#var-deep-merge
I used to use map-vals before Clojure 1.11. Index-by is useful too, and assoc-some. It's a minimalistic library but imho quite useful
Is there good native solutions if I need TLS? The stuff I'm finding on github is quite old.
I don't know exactly in what sense you ask, but sometimes we use https://github.com/aphyr/less-awful-ssl and sometimes we try to use p12-keystores instead of the JKS ones.
Hi everyone; I have a weird mismatch in behaviour between REPL and uberjar. For (println (java-time/instant))
in REPL I get #inst "2022-05-18T11:24:01.699124574-00:00"
and with uberjar I get #object[java.time.Instant 0x70cd122 2022-05-18T11:25:40.441559477Z]
. Has anybody encountered this and is there some magic I'm unaware of?
this is blowing my brain a little bit... let me check...
cider adds some print-method implementations but not for java.time.Instant
Indeed, I think @U45T93RA6 is correct; with lein repl
when I print an instant I get the #object
format
for me it prints #object[java.time.Instant
with cider-nrepl
As a follow-up question; How can I enable the #inst
format for java.time.Instant? It seems like https://clojure.atlassian.net/browse/CLJ-2224 is/was an attempt to add it, but the issue is still open, so I'm guessing it did not get merged yet.
you can get method implementation using
(get-method print-method java.time.Instant)
if something adds an implementation then you will see it in the namespace. (it should be different from clojure.core/...)
(get-method print-method java.time.Instant)
#function[cljs.instant/fn--727]
looks like you have clojurescript as a dependency https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/instant.clj
which is enabled in dev but disabled in uberjar (and that is fine i think)
aaaah I see
to answer your follow up question - just copy the patch from the issue somwhere in your code base 🙂
I notice that I have a gap in my understanding of how a Clojure program springs into existence. Trying to introduce what the REPL is, and brings to the table I wrote this: > Inside Clojure runs the REPL. To understand this REPL, let's start with what happens when a Clojure program is created. It is done in these steps: > 1. The Clojure Reader, reads the source code of some first file > 2. The text is converted to Clojure data (Clojure code is data) > 3. This Clojure data is sent to the Clojure Compiler, which compiles it to Java byte code > 4. This compiled code is then evaluated. And if this first file requires other files, this process is repeated for them as well. Including this step. > > Step 1 is Reading. Step 1-3 happens at compile time. Step 4 is Evaluating. Evaluation happens at run time. Once all of a Clojure program is compiled, and the program is running, only evaluation of compiled code is going on. > > However, during development the services like the Clojure Reader and Compiler are still there. And they can read new code and replace any part of the compiled program, while it is running. This makes the Clojure REPL something different than what you might think of as a REPL, such as the one in Python or the console in JavaScript. > > The R in Reading and E in evaluation are the RE of REPL. The REPL is the program that uses the Reader and the compiler and the evaluator, then ”Prints” the results (that is sends it back to the user) and Loops back ready to Read new code. > > That you can compile, and install new or updated parts of your programs is what opens up for what we refer to as Interactive Programming, or sometimes REPL Driven Development. > ... To me it looks a bit funny there with step 4, a circular reference, or a snake eating up itself from the tail... Any help with getting this right would be super appreciated! (Not just step 4, I am very good at misunderstanding things in general.)
There's a bit you missed where: Clojure's runtime is initialized The core namespace is loaded first which bootstraps the language, runtime and reader This is stage 0, so to speak, then you don't have the snake eating its tail
Thanks! So I added: > 0. Clojure's Core namespace is loaded, which bootstraps the language, the runtime and the Reader Is the rest largely correct, you mean?
First the Runtime class is initialized, then core is loaded, it populates some vars used by LispReader then you're off to the races
The rest seems accurate to me, there's also a good talk about this somewhere about Clojure's compiler
This is supposed to be entry level stuff. 😃 But I'll add the things you mention anyway, because cognitive dissonance hurts.
I don't understand step 1, I thought you were talking about the REPL
if you're talking about a repl, it's not reading any files, it's waiting to read something from the terminal
there are multiple other ways to "run" a Clojure program with some subtle differences (but I wouldn't call these the REPL)
I'm going to show Calva's Getting Started REPL thingy. So I want to let the viewers know what has happened up to that point when we start REPL-ing. No terminal involved.
but, there isn't a file being read is there?
(sorry, I'm catching up on the docs)
I guess I'm curious what that actually does - clearly you open these files in Calva, and you start a repl. do you actually load one or all of them?
The text above continues: > So here all of the above has happened. Calva has started a Clojure REPL and also evaluated this file. That means that all these vars defined in this namespace are created. And you can see that the file is evaluated by the fact that this ”Welcome” text is printed. It is the last thing in this file.
You are identifying a weak spot in the getting started REPL, @alexmiller...
Calva makes a promise never to evaluate anything you don't ask it to evaluate. But the getting started REPL actually evaluates this first file. Not the other two though.
I tried without loading it first, but it didn't quite have the right "This Guide has started” effect.
ok, that catches me up :) so I think there is a difference in describing what has happened vs "what happens when a Clojure program is created". it's different for a good reason, but maybe it should not mislead you into thinking this is normal?
However. It is the REPL doing it. So it is a bit of a lie that ”all the above” has happened, maybe. But I think it is fine. I just want to set the stage for appreciating what the REPL is, and how it might not be what you think it is.
I would combine 1. and 2. - the Clojure Reader is importantly the component that reads the text and makes Clojure data.
I don't know if you want to get into this, but it is an important difference from other languages (like Java) that "read" is not "read a file" but "read the next form" and compilation happens on a per-expression basis
and this is NOT DIFFERENT than you typing it into the repl yourself
The text actually continues in this direction. 😃
> Calva is a REPL client hooking the files you edit to the REPL running inside that compiled and running app. We can send things to this REPL by selecting it and run a command.
>
> You don't need to select things, though, Calva is pretty good at sending the right thing to the REPL. There's a video about it on this channel ”The Current Form”. You use ctrl+enter
to evaluate the current form. The reason Calva can do this is that Clojure is a LISP and the code is structured in nested list.
Then I have no more text, because I stopped and thought that maybe i had gotten the mechanisms wrong there.
in some sense, I think it is actually backwards to start from the REPL (or talk about the REPL at all), the important bit is that doing anything in Clojure follows the process of reading Clojure code (a string) into Clojure data, (which is compiled to bytecode and loaded into the JVM but maybe you can avoid talking about this for a long time), then evaluates the Clojure data
where does text come from? read from a file, open in your editor, or hey you can also just type it into a terminal
Good points! I'll have a think. There is some constraint here in that the feature is called Getting Started REPL. And I feel a need to elaborate a bit on what do I mean by a REPL, since it carries many connotations.
the last time Rich and I talked about this in depth, we talked about how we should talk less about the REPL and more about interactive development. much better to focus on interactive "eval from my code"
yeah, I'm giving you big picture ideas here, I'll let you figure out how to express :)
I'm in that camp too, actually. I say Interactive Programming in the text above, Should I use Interactive Development, you think?
teaching people to type things in a REPL is a dead end. teaching them to interactively develop in their source is alien superpowers
either of those is fine, the "interactive" (vs REPL) is the important bit
I like it :)
That's why no terminal. But I intend to show that you can also send stuff to the REPL from the prompt. To have the prompt and the file open side by side opens up for some comparisons that can drive this point home, I think.
isn't there some other tool that has no prompt at all? I think that is a bold but maybe interesting choice.
Though I do have a dead end in the Getting Started REPL thing still. There is no project created that the user can continue with. I intend to fix that.
yes, that's an important connector
Clover doesn't have a prompt. I think that was some MVP think at first, but people liked the bold move and it never got a prompt. 😃 Maybe I am not having this entirely correct. @U3Y18N0UC should tell the story, not I.
personally, I think it is mis-step to talk about stuff like project templates and clj-new etc at the point of moving to a project - really you need almost nothing to be in a project (a deps.edn with {}
and a src/ dir)
Yes. I have many such projects. 😃 Calva has a few ClojureScript starter commands that create this as well.
anyways, I appreciate you working on this and am happy to provide feedback (if you want it, I know you have plenty of your own ideas and I'm not trying to tell you what to do :)
I live by the mantra ”Don't tell me what to do!”, so it wouldn't do you any good if you did anyway. 😃 Appreciate the feedback a lot!
You can get away with no deps.edn
file too and just have src/
and some code (until you need dependencies) but I don't know whether that's helpful or not in this case...
@U0ETXRFEW About Chlorine/Clover, the full story is less beautiful 😄. To iterate faster, I used an UI library on Atom that did have the prompt, but I simply ignored it because it would take more time to have the first version ready. People got confused with the prompt that did nothing, so I removed it via CSS :rolling_on_the_floor_laughing:
Then that UI library changed (like, A LOT) and I quickly wrote a version of the console tab by myself, I believe in a couple of hours, to at least keep Chlorine working. Obviously, missing the prompt again...
I guess I didn't realize that Calva's output window is actually a REPL you can type into as well, since I came from Clover where there was no "typing into a REPL"... 🙂
(why would anyone type directly into the REPL? that's crazy talk! :rolling_on_the_floor_laughing: )
Finally, I was happy with Shadow-CLJS (ClojureScript) support and decided to re-visit the idea of being able to type on the REPL. By that point, almost all of the code was depending on a text editor being selected. Well, if you have the console selected, the editor does not really know which TextEditor it needs to use, so in the end.... I left as that. @U04V70XH6 with his preaching of "never type in the REPL" helped me a lot to both understand that I made the right decision (even if by accident 😄), and to convince people that "it is not a bug, it is a feature!" (spoiler alert, it was a bug but ended up becoming a feature :rolling_on_the_floor_laughing: )
Using https://github.com/nextjournal/clerk and https://github.com/scicloj/clay results in even less reasons to even look into the REPL at all, the browser becomes the (read-only and graphical) P of the REPL
@U7CAHM72M I use Portal, inside VS Code, so everything is part of my (full-screen) editor context and I don't need to switch to a browser for anything.
@alexmiller Tonsky's Clojure Sublimed has no prompt and doesn't need any other files; if deps.edn
is in the $PWD
it will use it, but works fine without.
It needs a nrepl server to connect to, so I guess that if nrepl server is started with -i
(interactive) option it can have a prompt.
Do I have to do something special to make clojure.data.json/write-str
write java.time.Instant
without throwing an error? It seems as if there is support for it via JSONWriter
protocol, yet I get:
(require '[clojure.data.json :s json])
(json/write-str (java.time.Instant/now))
Execution error at clojure.data.json/write-generic (json.clj:385).
Don't know how to write JSON of class java.time.Instant
My classpath (only) contains [org.clojure/data.json "2.4.0"]
Any chance you have Clojurescript on the classpath?
yes @alexmiller, I do...
ok... I think I get the message... this is the second time today I'm struggling with java.time.Intstant, and both times it was having cljs in the classpath. I guess I never realized I shouldn't do that. Thanks for input :thumbsup:
Clojurescript includes an older version of data.json in it
It's not your fault and this should not be an issue :)
oh wow... this validation feels so good when I've been banging my head against it for a while. I will update. Thanks again
hello folks, does anyone know if there is a tool to navigate on EDN data on terminal? I'm looking for something that allows to navigate some generic EDN structure, able to expand/collapse parts as we go
In principle, it wouldn't be that hard to add terminal support to https://github.com/phronmophobic/viscous, but I'm not sure what benefit there is to having a TUI when you can have a GUI. Are you trying to inspect data over the network via ssh?
> How would it work in a terminal? It's not used very often, but most terminals have mouse support.
https://github.com/borkdude/jet might be a good fit. I usually use it from inside vim which makes it easier to explore the data.
@U2FRKM4TW I imagine like on Emacs you can expand/collapse sections (think Org Mode)
@U7RJTCH6J no network, I just wanted a simple way to view, I'll check viscous, seems to be what I'm looking for 🙂
Ah ok. You may also want to check out https://github.com/djblue/portalwhich is a bit more polished. If you're using emacs, you can also try M-x cider-inspect
I do use portal all the time in dev 🙂, this is more for a case where I have no REPL
Sounds good. Viscous does let you just pass a file or read stdio. Feedback is welcome!
@U7RJTCH6J just trying, the pipe version worked fine, but when trying to pass a file I got an error:
clojure -X:viscous :file 150232_CARGUEROINOVACAO_VIACORRETOR.edn
Unreadable arg: "150232_CARGUEROINOVACAO_VIACORRETOR.edn"
this works fine: cat 150232_CARGUEROINOVACAO_VIACORRETOR.edn | clojure -X:viscous :file -
just realize it needs to be a Clojure string in the arg, this works: clojure -X:viscous :file '"150232_CARGUEROINOVACAO_VIACORRETOR.edn"'
but the docs make believe the first should work
If you a file or copied value, Portal can be used standalone https://djblue.github.io/portal/.
@U1G869VNV on that, this reminds me of a bug in Portal IntelliJ extension, when I accidentaly drag a file over it, it enters in the "drop zone" state and never leaves, not sure if you are aware of this one
and yeah, the standalone is lovely, I really got used to the portal way of navigating data ❤️
@U1G869VNV is there a place with the shortcuts list on portal? I keep forgetting how to bring the command pallet there (suggestion: the shortcut could be in the hint message on the UI button, that way it gets easier to remember)
They should be listed when you open the standalone app, :
, ctrl + j
or cmd + shift + p
. The hint sounds like a good idea too :thumbsup:
I'm blind, haha :man-facepalming:
thanks, yeah, that solves it (looking at the home), I guess I got so used to the extension (that doesn't have the "home screen") that I didn't notice them in my face
@U066U8JQJ https://github.com/djblue/portal/commit/b0ecdc3633a016f223c3aab60708394ae7035161 should fix the drop zone issue, not perfect, but good enough for now 👌
also, I'm doing something gross (using throw for something other than error handling), so I actually think it would be better to base it off Throwable
than Exception
? not sure what consequences that might have tho
You may want to take a look at https://github.com/scgilardi/slingshot
@U4YGF4NGM using it for something other than error handling is fine. the JVM is well-built for it. It absolutely should not extend exception if it's intended to not be an error condition however.
If you want a semantic type just extend throwable. If you want to have an explicit statement in the types that the value should not be caught by anyone except you, extend Error.
This is exactly what I did for #farolero, which has a non-exceptional throw as well to provide early return.
@U5NCUG8NR I see you have a simple java class you wrote. how do you develop locally & package it for deployment?
I use https://github.com/IGJoshua/americano , my simple java compilation library. It even supports git dependencies
which means when I change the java class (which is almost never) I just run clj -X:build
which compiles everything and then restart my repl.
Glad I could help!
I'm a bit ignorant of Java deps stuff. do you distribute the compiled artifacts in the JAR then when uploading your lib to e.g. clojars?
yes, the compiled result needs to be in the jar when put onto a maven repository.
only the java code should be compiled when put into clojars though, clojure code should be source-only
I need to signal from within a function that some parent context ought to skip whatever work the function is supposed to do and come back to it later
psuedocode:
(defn comments []
(let [data (get-comments!)]
(div
(for [comment data]
(div comment)))))
(defn page []
(html
(body
(div
(suspense {:fallback "Loading comments..."} (comments))))))
I want to, on first pass, signal from within comments
that the parent ought to send the fallback to the client and start fetching comments. then after the comments data has been fetched, stream some special code that will replace the fallback with the comments markup
there is some new fancy clojure/clojurescript library that chops things up and streams things back and forth from client to server
I don't think that delimc
et al. would work for me, because the reset
boundary is outside the lexical scope of the shift
in the code above, and that's necessary to Interop with existing code
loom continuations aren't reentrant so I don't think they would work for this case either
You could run the computation in another thread and use a channel to communicate that computation should suspend
(let [to-parent (chan)
to-child (chan)]
(thread (try
(do (<!! to-parent {:type ::come-back})
(!!> to-child)
(<!! to-parent {:type ::okay-done}))
(catch Throwable t (<!! to-parent {:type ::error :throwable t})
(loop [result (<!! to-parent)]
(condp = (:type result)
::error (throw (:throwable result))
::come-back (do (Thread/sleep 1000) (<!! to-child {}))
::okay-done nil))))
like I don't understand from this sketch how that integrates with the pseudocode I posted. at the end of running the page
function, I need a data structure that describes the HTML I should stream to the client. then I need to later stream some small JS code that replaces the fallback with the comments
rn i have some code that recursively walks the page tree, calling functions it finds until it has reached every leaf. I can in that code catch any errors and bubble that up to the nearest suspense
boundary
this doesn't show me how I would handle that "stack" of boundaries, return the fallback, etc.
I always forget that delimc does code transformation because core.match uses exceptions for jumps
I already have a lot of the machinery worked out. the way this works in React JS (which I'm copying the design of) is it throws a JS promise.
the way I want to do this is to throw a manifold deferred or something similar, but I can't do that because the type system is more strict
if I catch an ex-info, check it for the payload, and if it doesn't have what I want re-throw it, will that mess with the stack trace?
user=> ((fn g [] (try ((fn f [] (/ 1 0))) (catch Throwable t (throw t)))))
Execution error (ArithmeticException) at user/eval2194$g$f (REPL:1).
Divide by zero
user=> (.printStackTrace *e)
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field printStackTrace can't be resolved.
java.lang.ArithmeticException: Divide by zero
at clojure.lang.Numbers.divide(Numbers.java:188)
at clojure.lang.Numbers.divide(Numbers.java:3901)
at user$eval2194$g__2195$f__2196.invoke(NO_SOURCE_FILE:1)
at user$eval2194$g__2195.invoke(NO_SOURCE_FILE:1)
at user$eval2194.invokeStatic(NO_SOURCE_FILE:1)
at user$eval2194.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:7181)
at clojure.lang.Compiler.eval(Compiler.java:7136)
at clojure.core$eval.invokeStatic(core.clj:3202)
at clojure.core$eval.invoke(core.clj:3198)
at clojure.main$repl$read_eval_print__9110$fn__9113.invoke(main.clj:437)
at clojure.main$repl$read_eval_print__9110.invoke(main.clj:437)
at clojure.main$repl$fn__9119.invoke(main.clj:458)
at clojure.main$repl.invokeStatic(main.clj:458)
at clojure.main$repl_opt.invokeStatic(main.clj:522)
at clojure.main$main.invokeStatic(main.clj:667)
at clojure.main$main.doInvoke(main.clj:616)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:40)
nil
user=>
I don't want to obscure real errors, which is why I was thinking of a custom type that extends Throwable
as someone who routinely catches Throwable, I don't put too much stock in the details of inheritance hierarchy under Throwable