This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-03-13
Channels
- # announcements (12)
- # babashka (42)
- # beginners (45)
- # calva (60)
- # cider (6)
- # circleci (1)
- # clj-kondo (18)
- # clojure (21)
- # clojurescript (36)
- # conjure (13)
- # cursive (2)
- # datahike (5)
- # datomic (4)
- # depstar (17)
- # emacs (4)
- # fulcro (3)
- # honeysql (2)
- # jobs (2)
- # jobs-discuss (9)
- # lsp (98)
- # malli (32)
- # off-topic (36)
- # other-languages (2)
- # overtone (4)
- # re-frame (5)
- # reveal (7)
- # rewrite-clj (47)
- # shadow-cljs (25)
- # spacemacs (4)
- # vim (7)
Yep, sorry I just deleted that on ya. I figured that out on a hunch seconds before you posted
[Audience: What about the condition system? You know, restarts ...]
You know, I looked at that. I mean, I actually think that the condition system is a hard coded special case in Common Lisp. That if you had some more general primitives, the condition system would just be one thing you could implement with them.
In Clojure, you have two things you can utilize to help you with those kinds of problems. One is the exception system, which allows you to travel up and down the stack.
The other is that dynamic binding of functions. You want to have a function. I am going to bind this function to something that you should call if you have a problem. Well now you have got that ability to call some code from above down low to see what you should be doing. Combining dynamic functions and exceptions gives you some of the condition system.
[Audience: But it does not give you restarts.]
[Audience: You can, once you throw an exception.]
But you do not throw an exception. That is what I am saying. Let us say you are somebody who needs to talk to the file system. And you say: if I have a problem talking to the file system, I am going to call "I had a problem talking to the file system". Somebody above you can bind that to do whatever you want. You are going to call that and use the return value, and not throw.
Right, and so I think that gets you most of the way there. Dynamically rebinding of functions and exceptions, I think, is enough. I like the condition system, but it seems to me to be a hard wired special construct, rather than two ...
— from https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureIntroForLispProgrammers.md
What is Rich Hickey referring to, when he mentions “the exception system, which allows you to travel up and down the stack” ?He's talking about the JVM's built in exception handling behavior, which unwinds stack frames one at a time, re-throwing the exception, until it is caught.
There's a lot more detail here: https://www.infoworld.com/article/2076868/how-the-java-virtual-machine-handles-exceptions.html
It isn't clear to me what he means when he says "up and down the stack", though. It is clear exceptions let you go one way (popping things off the stack)
yeah the "down" is less clear but I think I grok
when you use try
it compiles to bytecode that will insert an entry in the exception table, then you might call another function inside the body of the try
... in this sense you are "on your way down the stack" and the exception system is at work
though the entries in the exception table have nothing to do with the stack IIUC
they just include ranges of bytecode for which that exception handler applies
They do have something to do with the call stack in that some stack frames have an exception handler, but others might not.
sure, I just mean at the jvm bytecode level
At least, they can be viewed as behaving that way, regardless of the underlying implementation.
that seems right
The mechanism for throwing an exception in the JVM does behave like it is popping frames off the call stack, and in each one, checking whether an exception handler exists in the byte code location where the call occurred.
So control is traveling according to your code and the bindings you decided beforehand. But you (the developer) can’t travel arbitrarily while you’re testing and developing in the context of an eval, right? (I think what was confusing me was he said “you” and this was in comparison (in the conversation) to Common Lisp where you really could pick an arbitrary frame to restart after tweaking a binding.)
Are you talking about Common Lisp systems that let you enter an interactive debugger, modify bindings,and continue running the program?
There are some things at least similar to that in the Clojure world, none that I have personally used.
One kind of hand-rolled one can be found by searching for "break" in this talk transcript: https://github.com/matthiasn/talk-transcripts/blob/master/Halloway_Stuart/REPLDrivenDevelopment.md
I haven't looked for anything that is more like what some CL implementation give you, since I personally have never gotten into that style of debugging much.
That clojureman special project readme lists way more things than I would have ever recalled
I feel like I've seen quite a few clojure-debug projects come and go, though I can't recall how to find very many of them... I don't think I've ever seen the ability to pick a particular stack frame and resume from there (without setting a breakpoint there first)
sounds like an interesting feature, although I must admit I don't know exactly what I'd do with it if I had it
Probably in cases where it is very expensive or inconvenient to get to back to the same setup to re-try a proposed fix. If we have well-thought-out functions and manage state well, then normally this isn’t an issue. But we don’t always get to work with clean code. Restarting from an arbitrary stack frame feels like traveling back in time. But of course any side effects that already happened remain, and will be attempted again …
Hi
I had a quick question when I try to run this function i always get this .call is not a function
I am not sure why it’s not working. Am I doing something wrong?
(def word (atom ""))
(defn testing [string]
(if (= string "test") (swap! word "changed Value"))word)
(testing "test")
this is what I am trying to accomplish ( I am js dev)
function testing(string) {
let word = "";
if(string === "test") {
word = "changed Value"
}
return word
}
testing("test")
output: "changed Value"
swap!
takes a function as its second argument, that accepts the current value and transforms it. Your string is not a function. For your case, you'd want to call reset!
Thank you for helping @U01GXCWSRMW noob in clojure 🙂
Hi everyone, just wanted to know if I am correctly executing the main function of a clojure file using the clojure command-line tools. I used the command: clojure -M -m pinger.core
The pinger.core clj file contains my main function. The command worked, just wanting to know if that is the correct way of doing it as I just inferred it from reading the clojure command-line tools help output and re-working the book's (that I am learning from) command of clj -m pinger.core
which seems to no longer be the correct way of doing it.
That is correct
-M means to run clojure.main, and -m is passed to clojure.main with a main class name
OK thank you very much Alex 🙂
Also when I first ran the code I got back an UnknownHostException for http://www.google.com but I can't repro it as afterwards every subsequent run went fine.
The source code for that is: (ns pinger.core
`(:import [http://java.net URL HttpURLConnection]))`
(defn response-code [address]
`(let [conn ^HttpURLConnection (.openConnection (URL. address))`
`code (.getResponseCode conn)]`
`(when (< code 400)`
`(-> conn .getInputStream .close))`
`code))`
(defn available? [address]
`(= 200 (response-code address)))`
(defn -main []
`(let [addresses ["https://google.com"`
`"https://clojure.org"`
`"http://google.com/badurl"]]`
`(while true`
`(doseq [address addresses]`
`(println address ":" (available? address)))`
`(Thread/sleep (* 1000 60)))))`
So was just curious as to why I might have gotten an UnknownHostException upon first running it?
Hi guys, I'm struggling to avoid thinking of modelling concurrent code with JS's Promises. It feels quite convenient to have functions that return Promises. I've written trivial code which use core.async semantics but I've not found tutorials/posts/etc that really go into detail into how JS Promises can be replaced by core.async semantics. Am I wrong in thinking that JS Promises solve totally separate problems that core.async is supposed to? If anything, it feels like core.async is much better compared with JS AsyncIterators
Give this talk a watch, Rich compares the core.async approach with promises https://www.youtube.com/watch?v=drmNlZVkUeE
Sweet, thanks. I'll check it out
I’m trying to learn macros, and am struggling a bit with something, I can’t work out how to turn a symbol->var->keyword of that var. Given something like the below:
(defmacro foo
[data]
(clojure.walk/prewalk (fn [part]
(if (symbol? part)
(if-let [resolved-var# (resolve &env part)]
(let [kw# (keyword resolved-var#)]
`[~kw# ~resolved-var#])
part)
part))
data))
=> #'user/foo
(defn bar [a b]
(+ a b))
=> #'user/bar
(foo [bar])
=> [[nil #'user/bar]]
..I’m trying to get something like [[:user/bar #'user/bar]]
out. what am I missing?
I’ve tried (keyword
resolved-var#)` but - predictably - that gives me the auto gensym, something like [[:resolved-var__31201__auto__ #'user/bar]]
- not the originally passed symbol. Any ideas?