This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-29
Channels
- # announcements (7)
- # babashka (4)
- # beginners (21)
- # calva (31)
- # cljdoc (12)
- # cljsrn (5)
- # clojure (89)
- # clojure-europe (26)
- # clojurescript (9)
- # conjure (1)
- # cursive (3)
- # data-science (20)
- # events (2)
- # fulcro (4)
- # gratitude (7)
- # introduce-yourself (1)
- # lsp (24)
- # nextjournal (3)
- # off-topic (5)
- # re-frame (22)
- # shadow-cljs (48)
- # tools-deps (11)
and go blocks are non-preemptive because the threadpool can't run another go block until the currently running go block yields by doing a channel operation
Thanks. That's a concept that I guess I would previously call "interrupt". Funny how a programming language-related discussion (and a look up of the etymology of "preemptive") just changed my perception of the word in a natural language.
I think this golang issue has some interesting discussions about cooperative vs preemptive scheduling: https://github.com/golang/proposal/blob/master/design/24543-non-cooperative-preemption.md You can also look up various resources about Erlang's BEAM VM's scheduler.
Reading the doc string of async/put
(defprotocol WritePort
(put! [port val fn1-handler] "derefable boolean (false iff already closed) if handled, nil if put was enqueued. Must throw on nil val."))
One part I couldn’t understand is the nil if put was enqueued
. I run some tests and find that (put!) either returns true or false. But never nil
.Why does Clojure https://github.com/ring-clojure/ring/blob/1.9.0/ring-devel/src/ring/middleware/reload.clj#L21 need to use a Queue need to use https://clojuredocs.org/clojure.core/locking? Is it because the namespaces have to reloaded independently and in a certain order? Are their any built in clojure functions that would do the same thing? Assuming its because of order, I guess the question would then become, how does https://github.com/weavejester/ns-tracker know that order? I guess that's in the clojure NS hashmap? I'm just digging into this idea a bit
(defn- reloader [dirs retry?]
(let [modified-namespaces (ns-tracker dirs)
load-queue (java.util.concurrent.LinkedBlockingDeque.)]
(fn []
(locking load-queue
(doseq [ns-sym (reverse (modified-namespaces))]
(.push load-queue ns-sym))
(loop []
(when-let [ns-sym (.peek load-queue)]
(if retry?
(do (require ns-sym :reload) (.remove load-queue))
(do (.remove load-queue) (require ns-sym :reload)))
(recur)))))))
The queue thing is really odd, my guess would be it is left over from a more complicated function that has had a lot of bits deleted
Yeah, in principle you just need to lock on something and then reload the namespaces. Not sure why they put a dequeue in there.
> The queue is maybe to support if loading causes an error
So if the (require ns-sym :reload)
hits an error while being interpenetrated, something like a missing parens, it would ... something something... let the developer fix the file and then the queue would pickup where it left off?
Yeah, the queue is persisted between runs, so the next time you go to reload all the old namespaces will still be in there
So it saves time & energy by not doing extra reloads?
E.g. if namespaces x y and z end up in the queue to reload and y throws an error, then you fix y, z is still in the queue to be reloaded
This isn't in Ring proper, is it? This is just in the weird reload middleware, I hope?
https://github.com/ring-clojure/ring/blob/1.9.0/ring-devel/src/ring/middleware/reload.clj#L21 This looks like proper ring to me
i mean, i'm not sure what it means to be proper. 😆
That's middleware, not core Ring.
I recommend not using the reload middleware. Or any of these reload/refresh things. Just don't do it.
@U04V70XH6 why not? Being able to quickly update parts of my code to see how it changes the over system is something i do a lot to great effect. I thought that this was in a similar vein or is there some drawback im missing?
This would be for development purposes only of course.
You do not need any of this reload stuff to do that.
I develop live in web apps all the time. Never use any reload/refresh stuff.
I think they just encourage bad habits.
I also think it's a really bad idea to have a different dev stack to your QA/prod stack.
there must be a terminology to implementation break down. Client sends a request to server Server improperly handles it and returns not the result i wanted I need to change the server handler. Currently i have to shut down my server, make my change, then restart it. i would call that a reload. My goal is just to make this faster in my dev environment.
No, you don't have to do that.
I fail to compute. Which part don't i have to do?
Have you read the REPL-friendly section of the official docs with the REPL guide?
You absolutely do not need to shutdown a server to make changes and you do not need "reload" stuff.
hmmm. let me load up my little server and see what i'm doing here.
I patch web apps running on remote servers via the REPL with none of this middleware.
The official docs about this https://clojure.org/guides/repl/enhancing_your_repl_workflow#writing-repl-friendly-programs
(I'm on a one-man campaign to stamp out these reload/refresh libraries and get people doing "proper" REPL-driven development!)
I have read those, but i might not have understood them because the context wasn't there for me
But in my defense, people can macro and framework you into patterns that getting out of is basically useless. So you have to forgive those of us that think Up is down.
Macros bad. Frameworks bad. 🙂
I think we as a community are really bad at teaching beginners the "right" way to do stuff 😞
Although, to be fair, http://clojure.org has really good guides. But people don't read them end-to-end, and they rely on random tutorials online and random frameworks that enshrine "bad" practices 😞
I'm getting my little server setup here, then i'll really look at what i'm doing so vs what's in that doc and see if there is an easy win.
One the examples I point ppl at is my usermanager web app: https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj#L113-L115
I was unable to make a change that allowed me to re-eval my handler and change the reponse message. This is a cljs namespace that is watched by shadow that produces a node library that we then run using node. It's a node-library because that's useful if your creating AWS lambdas. Or at least I haven't been able to look into this notion further. I want to create a node HTTP server that we can use for local development to talk to our browser client. Currently, if i want to change the message body, the only way i know how is to kill running node and then re-eval the code, then boot up node again. I was assuming i was going to have to save the server in an atom and call some kind of stop, then reload the code, then start it again. Which is similar in nature to what i see that ring lib was doing.
(ns server.corev2
(:require [taoensso.timbre :refer [info]]
[macchiato.server :as http]
[reitit.ring :as ring]
[reitit.coercion.spec :as c]
[reitit.swagger :as swagger]
[macchiato.middleware.params :as params]
[reitit.ring.coercion :as rrc]
[macchiato.middleware.restful-format :as rf]))
(defn no-auth-routes
[]
[""
["/eql" {:post {:responses {200 {:body {:message string?}}}
:handler (fn [request respond _]
(respond {:status 200
:body {:message (str "Hello there you handsome angel" )}}))}}]])
(defn wrap-body-to-params
[handler]
(fn [request respond raise]
(handler (-> request
(assoc-in [:params :body-params] (:body request))
(assoc :body-params (:body request))) respond raise)))
(defn app
[]
(ring/ring-handler
(ring/router
[(no-auth-routes)]
{:data {:middleware [params/wrap-params
#(rf/wrap-restful-format % {:keywordize? true})
wrap-body-to-params
rrc/coerce-request-middleware
rrc/coerce-response-middleware
]}})
(ring/create-default-handler)))
(defn server []
(info "Hey I am running now!")
(let [host "127.0.0.1"
port 3001]
(http/start
{:handler (app)
:host host
:port port
:on-success #(info "macchiato-test started on" host ":" port)})))
(comment
;; start server
(server)
;; ➜ server git:(server-setup) ✗ curl -X POST localhost:3001/eql
;; {"message" : "Hello there you handsome angel"}%
)
So we have • shadow server • Nprel server • node • emacs If someone can paint me a picture of whats going on here, i would be delighted.
Emacs sends request to nrepl to start server, nrepl then forwards it to shadow server to translate to JS file. Node notices js file changed and does thing aka start server.
So i think if i didn't want to stop my server, i would need to have it 1) have the raw uncomplied cljs code 2) have a port open listening for ast updates
No idea about cljs. I thought Shadow was supposed to auto-reload all changes anyway? (never used it -- when I tried Figwheel Main it seemed to auto-reload cljs files)
But the compilation step in cljs (from cljs to JS) means it's never going to be as smooth as clj -- and earlier you were talking about Ring etc which is clj, not cljs.
Yea, i was hoping that lessons transfered, reitit has a ring middleware for cljs. The solution is likely that shadow needs to run in app mode. This will likely be very relevant https://shadow-cljs.github.io/docs/UsersGuide.html#NodeHotCodeReload I'll spin down this thread myself, just wanted to end it with a link in case someone else found it.
Sorry if off topic for Clojure, but what are our thoughts on a data access layer api? Would it be better to go for a more general CRUD approach, or a more specific approach? For example: update-user
vs change-email
. I’m leaning towards a general approach for my data access layer and leave specifics to the business layer. Thoughts?
Also happy to delete this and move to the appropriate channel, I’m just not sure which one would be more appropriate.
> I’m just not sure which one would be more appropriate. In such cases, #off-topic is a safe bet.
When you say API, do you mean something a part of and consumed by your application, or something you present to others? For the former, I find I get better composability by having functions return queries rather than execute them, and execute them elsewhere. Honeysql’s helpers help a lot with this.
Does anyone have an example of using https://clojure.org/guides/deps_and_cli#prep_libs in this wild? I'm trying to add a java class to my project that will help facilitate better iterop. Its working if I manually put the compiled class file on the classpath, but this option looks like the proper way. Any help would be much appreciated!
(Edit: I have tried adding the java class to a separate project with the :deps/prep-lib
declared in deps.edn
but it does seem to have any effect)
Hey, so prep-lib is designed only for use in dependencies. So in your case if you're compiling a java class, you'd do that as a part of the prep-lib step so that someone depending on your library as a git dep could use it with the compiled java class.
Normally you'll just have your own alias in your deps.edn that will compile the java and put it in the right place
I have a library meant for doing both of these as easily as possible for simple cases with java. https://github.com/IGJoshua/americano
Thanks! I'll check this out for sure
Works like a charm. Really appreciate your reply and work on this project
Glad it can be of some use!
Did you run the prep step in the separate project?
I think I was running it in the dependency. It looks like I'm actually supposed to be running it in the parent.
Getting a FileNotFoundException but I think I should be able to work that one out
Yes, you'll run it in the project that depends on the dep that needs prepping
OK thanks for the help
The first step is having a build alias that compiles the Java class, probably with something like https://clojure.org/guides/tools_build
I'm trying to call a java superclass method in a deftype
call, but it's (naturally) recursing and blowing up the stack:
(deftype ThingOne [x y])
(= (->ThingOne 1 2) (->ThingOne 1 2))
;; =>
;; false <-- expected
(str (->ThingOne 1 2))
;; =>
;; "scratch.records_types_protocols_interfaces.ThingOne@7d195123"
(deftype ThingTwo [x y]
Object
(equals [this o] (or (identical? this o)
(and (.equals x (.x o))
(.equals y (.y o)))))
(hashCode [this] (Objects/hash (into-array Object [(.x this) (.y this)])))
(toString [this] (Objects/toString this)))
(= (->ThingTwo 1 2) (->ThingTwo 1 2))
;; =>
;; true <-- yay!
(hash (->ThingTwo 1 2))
;; =>
;; 994 <-- also works ... so far, so good
;; stack overflow:
(str (->ThingTwo 1 2))
... so I've managed to override .equals
and .hashCode
OK, but I want to call the stock version of Object.toString
in ThingTwo
and clojure keeps calling my implementation. what's the trick I need to employ? I also gave this a shot but it fails: (toString [this] (.toString ^Object this))
, btw ...well, whaddayaknow ... commenting out the toString
method works. I'd tried another test and clojure barked about a missing method or something like that, must have been a poor test. in any event, this works:
(deftype ThingTwo [x y]
Object
(equals [this o] (or (identical? this o)
(and (.equals x (.x o))
(.equals y (.y o)))))
(hashCode [this] (Objects/hash (into-array Object [(.x this) (.y this)])))
#_(toString [this] #_(Objects/toString this)
(. Object (toString this))))
(str (->ThingTwo 1 2))
;; =>
;; "scratch.records_types_protocols_interfaces.ThingTwo@3e2"
point was to not have to create a custom method, but to use the superclass' implementation.
Try with defrecord @mbarillier
well, whaddayaknow ... commenting out the toString
method works. I'd tried another test and clojure barked about a missing method or something like that, must have been a poor test. in any event, this works:
(deftype ThingTwo [x y]
Object
(equals [this o] (or (identical? this o)
(and (.equals x (.x o))
(.equals y (.y o)))))
(hashCode [this] (Objects/hash (into-array Object [(.x this) (.y this)])))
#_(toString [this] #_(Objects/toString this)
(. Object (toString this))))
(str (->ThingTwo 1 2))
;; =>
;; "scratch.records_types_protocols_interfaces.ThingTwo@3e2"
What explains this behavior and how do I proceed if I'd like to use a type's field for its equality identity, regardless of the type it's being compared with?
(deftype bar [value]
Object
(equals [_ other]
(if (= (type other) bar)
(= (.value other) value)
(= value other))))
(= (->bar 1) (->bar 1)) => true
(= (->bar 1) 1) => true
(= 1 (->bar 1)) => false
It's possible that this isn't a smart thing to attempt.
I don't believe you can accomplish this.
from (source =)
([x y] (clojure.lang.Util/equiv x y))
and that will dispatch off of the first argument. And integers know how to compare themselves to others, just like how your type knows how to compare itself to othersstatic public boolean equiv(Object k1, Object k2){
if(k1 == k2)
return true;
if(k1 != null)
{
if(k1 instanceof Number && k2 instanceof Number)
return Numbers.equal((Number)k1, (Number)k2);
else if(k1 instanceof IPersistentCollection || k2 instanceof IPersistentCollection)
return pcequiv(k1,k2);
return k1.equals(k2);
}
return false;
}