Fork me on GitHub
#clojure
<
2020-09-29
>
cfleming00:09:17

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

cfleming00:09:20

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]]

cfleming00:09:01

That would do it 🙂

cfleming00:09:33

They don’t normally do that but I defined a print-method for them for some testing a while back.

noisesmith00:09:33

it was tricky printing like I thought!

cfleming00:09:42

Indeed it was!

plexus06:09:27

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

codeasone13:09:11

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.

Vladislav16:09:31

use cursive for it, as mentioned above

jumar08:09:39

Clj-refactor was able to do it too - bot sure if that’s using clojure.tools

slipset08:09:58

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 ?

Cameron09:09:52

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 > Protocols 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 )

Cameron09:09:33

I have to go but I may write more in a bit when I'm back, hope that helps at least

slipset09:09:14

It does, thanks!

Cameron09:09:52
replied to a thread: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 > Protocols 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 )

nickt12:09:34

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))

delaguardo12:09:09

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))))))))

markmarkmark12:09:48

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)))))

ghadi13:09:00

(concat shorter-end (repeat nil)) then interleave as normal

nickt12:09:17

oops, fixed

MatthewLisp12:09:22

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

MatthewLisp12:09:25

technically it's just a JSON 😅 but i wonder if there's anything beyond only parsing it as JSON

javahippie12:09:43

When I read the spec correctly, it is json based. If that’s the case, you could process with e.g. cheshire

javahippie12:09:25

Ah, now I get you. What things beyond parsing do you have in mind?

MatthewLisp12:09:20

Honestly i don't know, but if anyone made anything i'd like to check it out before reinventing the wheel

MatthewLisp12:09:46

maybe i'll find out while building my solution 😄

evocatus17:09:30

Do you miss Leiningen templates when using cli-tools?

practicalli-johnny09:09:21

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.

👍 3
evocatus17:09:24

If you do full-stack development do you make it one big project (backend+frontend) or separate them?

practicalli-johnny09:09:08

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

👍 3
evocatus22:09:33

I get your point, thanks

Alex Miller (Clojure team)17:09:04

you can still use leiningen templates with the cli tools with clj-new

curlyfry18:09:32

(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 trues for the default operations.

mafcocinco19:09:09

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.

mafcocinco19:09:34

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.

ghadi18:09:35

mix -> and cond->

ghadi18:09:52

(-> {:foo "foo"}
    (assoc :bar "bar")
    (update :foo str "123")
    (cond-> some-bool? (assoc :baz "baz"))

curlyfry18:09:55

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"))

curlyfry19:09:09

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")))

curlyfry19:09:30

Looks good to me! Thanks @ghadi

ghadi19:09:01

np. @curlyfry a little of that can go a long way

potetm19:09:34

@curlyfry alternatively merge:

(merge {:foo "foo"}
       {:bar "bar"
        :foo "123"}
       (when some-bool?
         {:baz "baz"})
       (when some-other-bool?
         {:quux "quux"}))

potetm19:09:01

Requires that you explicitly get update values, but it’s extremely straightforward:

(let [{foo :foo} mah-map]
  (merge {:bar "bar"
          :foo (str foo "123")}
         (when some-bool?
           {:baz "baz"})
         (when some-other-bool?
           {:quux "quux"})))