This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-09-29
Channels
- # announcements (1)
- # babashka (120)
- # beginners (184)
- # cider (14)
- # clara (2)
- # clj-kondo (25)
- # cljfx (9)
- # cljsrn (43)
- # clojure (46)
- # clojure-australia (2)
- # clojure-berlin (5)
- # clojure-dev (2)
- # clojure-europe (10)
- # clojure-france (3)
- # clojure-nl (1)
- # clojure-spec (14)
- # clojure-uk (30)
- # clojurescript (50)
- # code-reviews (19)
- # conjure (11)
- # core-logic (2)
- # cursive (20)
- # datascript (1)
- # datomic (74)
- # figwheel-main (1)
- # fulcro (10)
- # funcool (2)
- # graphql (1)
- # lambdaisland (1)
- # malli (2)
- # meander (22)
- # nrepl (13)
- # off-topic (28)
- # overtone (3)
- # pathom (7)
- # pedestal (4)
- # re-frame (4)
- # reagent (16)
- # reitit (4)
- # releases (1)
- # ring (8)
- # shadow-cljs (93)
- # specter (6)
- # sql (13)
- # test-check (1)
- # tools-deps (1)
- # tree-sitter (2)
- # vim (8)
- # xtdb (25)
No, it’s something weirder than that:
(prn (first (errors-from (:new (second errors)))))
{:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}}
=> nil
(prn {:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}})
{:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}}
=> nil
(contains? common-errors (first (errors-from (:new (second errors)))))
=> false
(= {:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}} (first (errors-from (:new (second errors)))))
=> false
Arg, one of those keywords is an AST class which prints as the actual keyword:
(->> (tree-seq #(or (sequential? %) (map? %)) identity (first (errors-from (:new (second errors)))))
(mapv #(vector % (class %))))
=>
[[{:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}} clojure.lang.PersistentArrayMap]
[[:unexpected :except] clojure.lang.MapEntry]
[:unexpected clojure.lang.Keyword]
[:except cursive.psi.impl.ClEditorKeyword]
[[:expected #{":only" ":rename" ":exclude" :eof}] clojure.lang.MapEntry]
[:expected clojure.lang.Keyword]
[#{":only" ":rename" ":exclude" :eof} clojure.lang.PersistentHashSet]]
They don’t normally do that but I defined a print-method for them for some testing a while back.
it was tricky printing like I thought!
Are there any tools/libraries that help moving/renaming namespaces in bulk, including references? I found clojure.tools.namespace.move
but I'm wondering if anything better has come along since, since it just does a naive regex replace
I heard that Cursive was great for this sort of thing. I'm not a cursive user myself, but it maybe worth taking a look at how it is handling such refactors.
A little something about protocols: My first question is: is this the correct way to type-hint the return type of a fn in a protocol?:
(defprotocol Foo
(^String foo [this]))
;; foo should be typehinted to return a String
This seems correct to me, but I'm not familiar nor comfortable with type-hints.
Second question. Given a multi-arity protocol function, is this the correct way to type-hint it?
(defprotocol Bar
(^String bar
[this]
[this that]))
Follow up question (which I'm not sure is very sensical, is there a way to have a different return type on these two fns?
Third or fourth question, depending, when I look at the macroexpand of the Foo protocol, there's a lot going on, but I find this bit interesting:
(gen-interface
:name
typehints.protocols.Foo
:methods
([foo [] Object]))
So even though I've type-hinted foo
to return a String
, it seems like the interface method is generated with a return type of Object
?To start answering your first question, that does appear to be the correct way to type hint the return value of foo
; if you check (meta #'foo)
now, you'll notice its meta's tag
is now String
. But as for the interface produced, it shouldn't enforce it, and the return value of foo
should still be Object
(while if you use definterface
, it will enforce it and generate a return type of String
).
I've tested this with clj-java-decompiler
to decompile the code in question; namely, (defprotocol Foo (foo [this] [this that])))
and (defprotocol Foo (^String foo [this] [this that]))
appear to produce an identical decompilation (well, I didn't exactly diff it but both at least produce
public interface Foo
{
Object foo();
Object foo(final Object p0);
}
Likewise, I've read something similar here, along with a motivation
> Protocol
s are for consumption of Clojure functions, which aren't supposed to be statically typed; interfaces are for consumption by Java classes, which are [in fact] required to be statically typed;
https://groups.google.com/g/clojure/c/JxYHE4eqDv4 )To start answering your first question, that does appear to be the correct way to type hint the return value of foo
; if you check (meta #'foo)
now, you'll notice its meta's tag
is now String
. But as for the interface produced, it shouldn't enforce it, and the return value of foo
should still be Object
(while if you use definterface
, it will enforce it and generate a return type of String
).
I've tested this with clj-java-decompiler
to decompile the code in question; namely, (defprotocol Foo (foo [this] [this that])))
and (defprotocol Foo (^String foo [this] [this that]))
appear to produce an identical decompilation (well, I didn't exactly diff it but both at least produce
public interface Foo
{
Object foo();
Object foo(final Object p0);
}
Likewise, I've read something similar here, along with a motivation
> Protocol
s are for consumption of Clojure functions, which aren't supposed to be statically typed; interfaces are for consumption by Java classes, which are [in fact] required to be statically typed;
https://groups.google.com/g/clojure/c/JxYHE4eqDv4 )Hey folks, how can I use interleave
such that lists of different lengths zip with nil? e.g. (partition 2 (interleave [1 2 3] [4 5]))
=> ((1 4) (2 5) (3 nil))
I wrote my one version of interleave)
(defn exhaustive-interleave
"Same as clojure.core/interleave but continue until any input is not empty"
{:added "1.0"
:static true}
([] ())
([c1] (lazy-seq c1))
([c1 c2]
(lazy-seq
(let [s1 (seq c1) s2 (seq c2)]
(when (or s1 s2)
(cons (first s1) (cons (first s2)
(exhaustive-interleave (rest s1) (rest s2))))))))
([c1 c2 & colls]
(lazy-seq
(let [ss (map seq (conj colls c2 c1))]
(when (some identity ss)
(concat (map first ss) (apply exhaustive-interleave (map rest ss))))))))
here's a one-liner that does the zip: (defn zip [[a & as] [b & bs]] (lazy-seq (cons [a b] (when (some seq [as bs]) (zip as bs)))))
Hello folks 😄 Does anyone happen to have worked with .HAR files in Clojure? is there any libraries ready to use? I haven't found any
Do you mean this one? https://en.wikipedia.org/wiki/HAR_(file_format)
technically it's just a JSON 😅 but i wonder if there's anything beyond only parsing it as JSON
When I read the spec correctly, it is json based. If that’s the case, you could process with e.g. cheshire
Ah, now I get you. What things beyond parsing do you have in mind?
Honestly i don't know, but if anyone made anything i'd like to check it out before reinventing the wheel
maybe i'll find out while building my solution 😄
I've been using Clojure CLI this year after about 9 years of using Leiningen and it's templates. At first I missed a few templates until I realised I could just create a deps.edn file and copy over the dependencies. I don't miss using Leiningen plugins. They were useful when I started learning, but did hide away details of how things worked. I'm now creating my own templates for Clojure CLI tools, it seems very straightforward when using clj-new template, a template to create templates.
If you do full-stack development do you make it one big project (backend+frontend) or separate them?
Unless there is reason to create a monolithic full stack app, I will separate front from back. This encourages development of a good API around the backend and allows greater flexibility in the architecture. It's also easier to scale separate parts for their own specific needs
you can still use leiningen templates with the cli tools with clj-new
@gr.evocatus https://github.com/seancorfield/clj-new is what Alex is referring to. See a list of CLI tools here https://github.com/clojure/tools.deps.alpha/wiki/Tools
(cond-> {:foo "foo"}
true (assoc :bar "bar")
true (update :foo str "123")
some-bool? (assoc :baz "baz"))
How would I go about making this a bit nicer? Specifically avoid the true
s for the default operations.Could also do this:
(cond-> {:foo "foo123" :bar "bar"}
some-bool? (assoc :baz "baz"))
The things that are always true
can just be included in the initialization step fo the map.Without more context on how dynamic you need it to be, I’m not sure. But the general principle holds that anything in a static true
section should be moveable into the initial map.
(-> {:foo "foo"}
(assoc :bar "bar")
(update :foo str "123")
(cond-> some-bool? (assoc :baz "baz"))
Does that play nicely with multiple conditions? e.g:
(cond-> {:foo "foo"}
true (assoc :bar "bar")
true (update :foo str "123")
some-bool? (assoc :baz "baz")
some-other-bool? (assoc :quux "quux"))
I guess I'd end up with:
(-> {:foo "foo"}
(assoc :bar "bar")
(update :foo str "123")
(cond-> some-bool? (assoc :baz "baz")
some-other-bool? (assoc :quux "quux")))