Fork me on GitHub
#clojure
<
2021-09-26
>
didibus04:09:25

I feel when I write macro I often want do have conditionals like:

`(try
       [email protected]'
       ~(when catch
          catch)
       ~(when finally
          finally))
But since when returns nil when false, the macro ends up with nils in it. Is there some cool trick for this?

didibus04:09:26

Oh, might have found a trick of my own just as I was asking:

`(try
       [email protected]'
       [email protected](when catch
           [catch])
       [email protected](when finally
           [finally]))
Seems to work

👍 1
duckie 1
🙌 1
Alex Miller (Clojure team)05:09:19

another technique is to not use ` and instead cons up a coll of clauses which may be conditionally built

💯 1
Alex Miller (Clojure team)05:09:38

(cons `try (cond-> try' 
             catch (conj catch)
             finally (conj finally)))
something like that

1
Carlo10:09:47

using malli, is it possible to spec a binary add function so that we check that the result is greater than the arguments?

borkdude10:09:47

@meditans fyi, there is also a #malli channel :)

Carlo10:09:21

yes, thanks @U04V15CAJ, I posted there, but it seems a fairly low traffic channel, so I hoped to have more visibility here; if the duplication is a problem, I can delete the one in #malli

borkdude10:09:06

not a problem with me

Ben Sless10:09:15

malli is a pretty active channel for a lib channel, don't worry

SK15:09:10

hi! is there a way to have a UI component appear in the REPL to input data that is better done via a UI? (eg picking a date, or picking a set of elements from a list)

didibus20:09:27

If by "is there a way", you mean would it be feasible to have such a REPL, the answer is yes. If by "is there a way", you mean using one of the existing popular REPLs and there UIs, the answer I think is no.

Ed22:09:30

Something like #reveal is probably a good place to start

p-himik07:09:27

If you don't care about the input appearing right in the REPL UI and you would be content with such an input to be in a pop-up, then you can define an atom and use any UI library to show you the right control that changes the atom. Like it's done e.g. here: https://github.com/cljfx/cljfx#atoms

p-himik07:09:30

#reveal , while being a great thing by itself, is probably more confusing in this case than helpful. It's not a REPL, it's an extra UI that you usually use in addition to an existing REPL.

Eddie15:09:20

I have a requirement that a particular class exists when the application exists. The class is a concrete implementation of an interface. I tried using reify this, but the class will only exist when the call to reify is loaded. Is it possible/recommended that I implement this class in Java and then distribute a the compiled class files with my project? My understanding is that java is binary compatible so if I compile with an old enough java it should “just work” on virtually any user’s environment. Is that right?

emccue15:09:02

• yes you can just include a class file you got from java • alternatively you can AOT a namespace to get a class file to exist for it with :gen-class

Eddie15:09:48

When does the compilation of a :gen-class namespace happen?

Eddie15:09:16

Also, thanks for the confirmation about distributing classes!

p-himik16:09:00

It happens when you tell it to happen - no difference from Java here. A handy guide: https://clojure.org/reference/compilation

Eddie16:09:29

I think I misunderstood the suggestion to use :gen-class. Is the idea that with a :gen-class namespace there is no need to distribute class files because Clojure can automatically compile them on application start or is the suggestion to use :gen-class as a means of creating some class files to include the distribution?

p-himik16:09:43

As mentioned in that guide: > gen-class and the :gen-class directive are ignored when not compiling. It's called Ahead Of Time compilation - you gotta compile it before you run it.

Eddie16:09:02

Gotcha. That was my understanding. I have used :gen-class a number of times before when either 1) the entire app is AOT compiled or 2) there is a separate build step for compiling a few gen-class namespaces. I’m not sure if the class files produced by :gen-class bind your application to a particular version of Clojure or not. I believe Clojure libraries are specifically distributed as source to avoid this issue.

Eddie16:09:05

If I am wrong about that, then :gen-class seems like good solution to keep the entire codebase in Clojure. Beyond that, it is kind of orthogonal to the issue of distributing a library that requires certain classes exist on the classpath before the class-loader that references them is created.

p-himik16:09:06

> I’m not sure if the class files produced by :gen-class bind your application to a particular version of Clojure or not Yes, but at the same time Clojure tries really hard to not introduce backwards-incompatible changes. AFAICT, it's pretty much the same as Java - compiling something will tie you to the version that you used, but it's very likely that you will be able to use the same thing with some future version of Clojure/Java.

Eddie16:09:07

Ah, okay. That's good to know. Thanks!

Eddie16:09:20

> but it's very likely that you will be able to use the same thing with some future version of Clojure/Java. > Just to confirm we are on the same page, in this context "thing" means the exact class file. No need for recompilation, right?

p-himik16:09:40

Right. At least, that's my personal understanding. Maybe someone more knowledgeable will correct me.

didibus20:09:54

Wow, I just realized as-> can be used to destructure!

(-> [1 2]
    (as-> [one two]
        (println one two)))

;;=> 1 2

notbad 1
🤯 3
p-himik20:09:36

Quickly, delete it before someone else sees it and decides to use in the real code, with multiple forms within as->. :D

😆 4
didibus21:09:51

I've also been wondering what people think of if the thrrad-last macros were made aware of thread-first macros so they could compose? You know how you can use a thread-last inside a thread-first? But the other way doesn't work. Well what if you did:

(defmacro <<-
  [form arg]
  `(~(first form)
    ~arg
    [email protected](next form)))

(defmacro ->>
  [& forms]
  `(clojure.core/->>
    [email protected](for [form forms]
        (if (and (seqable? form)
                 (#{'-> 'as->} (first form)))
          `(<<- ~form)
          form))))
For example, which means that now you can compose them like so:
(->> [1 2 3]
     (map inc)
     (as-> [a b c]
         (+ a b c)))
Does this seem like a good idea? I know it kind of breaks the simplicity of the macro, but I feel it makes them nicely compose.

emccue21:09:01

i think you are unironically suggesting ->->><?as->cond->!

didibus21:09:43

Haha, hum :thinking_face:

seancorfield23:09:52

What's wrong with:

(-> [1 2 3]
    (->> (map inc))
    (as-> [a b c]
      (+ a b c)))
Why is everyone always trying to make arrow macros more complex? They do exactly what they're supposed to.

didibus00:09:39

Well, when you have longer sequence manipulation, you'll have ->> at first, and suddenly you might realize, oh this function takes the coll as first arg, now you'd need to refactor the whole chain.

didibus00:09:13

Or put some other way, I more often need the composition the other way around, since its generally that I'll modify a sequence, and near the end, use a non sequence function on it, like one of the string functions or something else.

seancorfield00:09:05

All you need to do is wrap the ->> expression with -> - hardly "refactoring the whole chain".

didibus00:09:31

Its subjective how "annoying" you find it or not I guess.

seancorfield23:09:41

(there's also a good argument for not mixing the arrow types since it says you're mixing "things" and "sequences" in your pipelines)