Fork me on GitHub
Drew Verlee02:09:46

quick poll. Click emojii reaction to vote. 1️⃣ Eval side effecting expressions in editor (probably in comment block!) 2️⃣ Eval side effecting expressions in repl

1️⃣ 30
2️⃣ 1
Drew Verlee02:09:31

Well, my advice, is if you eval things in your editor, you find a way to view the log. This, like most things, is obvious once said aloud. In cider the log is called (as you might have guessed): cider-repl-history

Drew Verlee02:09:44

Though, it's currently not showing me the history i want...


What is the difference?


I have all logging wired into tap> so it appears in Portal inside my editor (VS Code) which is very helpful 🙂

Drew Verlee03:09:49

@ hiredman. The difference, to me, is that the repl... (this interface at least):

> (inc 1)
> (inc 2)
Gives me a history of what i did, which only matters if what i'm doing is stateful. Usually, i don't have a bunch of stateful stuff to review, but with this aws thing i do, and i realized i need a log in order to make it sane.

Drew Verlee03:09:59

Thanks @U04V70XH6. i'll take a look 🙂


Portal maintains a history of tap>'d values. And the REPL in VS Code/Calva also maintains a history. So I guess I'm not sure what you're asking about (or complaining about)?

Drew Verlee03:09:04

@U04V70XH6 I think you might be responding to my comment "The difference..." as if it was aimed at your reply, but it was aimed at hiredman's question "what is the difference". I edited the comment to clarify.

Drew Verlee03:09:22

we need threads within threads!


No, I meant your comment about history.


It sounds like evaling from your editor doesn't give you an easily accessible history of evaluation?

Drew Verlee03:09:21

Correct, i'm not currently able to find it. I have the cider-nrepl-history command, but it's bringing up history from a repl i ran like a week ago. (or so it seems)


There are many reasons I switched from Emacs 🙂

Drew Verlee03:09:26

I'm not sure i'm asking the emacs client the riqht question... but if it's too hard to ask, thats kind of an issue itself.

Drew Verlee03:09:35

it would seem to be. idk i'll make a ticket, hopeful someone can help or i can find the time to help or ... i can learn to do the 100 small things i do in emacs in vscode. 🙂


I started with Emacs back in the 17.x days, and used it through the early 19.x days, then drifted off to other editors for years. Then I came back to Emacs when I picked up Clojure. Maybe the late 23.x days? Anyway, I used Emacs on and off for years with Clojure but I was never really satisfies and I kept trying other editors, back and forth. And finally switched to Atom and ProtoREPL, then Chlorine when ProtoREPL dropped out of maintenance, then VS Code after Chlorine was ported to VS Code as Clover, and once I was on VS Code, I switched to Calva. I like that I can customize it/drive it with ClojureScript via Joyride, and VS Code is super customizable overall. Having the Portal extension so Portal is built right into VS Code is awesome, and the recent Notebook support work is very, very promising for development/RCF work.

👀 1

For a counterpoint, I switched from VSCode/Atom/IntelliJ to Emacs and like Emacs 1000x more. But I also learned Emacs Lisp and went through the full Emacs manual. Of all of them VSCode was my least favorite.


Ok, now to the main question. If you eval code in the REPL, it evals within the current *NS* of the REPL, most of the time you want to eval within the context of the namespace you are working on. So evaling in the file has that advantage. The other benefit, is most likely you want the commands you might need to have handy every time you work in that namespace also available to you in the future or for other developers. That's also a benefit to doing so in the file.


You can switch to using the Cider "send" commands instead of "eval" ones. They'll send stuff to the Repl window to be run, so it will add to the repl history. But I don't think there's a feature to have a history of evaluations, though seems it shouldn't be too hard to add, could be a nice feature.

Drew Verlee01:09:52

Ahhh, so the nrepl history is for the send commands. That's good to know.

Drew Verlee01:09:52

Yeah, I'm trying to gain the courage to either drop emacs or learn how to help fix up the parts of it that i use most often.

Drew Verlee01:09:10

Thanks for the insight @U0K064KQV!


What keeps me to Emacs are the fundamentals. The navigation/indenting, the simplicity of the theme, zero UI anywhere, all keyboard based navigation, easy macros, avy jump commands, swiper, winmove, auto-indent, the quality of smartparens, selection, project management, opening files, etc. The rest of Emacs can be annoying, could have better UX support, can be finicky, no good windows support, can be a bit slow on big files, etc. But I have not found another editor that has those fundamental things that I love.


VS Code can be scripted with cljs (via Joyride) and I use entirely the keyboard for working with it, creating Jira issues and BitBucket Pull Requests and reviewing them all entirely inside the editor 🙂


I think both Emacs and VS Code are extremely competent, scriptable editors these days with an amazing range of packages/extensions, which great Clojure integration.


I couldn't get anything I wanted from VSCode. Like I said, things like swiper, aggressive-indent, smart parents, winmove, undo-tree, avy-jump, etc. Now I'm a little surprised you use only the keyboard, and maybe I'm skeptical, unplug your mouse and you'd be fine? Last time I tried it was 2 years ago, so maybe I could give it another shot, though I also don't like Microsoft, so am not really in a rush. Some of the limitations on the VSCode API too was super annoying, I've hit that before, it's really not very customizable, unlike Atom, which is where I'm also disappointed they killed Atom in favor of VSCode. The only thing tempting me again is the web view integration, having portal embedded or having your web view side/side is definitely tempting... I do hope Emacs finds a way to embed proper web views in the future.

Drew Verlee22:09:57

@U0K064KQV why stop at a webview in emacs when you can just put everything in Emacs with exwm?

👀 1
Drew Verlee23:09:19

The solution to your emacs woes is always more emacs.


Do you use it? It looks a bit insane haha, also not sure if it will play well with WSL2 in windows :thinking_face:


Is there a way to go back to previous namespace without loading it again? something like cd - or git checkout -


in-ns takes a name of the namespace, sorry for not being clear before, but I was thinking of something that can be treated as a shortcut/short command in my IDE.


so, if there was something like (in-ns -) then it would serve my purpose 🙂

Ferdinand Beyer13:09:36

This is not supported by built-in tools. There might be some REPL implementation out there that does support this. However, you might want to consider how you use the REPL in the first place. Don't think of it as a fancy shell 🙂 If you have not done it yet, consider connecting an editor to your REPL, and send snippets from your editor instead of typing in the command prompt.


I'm using test-runner like from deps this: io.github.cognitect-labs/test-runner {:git/tag "v0.5.0" :git/sha "48c3c67"} Now I can't run tests without an internet connection: Execution error (ExceptionInfo) at (impl.clj:94). Unable to fetch /Users/user/.gitlibs/_repos/https/ fatal: unable to access '': Could not resolve host: Is that expected? (The other problem of course is that network activity is slow so it slows downs the tests)

Alex Miller (Clojure team)14:09:33

you prob should switch to the full sha in the git coord instead of sha/tag (as short shas cause verification with tag)

{:git/sha "48c3c67f98362ba1e20526db4eeb6996209c050a"}


You're right. This works for me:

:extra-deps {io.github.clojure/ {:git/sha "0d20256c40b5a6b6adbcbdf7d0c52cf9e22e994d"}
                      org.clojure/test.check {:mvn/version "1.1.1"}
                      {:git/sha "48c3c67f98362ba1e20526db4eeb6996209c050a"}}

Jacob Rosenzweig20:09:35

Why do you need to convert an inst/date to a zoned or local date time to do any arithmetic wrt time between dates. E.g. (jt/time-between inst-now inst-yesterday) (assuming both args are instants) will give an error. This is the java-time lib btw.

Jacob Rosenzweig20:09:40

It’s more of a Java api question tbh but I’d assume at least this would work: (jt/time-between inst-now inst-yesterday) but it fails if the two args are instants/dates


what is the error you get?

Jacob Rosenzweig20:09:15

; CompilerException java.lang.IllegalArgumentException: No single method: time_between of interface: java_time.core.KnowsTimeBetween found for function: time-between of protocol: KnowsTimeBetween


java-time is all about the newer java.time.* stuff, where as the clojure #inst tag is by default read in as java.util.Date (but many time types print as #inst literals)

👀 1
Jacob Rosenzweig20:09:48

Okay actually I lied, (jt/minus (jt/instant) (jt/days 2)) isn’t given me an error. I think it’s just hte time-between that it trips up on.


that error isn't actually an error calling time-between, it is an error in the protocol machinery


(java-time/time-between (java-time/instant) (java-time/instant) :days) doesn’t error for me. Can you give an example that errors?


hard to say what exactly is causing it, maybe some kind of bogus code reloading


or stale aot compiled classes or something


like somehow the java inteface generated by the protocol and the protocol itself are out of sync


(as far as I can tell quickly looking at it, you should never get that error with the protocols in java-time because nothing implements them directly)

Jacob Rosenzweig20:09:24

after smashing the hot reload keybind in calva a few times, I think the errors are going away

Jacob Rosenzweig20:09:07

Cool, everything checks out. Looks like this was all user error. Thanks for the explanation guys


anyway, I don't like using java-time, most date types will have the protocol clojure.core.Instant extended to them, so for date type polymorphic code to find the time between two dates I would do something like (fn [earliest latest] (.until (Instant/ofEpochMillis (inst-ms earliest)) (Instant/ofEpochMillis (inst-ms latest)) TemporalUnit/SECONDS))


I guess you could do (Duration/between ... ...) there as well


Why do (:a 2) , (:a (atom nil)) , etc return nil instead of usefully complaining about trying to treat a non-associative thing associatively? (same for get which I would have hoped to be more strict)


That feels like it should be an FAQ on 🙂 Ah, I think that was what I was trying to find...


Thanks! I might go as far as adding get to my clj-kondo :discouraged-vars... I don't like bugs / time wasters :)


nil-punning is your friend 🙂


or is it :thinking_face: there's also but probably it would need some love first.


speculative specs functions as they are intended to work (often verified with the core team) in clojure, not how one wishes them to work.


get is a very forgiving function, by design. e.g. in keys destructuring it does not crash. if it would, many programs would likely be broken


I've heard that before, but why would destructuring have to use the same get function that is a public API?


dunno, but Clojure does that. Instrumenting get with a spec which thinks otherwise would crash currently valid code.


maybe you could try spending some energy on this in an ask.clojure issue


or make your own get function which is less permissive :-D


I think I'll use find + val where I can. With a bit of luck I'll manage to convince peers along the way!

👍 1

(just kidding: fantasizing about a project name which would be a bit upsetting ;)


user=> (defn get- [^java.util.Map m k] (.get m k))
user=> (get- {:a 1} :a)
user=> (get- "foo" :a)
Execution error (ClassCastException) at user/get- (REPL:1).
class java.lang.String cannot be cast to class java.util.Map (java.lang.String and java.util.Map are in module java.base of loader 'bootstrap')

👀 1
Joshua Suskalo13:09:09 Worth sharing here I think. Yes you can make a less permissive get, and maybe it's okay to have it, but nil punning genuinely is a reasonable strategy for specific parts of programs to allow you to write more elegant code.


oh don't get me started about nil punning :)

Joshua Suskalo14:09:06

actually I'd love to get you started on it, I want to hear more about what other people are thinking about or dissatisfied with on clojure error handling. 🙂

Joshua Suskalo14:09:43

Seeing as that's the part of clojure I like the least, and what I want to focus time and effort on improving, which is what #farolero is an attempt to gain information on.

👍 1

I enjoy giving an unmistakable semantic to nil : nothing, absence of a thing. A programmer error is not nothing. An user-facing error is not nothing. An empty list is not nothing. False is not nothing. So nil-punning (at least the way I last understood it) seemed a huge conflation to me. A remnant of a past where people where more concerned with concision than with correctness/maintainability.

Joshua Suskalo14:09:26

arguably nil in the mindset of nil punning is not programmer error, user facing error, empty lists, false, or anything of the kind. It's None in a maybe monad and nil punning is implicit bind. That makes it a useful tool for chaining computations and at the end once you have your final result (after lots of elegant code where you don't have to check every second line) that is either something or it's nothing, and you act accordingly.


@U45T93RA6 With the rigidity you're often looking for (my interpretation) the thought in my head came up whether you evaluated more rigid languages like ocaml/haskell or perhaps a typed lisp (I don't think there is a major typed lisp for production right now, but could be wrong)

Joshua Suskalo14:09:57

i mean there's the typed-clojure project, plus racket has optional types.


yeah, but I said production

Joshua Suskalo14:09:51

That's why I only mentioned those two and not like carp or anything 😅


I saw a blog post by circleci about typed clojure, but this may be severely outdated


(find [] :x)
=> nil
(find nil :x)
=> nil
(find #{:x} :x)
Execution error (IllegalArgumentException) at me.test/eval28742 (test.clj:32).
find not supported on type: clojure.lang.PersistentHashSet
(:x #{:x})
=> :x


If you compare for instance the nil-punning contract with the Result contract, it's evident which is more explicit Do we plan to convince every Clojure API to use nil punning? How do you even know it's returning nil intentfully?

Joshua Suskalo14:09:12

that's the key problem with nil punning imo, and personally I think it's mostly a failure of documentation, since in lisp land (at least without spec) documentation is our types.

👍 1

Some people made jokes about JS having two nulls: null and undefined, like a double million dollar mistake, but when I recently did some pure JS, I actually found it handy to not have to check if a map's value for a key was null or if the key was absent, in which case the return value was undefined

Joshua Suskalo14:09:26

That said, I don't like nil punning as a pervasive way to handle fallible things. It's very nice in simple cases, and I'm of the opinion that only basic data structure operations should nil pun, mostly in a language's core library.


personally, if for example I have a hetrogenous collection and I (map :x coll) I'd rather (remove nil?) than handle exceptions


> @U45T93RA6 With the rigidity you're often looking for (my interpretation) the thought in my head came up whether you evaluated more rigid languages like ocaml/haskell or perhaps a typed lisp (I don't think there is a major typed lisp for production right now, but could be wrong) I don't like static typing much (or at all) tbh. Spec all the way :) in all its expressive power (I don't see myself as rigid at all either! One can reconcile high dynamism with a devotion to correctness)


I wasn't saying you are rigid, but I've seen you have a strong opinion on what some functions should do several times. This is just an observation, nothing wrong with this at all

👍 1

As a quick note on Typed Clojure, Ambrose appears to have something big cooking. One can already see spec- and malli bridges released, among other ideas/utils.

🎉 1