This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-04
Channels
- # announcements (3)
- # babashka (14)
- # beginners (151)
- # calva (14)
- # cider (9)
- # clj-kondo (24)
- # cljdoc (12)
- # cljs-dev (195)
- # cljsjs (3)
- # cljsrn (13)
- # clojars (12)
- # clojure (234)
- # clojure-dev (3)
- # clojure-europe (9)
- # clojure-greece (1)
- # clojure-italy (2)
- # clojure-japan (4)
- # clojure-nl (4)
- # clojure-spec (89)
- # clojure-taiwan (1)
- # clojure-uk (16)
- # clojuredesign-podcast (2)
- # clojurescript (17)
- # conjure (11)
- # core-async (4)
- # core-typed (31)
- # cursive (9)
- # datomic (8)
- # emacs (17)
- # figwheel (1)
- # fulcro (5)
- # ghostwheel (42)
- # graphql (3)
- # hugsql (5)
- # jackdaw (3)
- # jobs-discuss (93)
- # joker (4)
- # meander (6)
- # mount (1)
- # off-topic (23)
- # pathom (10)
- # re-frame (23)
- # reitit (7)
- # remote-jobs (18)
- # shadow-cljs (153)
- # spacemacs (24)
- # sql (30)
- # tools-deps (14)
- # vim (12)
- # xtdb (1)
hopefully beginners is the right place to ask this. i am seeking a resource explaining how to package up some .cljs source to be distributed as a jar that can be included in :dependencies
- does anybody know of a good tutorial?
Reading back this and other channels in this slack space, I must say a big thank you for all the great help people are getting, even asking quite basic questions (me being one of basic question-askers). A very nice and professional community. I don't take that for granted, so thanks again to those who help out getting newcomers started :thumbsup:
Hey, I have some difficulties understanding spec. I would like to model some data that can either be a scalar type like string or a number or a vector containing the scalar types defined before. For the scalar type I started with (s/def ::answer-scalar (s/or string? int?))
but s/or
requires key predicate pairs as input. Any pointers and or material to study are really appreciated 😊
in order for conform to work you have to give some details of what to call each branch, so I think (s/def ::answer-scalar (s/or :string string? :integer int?))
will work for you
no problem! I usually scan through https://clojure.org/guides/spec#_composing_predicates for examples which might help
@UP2FUP0TT I have just started a video series on Clojure spec, just covering the basics but building up to more. https://www.youtube.com/playlist?list=PLpr9V-R8ZxiBWGAuncfBRYhZtY5-Bp75s Also starting a chapter on spec in the book https://practicalli.github.io/clojure/clojure-spec/
Does anything already exist to do the following, basically doing update but ignoring ops on non-existant keys
(defn update-existing
[m k f & args]
(if (contains? m k)
(apply update m k f args)
m))
what if I told you this exact same function is so common it has been included in a very popular utility library called medley? https://github.com/weavejester/medley/blob/master/src/medley/core.cljc#L48
ahh, nothing I'm missing from core then, thanks for the link looks useful!
There’s also Void, which is more tightly focused on that sort of thing: https://github.com/dvlopt/void.cljc
Does anyone have a good resource about how to program with abstract data types in Clojure?
why do you recommend this? is it a good reference? I actually have that book on my shelf, but I abandoned after chapter 3.
what do you mean by abstract data types? what problem are you actually trying to solve?
The problem I have in general with clojure, although without question I see clojure as very flexible and powerful, is how to create opaque objects, which know what they are. Sure I can create a list or a map, but clojure doesn't know anything about the semantics of two different maps. My program is responsible for managing that itself. My program can do that in many ways, such as using spec and considering an X is something which looks like an X. But there's no way for an object to be an X because it was constructed by the create-X function.
Another common feature of ADTs, (in Scala and Common Lisp) is some sort of print-object, toString function which tells the printer how I want the object printed.
so you want your own type
I hesitate to use the work "type" because it comes with baggage, and to me a "type" is any set of objects.
well I really mean Java's concept of type
perhaps class would be more specific
I don't mean to be evasive. sorry if it seems this way. I will read the recommended section about about records and protocols.
if you want effectively a map with a specific class, you can use defrecord for that. If you want more of a custom object, you can use deftype and implement the Clojure collection interfaces
As I understand java uses something called polymorphic nominal typing. I don't really understand that is. I have a vague idea, but not a real understanding.
In Clojure Applied, chapter 1-2 I cover both of these
What is Clojure Applied, is that a book or a website? or both?
paper or ebook?
cool.
I'll add it to my amazon wish list
I think you may have to use another site to get the physical book now
https://www.amazon.com/Clojure-Applied-Practitioner-Ben-Vandgrift/dp/1680500740/ref=sr_1_1?dchild=1&keywords=clojure+applied&qid=1591282102&sr=8-1ut it's on amazon etc
seems it's in the amazon catalog. not sure if it will let me order it though.
how does chapters 1 and 2 of your book compare with the brave and true book? https://www.braveclojure.com/multimethods-records-protocols/
I don't know how to answer that usefully
historically Common Lisp has defstruct and also defclass. I think a class can do everything that a struct can do, but structs are generally seen as light weight.
i suspect that most implementations treat them the same under the hood at the compiler level.
Clojure also has a defstruct but it's generally seen as deprecated in favor of records
https://clojure.org/reference/datatypes is probably the definitive reference page about this stuff
I recently say a video from Rich Hickey talking about the closure script compiler. He said the first thing the clojure code for the clojure script compiler was that it defines a bunch of protocols.
to me that says, he doesn't use maps for everything, but he defines some sort of abstract notions which make the compiler easier to programm.
just my guess, I haven't dared to look at the code.
protocols were (at least partially) added to provide a high-performance path to the kind of polymorphism that is heavily optimized by the JVM
they are inherently more limited than multimethods (can only dispatch on the class of the first argument) but because the JVM is super optimized for this case, they are also very fast
do records or deftypes let me define something like a toString method which the system will call to get the printed representation of the object?
That's not clear from the page https://clojure.org/reference/datatypes
you can install multimethods for print-method / print-dup in the printing system to do that, yes
the printing system keys off of class
you can also implement .toString in a defrecord/deftype (that's used in some specific cases)
I see the documentation for print-method, but it seems the doc of print-dup is missing, just some examples. https://clojuredocs.org/clojure.core/print-dup
yeah, this is under-documented for sure
oh i guess print-method is also missing documentation
could you help me understand what this example means?
(defmethod print-method XYZ [v ^java.io.Writer w]
(.write w "<<-XYZ->>"))
v
doesn't seem to be used.
perhaps w
is the stream to print to?
w is the writer, v is the value (your record/type object)
i guess v
is the object to be printed?
and what is the circumflex?
^
is a circumflex
oh, type hint
does that [ae]ffect the semantics in any way?
no, used in the compiler to avoid emitting reflective calls
I don't understand the difference between affect and effect, and I've never been able to understand for the past 54 years.
Does it promise the compile that this variable will only every be bound to something of the specified type?
it will fallback to making a reflective call otherwise
The compiler, I believe only for the purpose of deciding which among several possible Java methods to call (if there are several available), will assume it is of that class.
"otherwise" here meaning "if you do not provide a type hint in the source code"?
what is the consequence of me giving the wrong ^hint in my code? will I crash the JVM ?
no, otherwise meaning "if you actually pass it something else"
no bad consequence, just fall back to reflective call
(with some caveats around the specific primitives ^long and ^double which can actually have some negative consequences if used incorrectly)
what does dup
mean in print-dup
... I though first that it was away to handle printing duplicates, by referring back to a previous one printed...
no, it really I think refers to being able to duplicate an object as code (I'm not actually sure!)
print-dup is expected to print something readable by the Clojure reader
print-method is more for human consumption
in most cases for what you're talking about here, you will want them to do the same thing
ahh, so I can make my class readable, that's cool.
for a defrecord, you often want to emit a call to the record constructor
well, for both
in CL this feature is usually used to make the reader signal an error if it tries to read a particular printed representation.
unless you are also defining a custom reader tag like #foo and in that case you'd want to emit the reader tag representation
e.g., you can't serialize a data-base-connection etc.
yes, you could have it intentionally print something not readable I suppose
this is really interesting. another application of reader encoding is for floating point numbers. There is an internal binary representation for EVERY floating point number currently in the VM. however, when you print it in base 10 and re-read it you might not get a number which is equal. In one proprietary lisp that I used in the past, it was possible to print a float in a way which more or less marshalled the C++ bit representation. So we could know that serializing and deserializing maintained equality.
you could ensure such things if you used a custom reader tag #my/float "0101010101010..."
I think you'd want to be very delicate in the scope with which you modified the printer for that though :)
Does clojure have a reader representation that causes the reader to call a specified function? E.g., in common lisp if #.(foo bar) is encountered, then the reader returns the value returned by calling (foo bar)
... this is obviously a securty issue so there's a way to turn it off, but most people forget to do so.
there is an undocumented #=
read-time eval
generally I would recommend you not use it :)
you can also use #foo.Bar to invoke the constructor of a Java class, again I would say generally to avoid that
it's preferred to define a custom reader tag and provide a tag to reader function mapping
those reader tag mappings can be provided in a static file, or dynamically via binding, or by passing explicitly to a read
call
Yes I read that section 5 minutes ago, but I didn't really understand it very well. Anyway, not something I'm planning on using today. but really interesting to know about this feature.
https://clojure.org/reference/reader#tagged_literals says the #something is followed by a [bracked array], whereas the github documentation says it's followed by a {braced map}
re read-time eval, it's not allowed in the edn reader and can be controlled more via *read-eval*
, see https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*read-eval*
tagged literals actually take data, so can be either
the common lisp variable *read-eval*
has the same purpose.
so #foo [1 2 3]
or #foo {:a 1 :b 2}
or even #foo 5
in any case, it's one value
hmmm. seems #=
is indeed documented. in https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*read-eval*
it's not a public feature in https://clojure.org/reference/reader
ie, we make no guarantees about its future existence :)
This is a cool feature. I follow the Scala developers list, and there is a big problem of how people can write code which loads, compiles, and works in Scala 2.12, 2.13 and 3.x. Reader conditions are an excellent solution to this problem, in my opinion. But I don't see how it could work in Scala, as there's no concept of s-expression.
is https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*read-eval* not the public API? Perhaps someone needs to remove #= from that document, because it seems to me to be part of the public API.
we're happy with it as is
As you like, but it seems to be part of the public API. that's great for CL-like users.
Hi there. Lein run fails with the following "Caused by: java.lang.RuntimeException: could not find a non empty configuration file to load. looked in the classpath (as a "resource") and on a file system via "conf" system property" Any guidance for this Java noob on where to start looking (or educating myself to understand such incantations) would be appreciated.
it's a Luminus app if that's any help. I'm guessing the issue is my lack of comprehension of Java though (which is nearly always the blocker for me with Clojure)
It sounds like it's looking for #'guestbook.config/env but can't find it due to some other Java thing
I can see that #'guestbook.config/env is a state that mount is trying to load, but as it doesn't depend on other namespaces being loaded, I'm puzzled about why it fails.
Hmm, well. Still dunno what the issue was, but I tried again after upgrading to OpenJDK 11 (for entirely separate reasons) and it started working.
I eventually figured it out though. Somehow (maybe a github replication mishap given it's in the .gitignore) - I was missing the dev-config.edn file created by the Luminus template.
As a result, when cprop tried to get the environment variable for the db from that file, it couldn't find it
I had this issue when I started and it drove me crazy. I am glad you figured it out.
what does "AOT compiled" mean?
you do the compilation ahead of time (into Java .class files), rather than at load time (from .clj files)
Ahead Of Time, as opposed to Just In Time... ah ok.
Let’s say I have a polymorphic function f
that dispatches on its first argument, x
: (f x …)
. In addition to x
, f
can accept additional arguments a
, b
, c
, but depending on which x
is provided different combinations of a
, b
, and c
are valid. For instance, for some types of x
f
requires a
, b
, and c
, but for others only a
and b
are required. What would folks say is the right way to implement f
in Clojure?
My instinct tells me to break up f
into different functions based on which sets of arguments are required vs optional vs disallowed, but I wanted to double-check.
I think this implements it exactly:
(defmulti f (fn [x & args] (type x)))
(defmethod f t [x a b] ....)
(defemthod f t2 [x a b c] ...)
(defmethod f t3 [x c] ...)
if the args are mismatched to the type dispatch, the error will point to the specific impl that failed
of course, you might want some way of picking dispatch other than type
, that's the common case though, so that's what I pick as an example
That’s useful @U051SS2EU. Thanks!
I suppose my question is more about whether one should do such a thing, or whether it would be better to break up the function in question. It feels wrong for the set of required arguments to differ based on the type of the first argument, and I’ve struggled to find other examples of similar functions that do this in the wild. But perhaps this is is less of a red flag than I’m imagining?
clojure code usually worries less about the type signatures, and more about the composable operations provided - you can absolutely use spec to check the args separately in each defmethod
we have a lot of prior art for functions that return different types for different arg lists - see for example (map f)
vs. (map f coll)
they are related, it makes sense to call map
a single function, but their return values in those cases are very different
That’s an example of where the return type differs based on which arguments are used, not an example of where the full set of required arguments differs based on the type of the first argument, no?
Hi guys, got the following code:
(ns maisicuel.core
(:require [maisicuel.config :as cfg])
(:gen-class))
(defn write-files [path results]
(for [app-results results
:let [today (.format (java.text.SimpleDateFormat. "yyyy-MM-dd") (new java.util.Date))
app (name (key app-results))
figures (val app-results)
line (clojure.string/join "," (vals figures))]]
(spit (str path app ".csv") (str today "," line "\n") :append true)))
(let [output-path "/Users/hlodowig/Docs/usage/"]
(write-files output-path cfg/results))
I'm getting
Execution error (IllegalStateException) at maisicuel.core/eval1528 (form-init2559437174217991231.clj:2).
Attempting to call unbound fn: #'maisicuel.core/write-files
If I take the code outside of the defn
it works just fine. I've done some googling but I'm lost. It fails in REPL and uberjar. Would appreciate your help.what do your project dependencies look like?
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/java.jdbc "0.7.11"]
[mysql/mysql-connector-java "5.1.6"]]
is write-files
used anywhere else in your project?
and what happens if you wrap the bottom write-files call in a -main
function:
(defn -main [& args]
(let [output-path "/Users/hlodowig/Docs/usage/"]
(write-files output-path cfg/results)))
the unbound fn
error happens if you try to call write-files
before it is defined
in a language like java, it doesn’t matter if the source code for write-files
is before or after it’s called, but in clojure, it’s as if each top level expression is evaluated in order from the top of the file to the bottom of the file
I suppose my question is more about whether one should do such a thing, or whether it would be better to break up the function in question. It feels wrong for the set of required arguments to differ based on the type of the first argument, and I’ve struggled to find other examples of similar functions that do this in the wild. But perhaps this is is less of a red flag than I’m imagining?