This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-20
Channels
- # announcements (16)
- # babashka (71)
- # beginners (121)
- # bristol-clojurians (2)
- # calva (55)
- # clj-kondo (16)
- # clojure (103)
- # clojure-europe (9)
- # clojure-italy (5)
- # clojure-nl (4)
- # clojure-spec (49)
- # clojure-uk (57)
- # clojurescript (28)
- # conjure (9)
- # cursive (6)
- # datascript (3)
- # datomic (35)
- # duct (20)
- # events (3)
- # figwheel-main (12)
- # fulcro (6)
- # graalvm (12)
- # juxt (3)
- # kaocha (5)
- # lumo (10)
- # malli (5)
- # off-topic (54)
- # pathom (8)
- # re-frame (19)
- # reitit (21)
- # remote-jobs (1)
- # shadow-cljs (102)
- # sql (38)
- # tools-deps (60)
- # uncomplicate (3)
- # xtdb (10)
If some-ns/some-method
is a method of some protocol, how can I get its name ("some-method") from the some-ns/some-method
var, from a different ns?
@clojurians-slack100 If you're on a recent version of Clojure: (name (symbol #'some-ns/some-method))
I would consider it a more "sane" approach than going through the metadata.
In Clojure 1.10 (or maybe since?), they made the whole name
/`namespace`/`symbol` call space a lot more normalized... let me go find the commit...
![thanks3](https://emoji.slack-edge.com/T03RZGPFR/thanks3/868be8344387d7f0.gif)
https://github.com/clojure/clojure/commit/d29219f78e51da66daf1c66108ebebb97c68442f
So, yeah, 1.10.
hi, i’m back again - i’m using compojure-api
, and i’d love to be able to use a plumatic schema to define my query params. it looks like all i can do is
:query-params [{q :- String ""}
{offset :- Long 0}
{limit :- Long 10}]
and explicitly specify each query param. Is that true? Is there an easy way to use a schema here to coerce my query params (and work with swagger ui)?
Every combination of :query
or :query-params
that is not this exact type of incantation gives me errors in the eg GET
macro. Fuller example of what i’m doing is something like…
(GET "/search" []
:return SearchReponseScheam
:query-params [{q :- String ""}
{offset :- Long 0}
{limit :- Long 10}]
search-handler-fn)
Thanks in advance for any help. It seems like just defining the routes and parameters has been the hardest part of building a clojure rest api so far 🙂Since you have the same code (that apparently works?) in both code fragments, can you share what you tried that didn't work?
Or am I misunderstanding what you're saying / trying to do?
:query SearchParamSchema
Exception in thread "main" Unexpected error macroexpanding GET at (the/routes/file.clj)
…snip…
Caused by: java.lang.UnsupportedOperationException: nth not supported on this type: Symbol
:query [SearchParamSchema]
Exception in thread "main" Unexpected error macroexpanding GET at (the/routes/file.clj)
…snip…
Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec.
:query-params SearchParamSchema
Exception in thread "main" Unexpected error macroexpanding GET at (the/routes/file.clj)
…snip…
Caused by: java.lang.UnsupportedOperationException: count not supported on this type: Symbol
:query-params [SearchParamSchema]
This let the server start, but the single param (in swagger) was SearchParamSchema
as a string. Maybe I could unpack the schema somehow here?
https://github.com/plumatic/plumbing/tree/master/src/plumbing/fnk#fnk-syntax
This link to syntax seems to come up, but I’m not exactly sure how that applies to what I’m trying.hi, not sure how to understand ^String (with that hat) in this form (String. (.decode (Base64/getDecoder) ^String to-decode))
? thanks
That is a type hint. It indicates that to-decode should be a JVM object of type java.lang.String. The Clojure compiler can use that to decide which String constructor to call, if there are multiple methods with the same number of arguments, but different types, in that parameter position.
I think I'm missing something basic. is there a reason "dot methods" (i.e. java-interop methods, not sure what you call them) cannot be passed around? Namely, I ran some code like this. The items in coll
have a .text
method :
(map .text coll) ;; Unable to resolve symbol...
(map #(.text %) coll) ;; Works!
https://clojure.org/reference/java_interop See member access
Ah, thank you! I been looking at a much less in-depth page which I thought was the source of truth https://clojure.org/guides/learn/functions#_java_interop
to be pedantic about terminology: methods cannot be passed around period, they are properties of objects clojure functions are objects with an invoke method
some languages use method / function loosely or informally, in clojure it's a true difference
if java had usable first class methods I suspect clojure wouldn't have needed to be invented
Thanks @U051SS2EU the clarification is helpful. I'm coming from JS where there isn't a real method/fn distinction
right - it's inverse! there's no true methods in js, just functions owned by objects, this was intentionally borrowed from how lisps do it
then there's machine code, where there's no objects or functions, just bytes
oh didn't know that's where that part of jS got it's roots. I'm definitely feeling rather at home in CLJ with functions everywhere, except that is until I start talking to java
yeah, hopefully the history helps make it more meaningful
https://github.com/jacobobryant/biff/blob/master/example/src/example/core.clj#L17 what is going on with the #:example.biff.auth
syntax?
@ozzloy_clojurians_net Namespaced keys in a map.
It's a shorthand for {example.biff.auth/send-email send-email example.biff.auth/on-signup "/signin/sent" ...}
Is "brew install" the only way of installing Clojure on MacOS? Wondering if there is any alternative way that does not involve using homebrew. Thanks.
If you are using the Clojure CLI tools from http://clojure.org, then I do not know any way to install those without first installing homebrew.
You can certainly use Clojure without the Clojure CLI tools, e.g. some people use Leiningen for Clojure development, and that can be installed without installing homebrew.
Technically you can go very bare-bones and use Clojure by copying Java JAR files around by yourself, but I don't know anyone who wants to do that.
Thanks Andy for your help. Have been using Clojure in a Linux virtual machine since I would rather not have brew change permission for /usr/local. However, virtual machine does run a little sluggish, so I am hoping to switch back to MacOS for the long run. The risk is minimal and probably a non-issue for most programmers, but it would be excellent if there is a way to install Clojure CLI tools on MacOS without using brew.
What risk are you referring to? I thought that Homebrew was designed to use super user privs only at initial install, and then not need them for later changes to brew packages
Have you tried using the Unix script on MacOSX, it's just an installer that puts files in the right places I believe. Would be surprised if it didn't work on Mac
Or you can just copy what that Unix script does
@U0CMVHBL2 Read about this quite some time ago from a website. The website seems to be gone. Found a web archive link. Check this out (with a pinch of salt though as it's quite hypothetical): https://web.archive.org/web/20190925064628/https://applehelpwriter.com/2018/03/21/how-homebrew-invites-users-to-get-pwned/
@U05254DQM Good idea. I'll give it a try. Thanks for helping!
@UVDMR4Y75 I would be very interested in knowing how you get on. I’d like to add that approach to my install info if it works. Thank you. https://practicalli.github.io/clojure/clojure-tools/install/install-clojure.html#clojure-cli-tools
@U05254DQM It'd be my pleasure. Still have not figured out a way yet. Using Unix script should work, but would come full circle because MacOS does not come with the APT command and requires Homebrew or MacPorts etc to install it. MacPorts looks nice, but for the time being, I'll just stick with my Linux machine. By the way, your website is awesome and an incredible source of Clojure knowledge for the community. Thanks a lot for your contributions!
I'm trying to parse a http response that is separated by a multipart-boundary; essentially i want to get the first part and discard the rest. I thought an elegant approach would be this: get the response body as a reader, read it lazlily into a byte sequence, split that whenever I see the boundary, and take the first result of that split. I wrote this to treat an InputStreamReader
as a lazy sequence but it seems to try and read the entire reader eagerly. Why?
(defn input->byte-seq [input]
(lazy-seq (cons (.read input) (input->byte-seq input))))
if this isn't a learning exercise, there's a ring middleware for multipart
@arne-clojurians in what context is the reader eagerly being consumed? your repl? application code?
You had a good instinct here! I tried to debug it in Cider with a #dbg
statement and the step debugger tried to realize the whole sequence (i think).
this behavior looks correct:
org.noisesmith.hammurabi.hold-my-beer-test=> (def sr (java.io.StringReader. "abcde"))
#'org.noisesmith.hammurabi.hold-my-beer-test/sr
org.noisesmith.hammurabi.hold-my-beer-test=> (def ibs (input->byte-seq sr))
#'org.noisesmith.hammurabi.hold-my-beer-test/ibs
org.noisesmith.hammurabi.hold-my-beer-test=> (.read sr)
97
org.noisesmith.hammurabi.hold-my-beer-test=> (char *1)
\a
org.noisesmith.hammurabi.hold-my-beer-test=> (first ibs)
98
org.noisesmith.hammurabi.hold-my-beer-test=> (char *1)
\b
if you just call input->byte-seq in a repl, without wrapping it to avoid printing, the print behavior will force the byte seq, even though only an opaque identity is printed
also btw your input->byte-seq needs a test for end of stream, it's sitting here producing a massive lazy seq right now and I am waiting for it to crash with an OOM
org.noisesmith.hammurabi.hold-my-beer-test=> (def sr (java.io.StringReader. "abcde"))
#'org.noisesmith.hammurabi.hold-my-beer-test/sr
org.noisesmith.hammurabi.hold-my-beer-test=> (input->byte-seq sr)
it can't print the object identity for the lazy-seq without reading the entire seq (this relates to hash identity and the print form using that identity iirc, and the hash requires full realization)
I am getting these warnings
113 | (kp/let [element (.$ page "#asset-type-select-options")]
--------------------------------^-----------------------------------------------
Cannot infer target type in expression (. page $ "#asset-type-select-options")
I saw this https://clojurescript.org/guides/externs#externs-inference but I don't see how it would help here. I am not even sure what 'target' means in that sentence. I am also not sure how I could explain to it the type since I don't know it myself, page is coming from puppeteer and the whole thing is promise based.Probably better to ask in #clojurescript . But you could try this: (.$ ^js page "#asset-type-select-options")
https://shadow-cljs.github.io/docs/UsersGuide.html#_simplified_externs so weird because I read this a couple of times and it didn't register at all, I thought it was about something else
How do I use global variables in Clojure? I want to update the global variable in one function and read the updated value in another. I am also familiar with Elm and passing model around to achieve the same. But I can't figure out how to do it in Clojure. Googling gives me lots of nonsese that does not make sense.
often (not always) the answer is don't use global variables. but there are several ways to use atoms and functions to achieve the result you want. Can you go into what your use case is? Many times global state falls away. But a straight forward way to do this is (def foo (atom 1))
and anyone can call (reset! foo 2)
and get the value with @foo
.
yeah, atoms are what you want
atoms are many times what you want. especially when new to the language it is easy to try to mimic other languages and use mutable containers where they are not needed.
@dpsutton I worked straight away! But why when I google for this thing there is no example to be found?
an example, in other languages to sum numbers in a list you might do something like
(def total (atom 0))
(doseq [x [1 2 3]]
(swap! total + x))
but this is extremely far from what it would look like in ClojureThat's because "global variable" means something different in Clojure to other languages @ruby.object
You'll find that trying to write Clojure in an imperative style with "variables" will be hard and will also not be idiomatic.
as someone working on a highly imperative codebase written in clojure, don't do it, it's hell
@seancorfield I see your point
I think you'd do better in your Clojure journey by just abandoning that thinking and pretending you're learning programming from scratch.
1 step backward, 900 steps forward
@seancorfield my current attmpts were very frustrating, so I have nothing to lose
I remember my first functional programming language being very hard to learn as well (It was Elm). Please be kind to yourself, and give it some time.
You may find this free book helpful https://practicalli.github.io/clojure-webapps/ There is still lots to add, but should have some useful info for you
Not sure if it applies to your case, but using - let - might be already a better solution if your functions are invoked sequentially
if you discuss what you're trying to do perhaps we can talk about different approaches and how to think about it. its possible atoms are what you need, its possible they are bad for this use case. But would love to know what you're doing if you want to share
(ns server.start
(:require [ring.adapter.jetty :refer [run-jetty]]))
(def x (atom "1"))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body (str "Hello World " @x)})
(defn -main [& args]
(println (str "task for starting server on port 3000 with args" args))
(reset! x (str args))
(run-jetty handler {:port 3000 :join? false}))
FYI, you can use triple backticks around blocks of code to make it easier to read:
(ns server.start
(:require [ring.adapter.jetty :refer [run-jetty]]))
(def x (atom "1"))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body (str "Hello World " @x)})
(defn -main [& args]
(println (str "task for starting server on port 3000 with args" args))
(reset! x (str args))
(run-jetty handler {:port 3000 :join? false}))
(you may need to change a Slack preference so enter inside code blocks adds a newline instead of sending the message -- I can't remember what the default is these days)
Nope but you can simply pass the args down as second argument of handler :) the other guys are much more experienced so they’ll tell you better
As a data point, at work we have over 100,000 lines of Clojure code and we only have 85 atoms (and no refs).
even that seems high :)
Agreed. I'm sure we can get rid of a lot of those.
@ruby.object the typical Clojure approach is to use middleware or a closure to get parameters into a function like that:
(defn make-handler [args]
(fn [request]
{:status 200 :body (str "Hello World " args)}))
(defn -main [& args]
(run-jetty (make-handler args) {:port 3000 :join? false}))
Hello everyone! How do i stop myself from structuring my apps as if i had actors? I've use erlang/elixir and got very used to genservers and dynamic supervisors, so i would greatly appreciate any tips or links to books or videos.
what's wrong with actors?
the jvm doesn't give you all the benefits of using actors as the erlang vm, but many of the same principles can still be reused
what kinds of projects are interested in?
@U7RJTCH6J for example i've dabbled with core.async and dynamically created components that subscribe to a chan and do the work and send it downstream. About projects, for example i did data ingestion pipeline with elixir that was broadcasting partitioned data to users based on their subscriptions. Basically i like soft/hard realtime projects involving data processing
those sound like projects that fit well with actor based designs. although core.async isn't technically an actor based system, it should feel familiar. I guess the big difference with clojure is that you have the option of using shared state with things like atom
and more ,but it's totally acceptable to connect separate processes/threads together via queues
book recommendations comes up frequently. it would probably great to have a pinned post for something like that. here's a more comprehensive list: https://clojure.org/community/books
@U7RJTCH6J so im just dealing with projects that are better suited for actor model? I've read programming clojure 3rd edition, elements of clojure and hands on reactive programming with clojure,but i still feel like i dont know anything and got by just fine just because i got lucky with otp.
i wouldn't necessarily say the actor model specifically. I was thinking about CSP style designs (of which the actor model is one). the main caveat being that with actors, the processes and their mailboxes are combined whereas with CSP, you also have the option of having queues available separately from the process
there's a #code-reviews channel. it might be helpful to post some code and see what others think
if you haven't checked out all of the Rich Hickey talks, I would definitely recommend those, https://changelog.com/posts/rich-hickeys-greatest-hits. on this topic, I would specifically recommend "the language of the system" and "the value of values".
@U7RJTCH6J thanks!
in fact, the core async talk might be the best talk to get started with on this topic
generally, connecting isolated processes via queues is great. I recommend the joe armstrong erlang paper to clojure programmers all the time, http://erlang.org/download/armstrong_thesis_2003.pdf
This seems super simple but I can't find it documented anywhere. How do I use lumo to build a reagent application? All of the examples for reagent use a project.clj instead of build.cljs and I don't understand the mapping from one to the other
anyone familiar with scope capture? i'm trying to programmatically sift through hundreds of ep-id
s. my first attempt is (doseq [ep-id (range 70 300)] (sc.api/defsc [ep-id -8]))
, which throws ep-id should be either a positive number or a [(positive-number) (negative-number)] tuple, got: [ep-id -8]
. anyone know what i might be missing, here?
part of the answer is that sc.api/defsc
is a macro, but that's as far as i get.