This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-31
Channels
- # aleph (8)
- # announcements (11)
- # aws (1)
- # babashka (7)
- # beginners (104)
- # calva (52)
- # clara (1)
- # clj-kondo (28)
- # cljdoc (8)
- # cljsrn (2)
- # clojure (20)
- # clojure-europe (8)
- # clojure-uk (1)
- # clojurescript (26)
- # core-typed (3)
- # datomic (6)
- # holy-lambda (1)
- # jobs (1)
- # jobs-discuss (14)
- # malli (7)
- # pathom (31)
- # polylith (19)
- # re-frame (8)
- # reitit (1)
- # releases (1)
- # shadow-cljs (5)
- # tools-build (92)
Setup a Socket repl for your app listening on localhost, ssh into the prod machine, then nc localhost <port>
Startup time has a strong dependency on the program itself. It might be normal if it require some preparations like connecting to external systems and collecting some information.
I'm just trying to launch a repl. Even using integrant and assuming it's connecting to a local postgres and kafka before it lets me type in the repl, this seems like a strange amount of time
Are you using leinigen? Do you have a large class path? What JVM opts did you start with?
Using leinigen through intelliJ, JVM opts are
"-Dclojure.spec.check-asserts=true"
Have 50 dependencies in profile.clj, not sure if that is considered a lotis there a way to enumerate all namespaces for my project?
in other words, can I make (ns-all)
work only for :paths, not for :deps?
I imagine you could probably filter the output of (all-ns)
with str/starts-with?
(once you get the names) or something like that, but I think that by the point you're calling (all-ns)
, Clojure is basically only aware of 'the classpath' as a thing, with no distinction between what was contributed to 'the classpath' via :paths
vs :deps
- I could totally be wrong, though
Hi everyone, I am new to clojure and was trying out next-jdbc
(jdbc/execute-one! ds ["
insert into address(name,email)
values('Someone Else','')
"])
returns
#:next.jdbc{:update-count 1}
I was wondering how to get just the map of {:update-count 1}
out of this.
Also {:builder-fn rs/as-unqualified-lower-maps}
works for select
query but not insert
.(= #:next.jdbc{:update-count 1} {:next.jdbc/update-count 1})
is true. That prefix on the map is just a shorthand for indicating all of the keys in the map have that namespace.
And you can turn it off if you like:
(set! *print-namespace-maps* false)
false
user=> #:next.jdbc{:update-count 1}
{:next.jdbc/update-count 1}
Thanks @dpsutton that did work.
(= #:next.jdbc{:update-count 1} {:next.jdbc/update-count 1})
That does explain whats happening here. Never saw namespace-maps
while studying any of the clojure books and got confused.
If you want, you could an also destructure it, i.e., (let [{:next.jdbc/keys [update-count]} (jdbc/execute-one! ds .......)] (println "number of rows updated " update-count))
I have a Clojure API design question. I have a function foo
that takes an integer n
and returns a map. It is incorrect to call this function with n < N
. So, my question is what is the idiomatic way to handle when someone calls foo
with n < N
? Raise an exception? Return nil
? Try to catch n < N
beforehand so that foo
doesn't have to worry about it?
There are several ways of solving that. You could use a :pre
condition (https://clojure.org/reference/special_forms#toc10), or an fdef
(https://clojuredocs.org/clojure.spec.alpha/fdef) or hand-code an assertion check of your own if you want to have more control over the behavior of the fn when called with semantically incorrect input.
I'm not sure what is considered idiomatic, but my experience is that Clojure generally considers the response to invalid input to be "undefined" (meaning, "all bets are off"), unless specifically stated. In your specific example and without knowing more about the context, I'd probably just return nil
and mention that behavior in the docstring.
This is always a “your system” type of question. What do you think should happen? Is this bad but innocent data? Failure to validate human input? A broken invariant that absolutely should not be able to happen? Recoverable? Fatal? Amusing?
empty map result
Hello everyone! Are there any good tools that make clojure's stack traces more readable? Do you personally use such tools or is there a reason not to? Other languages seem to do a much better job at telling you what went wrong. I've seen some people say it's something you learn to work with, which I find hard to believe because usually the stack trace is a lot more cryptic than "can't cast one class to another". Sometimes I think that a better error message could have saved me a lot of time. Thanks in advance.
This blog post gives some decent advice, https://8thlight.com/blog/connor-mendenhall/2014/09/12/clojure-stacktraces.html. What IDE are you using? There might be some more specific tools that are available depending on your setup.
@U7RJTCH6J Thank you. I'm using neovim as my IDE.
I'm a weirdo that has never been bothered by the stack traces. I think some mitigations clojure has to make stack traces less troublesome: • easier to build programs in small pieces and then compose the pieces to make larger programs • repl driven development for tighter feedback loops If you haven't tried repl-driven development, I highly recommend it. It accentuates clojure's strengths and minimizes its weaknesses.
Unfortunately, I'm unfamiliar with neovim. I'm not sure what options might be available to help with stack traces.
Yes, I'm using vim-iced for interacting with REPL and it is awesome. Thanks for the advice!
My usual work flow is similar to what's recommended in the blog post. Find the stack trace that points to a line in my current namespace and work from there.
I came across https://github.com/athos/stacktracer recently. Haven’t tried it, but it looks nice
@dpsutton It's not really a problem with any particular stack trace, but rather me not being used to reading clojure stack traces. There was a particularly annoying one today, though. I was going to post it here, but while copying noticed that the reason was stated in plain english 🙂 It was somewhat buried, but I still feel silly. I am reading the article that @U7RJTCH6J suggested and it seems that it really is a question of getting used to it. Thanks for being so ready to help though. I'm glad I've discovered clojurians.
I think that’s the crux of it. It’s easy for your eyes to gloss over at first, but if you take a breath the stack trace will point exactly to the offending code and often has a very useful message
Yep, I guess I'm just more used to reading shorter error messages in other languages. But I'm going to practice then.
If you do find yourself confused after a minute of reading drop it here in a snippet (so it’s collapsing) and ask for help
I’m sure there’s still room for improvement as it’s certainly not just you. I think there has been quite a bit of improvement in clojure core, but I think the tools that surface the stack traces are still integrating the newer/better info that’s now available.
Yes, I've read that the situation has improved since the release. It must not be so easy to implement into the core language.
Unfortunately, I'm unfamiliar with neovim. I'm not sure what options might be available to help with stack traces.
Hey, when building an uber jar with tools.build
the build command clj -T:build uber
also starts the program. Is there a flag or something for just building?
I don't know if this is needed as context
(defn uber [_]
(clean nil)
(b/write-pom {:class-dir class-dir
:lib lib
:version version
:basis basis
:src-dirs ["src"]})
(b/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-dir})
(b/compile-clj {:basis basis
:src-dirs ["src"]
:class-dir class-dir})
(b/uber {:class-dir class-dir
:uber-file uber-file
:basis basis
:manifest {"Main-Class" "lhrb.wdylt.server"}}))
Are there any top level forms that have side effects other than defining constants or functions?
not that Im aware of
(ns build
(:require [clojure.tools.build.api :as b]))
(def lib 'lhrb/wdylt)
(def version (format "1.0.0"))
(def class-dir "target/classes")
(def basis (b/create-basis {:project "deps.edn"}))
(def uber-file (format "target/wdylt.jar"))
(defn clean [_]
(b/delete {:path "target"}))
;; build with clj -T:build uber
(defn uber [_]
(clean nil)
(b/write-pom {:class-dir class-dir
:lib lib
:version version
:basis basis
:src-dirs ["src"]})
(b/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-dir})
(b/compile-clj {:basis basis
:src-dirs ["src"]
:class-dir class-dir})
(b/uber {:class-dir class-dir
:uber-file uber-file
:basis basis
:manifest {"Main-Class" "lhrb.wdylt.server"}}))
:manifest {"Main-Class" "lhrb.wdylt.server"}
I copied this from one of the test cases everything else is from the offical guide
if you comment out all of the forms in your uber
function so it does absolutely nothing, does it still run your program when running clj -T:build uber
?
(b/compile-clj {:basis basis
:src-dirs ["src"]
:class-dir class-dir})
this seems to run the programthat's likely not the problem. Compiling is reading the clojure source files and writing the bytecode to classfiles. You have some top level def that does work rather than can be invoked to do work
what about in the lhrb.wdylt.server namespace or its requires?
if you eval that form you don't have a function that can create a webserver you are running a webserver
or eval the namespace form and each of the other forms you need (which is exactly what load-file does)
usually the important bits are just to have tools.build on the classpath and then you can just eval that file as you like. Note it is not on the classpath normally unless your classpath has .
on it (the root directory in addition to just src/
or whatever
and when I jack-in and try to eval something in the build file i get a filenotfoundException
1. Unhandled java.io.FileNotFoundException
Could not locate clojure/tools/build/api__init.class,
clojure/tools/build/api.clj or clojure/tools/build/api.cljc on classpath.
For these purposes, build
is just another alias that includes an extra dependency tools.build
and specifies to use the build
namespace
:aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.6.2" :git/sha "226fb52"}}
:ns-default build}}}
I have this in my deps filedo you have any resource where I can look up how to include a namespace with cider, when starting a repl?
if you do C-u M-x cider-jack-in
, then it let's you edit the command
Where would I put the build alias?
:aliases {:cider/nrepl {:main-opts ["-m" "nrepl.cmdline" "--middleware" "[refactor-nrepl.middleware/wrap-refactor,cider.nrepl/cider-middleware]"]}}
there should be a whole command there. with the beginning /usr/bin/clojure blah blah
or you can edit the cider-clojure-cli-parameters
emacs variable, but I forget how to do that as a one off
yes it is like this
/usr/bin/clojure -Sdeps '{:deps {nrepl/nrepl {:mvn/version "0.9.0-beta2"} refactor-nrepl/refactor-nrepl {:mvn/version "3.0.0-alpha13"} cider/cider-nrepl {:mvn/version "0.26.0"}} :aliases {:cider/nrepl {:main-opts ["-m" "nrepl.cmdline" "--middleware" "[refactor-nrepl.middleware/wrap-refactor,cider.nrepl/cider-middleware]"]}}}' -M:cider/nrepl
probably wouldn't* be that hard to add a command to your emacs config that starts a build repl
I should probably do that for my setup
Guys thank you so much. I figured it out. It was actually the (def server ...)
form which led to the behavior
Damn I was wrong it still starts the program in background :thinking_face: this is odd isn't it
(defn -main []
(let [server (jetty/run-jetty #'app {:port 3000
:join? false})]
(log/error "damn this gone horrible wrong")
(schema/create-db-structure ds)
(start server)
(.. (Runtime/getRuntime)
(addShutdownHook (proxy [Thread] []
(run []
(log/error "shutdown hook")
(.stop server)
(System/exit 0)))))))
clj -T:build uber
21:59:00.378 [main] DEBUG org.eclipse.jetty.util.log - Logging to Logger[org.eclipse.jetty.util.log] via org.eclipse.jetty.util.log.Slf4jLog
21:59:00.384 [main] INFO org.eclipse.jetty.util.log - Logging initialized @1815ms to org.eclipse.jetty.util.log.Slf4jLog
WARNING: set already refers to: #'clojure.core/set in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/set
WARNING: into already refers to: #'clojure.core/into in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/into
WARNING: group-by already refers to: #'clojure.core/group-by in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/group-by
WARNING: update already refers to: #'clojure.core/update in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/update
WARNING: partition-by already refers to: #'clojure.core/partition-by in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/partition-by
WARNING: for already refers to: #'clojure.core/for in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/for
WARNING: filter already refers to: #'clojure.core/filter in namespace: lhrb.wdylt.server, being replaced by: #'honey.sql.helpers/filter
(ns lhrb.wdylt.server
(:require [ring.adapter.jetty :as jetty]
[ring.middleware.params :as params]
[reitit.ring.middleware.muuntaja :as muuntaja]
[muuntaja.core :as m]
[reitit.ring.coercion :as coercion]
[reitit.ring :as ring]
[hiccup.core :as html]
[clojure.spec.alpha :as s]
[next.jdbc :as jdbc]
[honey.sql :as sql]
[honey.sql.helpers :refer :all]
[lhrb.wdylt.migration :as schema]
[clojure.tools.logging :as log])
(:gen-class))
do you see anything else? those are all warnings from compiling code. and initializing a logger isn't crazy
building is going to load the main namespace and its requires which will evaluate all of the top level forms