Fork me on GitHub

I almost never use loops because collections are just easier to work with, and this thing with the position of recur is very obscure


Is that hx or helix?


Not familiar with who is providing the hooks wrappers


is that relevant here?


I don't know, I would hope it's irrelevant


I was gonna try to recreate if I knew which lib


it's helix


I can try to give better code examples if that's the goal, sorry that I reacted that way to the question, seemed like a tangent 🙂


No worries. I want to read the docstrings and understand. Could be a macroexpansion problem. Can you recreate with just a plain goloop and no hooks involved?


I can try but I don't have access to easy sandboxing, takes a while to create a new shadowcljs app and configure everything in the build.


I keep planning to learn clj and deps.edn and have some aliases for bootstrapping minimal cljs apps, but I never get around to it, too much other stuff to do


If you want to play around I think “shadow-cljs browser-repl app” will get you a repl


I don't know how to use repls


the go macro rewrites its body, it's not hard to end up with a situation where the "tail" is no longer a tail after the rewrite


@ashnur the go compiler might have a better chance with a simpler form with fewer branches:

(defhook use-take
  [channel on-take]
  (let [cancel-signal (hooks/use-ref false)]
     [channel on-take]
     (go-loop []
              (if-some [msg (when (not @cancel-signal)
                              (<! channel))]
                (do (ontake msg)
                (reset! cancel-signal true)))
     #(reset! cancel-signal true))))
I think that would behave the same as your original


the when combines the check on cancel-signal with the channel read, as it returns nil if its first arg is falsey


thanks, it's a bit confusing because I haven't had this working in any form yet, and the code I shared was a rewrite of an example I got, and .. and.. : D well, I am trying, and if it wont work, I will try to get at some simpler example


the rule of thumb is that go / go-loop are weird macro things, and they make chained callbacks on channels look like sequential code


so if they do something you don't understand when compiling, a good first try is to do less nesting (especially less nesting of macros)


the CSP part is not new to me, only clojure/clojurescript core functions and macros and their own ways of doing things 🙂


the rewriter is less likely to get confused when rewriting simpler forms


less nesting of macros : ) ok


I didn't think the rewriter could get confused at all


I turned the stack of go-loop / if-not / let / if-not / do (all macros) into go-loop / if-some / do


Yeah, I tried your version, it says the same thing. I will try to get at an isolated example now.


use-effect also appears to rewrite the body


oh that would explain it


Or maybe I misread it


I might missed this in the docs, but is there a way to download a new dependency without restarting the REPL while using tools.deps CLI?


not with the default set of deps - there are libraries that do this but they tend to be a bit hacky


Gotcha, thanks for the help!


I mean, even using a dep that you've downloaded for another project isn't simple - it's not the downloading that's complex, it's making the vm add new things to the classpath


@ander There is a branch of tools.deps.alpha that supports that, via a function call add-lib. I use it a lot. You can see how to use it in my dot-clojure repo: so I can just do clj -A:deps and then I have a REPL I can dynamically add new dependencies to.


In addition, the weird-looking DynamicClassLoader incantation there means I can do clj -A:deps:socket:rebl-11 and have Cognitect's REBL start up with a Socket REPL on port 50505 and both will support add-lib (since it needs a DCL).


I'm hoping to find time this week to do a new video for my YouTube channel that shows a dynamic REPL workflow where I start from a minimal new deps.edn project and add dependencies and build a web app all inside a running REPL with no restarts...


Oh wow, thanks for that! I'll give it a shot tonight. The premise for that video sounds great, I'd love to see it


This rocks! Thanks again


You have add-lib working? 🙂


Yep! Your dot-clojure is a great help as well. I have a lot to learn, and I can get caught up in getting my environment just right


Feel free to DM me with any questions about the dot-clojure stuff or REBL or anything in my videos 🙂


@ashnur it seems to work for me. I'm trying to recreate as much as possible

Bill Phillips03:05:29

Are there any good solutions for rename refactors? Or move refactors, or argument reordering? clj-refactor in emacs seems quite dead; is cursive good for this?


You should cut a ticket if you have issues with clj-refactor not working


The only rule of thumb to use it is that your code must compile before you perform a refactor on it


With code that compiles, its always worked for me. But I don't have mixed clj/cljs projects


@jings.bill Not sure where you're looking but looks pretty darn active to me...

Bill Phillips03:05:33

I guess that was harsh. I said it was dead because it hadn’t worked for me and I was never able to find a workaround; googling has found reports from others that it has issues if e.g. there’s cljs in the tree. That was the basis for my judgement; I guess it was premature.


I think the clojure-emacs team are most active on Gitter and IRC. Not sure where they hang out here on Slack -- maybe ask in #emacs or #cider ? I bet if you ask some of the team, they'd be happy to help you get it working...


(I've never used any automated refactoring support -- I prefer to keep my editor/toolchain as lean as possible and free of any "magic")

Bill Phillips03:05:34

Maybe that is well. It is difficult to give up once one comes to rely upon it.

Bill Phillips03:05:54

It makes a lot of basic housekeeping tasks straightforward and anxiety free.


clojure-lsp can handle that

❤️ 8
Bill Phillips04:05:28

This is wonderful. Thank you

Bill Phillips04:05:17

clojure-lsp has given me even more useful tools than i was looking for in the first place


its quite nice


and it gives me 'cannot recur here' where the recur is


first I thought it might be the helix macro, but people say the same code that doesn't work for me, works for them


if I comment out these lines, everything seems to work normally


it's a bit weird to be told that it's a non-deterministic process that decides if my code that is the same (to my very limited knowledge) as other functional code


one good news is, which it took me to sleep before, is that just using (go (loop instead of (go-loop works fine

Matthew Lemon15:05:53

Hi all. Python programmer here. Have tinkered with Clojure very briefly in the past and have been intrigued by it. Just bought a Clojure book (Getting Clojure) and am starting fresh. Have even dusted off my old Emacs config (vimmer by trade, but have switched back and forth a few times). Looking forward to getting stuck in.

👍 24

At the risk of opening a can of worms... If you're used to vim but have some emacs knowledge too you might find interesting. It's a whilst since I've used Emacs as my main editor for my Clojure but it is definitely my favourite of the assortment of Emacs options.

👍 4

there are also excellent options for vim. and often best to not juggle too many things while learning the language.


yeah, IMHO the vim clojure tooling is very good

👍 4
Matthew Lemon16:05:20

Yeah, have tried Spacemacs in the past and did like it, but I'm too much of a tinkerer and tore it all down to a bare Emacs config a few times. Have done that vim too recently, as well as looking at VS Code, etc. Definitely looking for an environment where I can just learn the language - I hadn't actually thought about vin tooling. It never seemed to be that great in the past. Worth a go now??


I use neovim with vim-clojure-static plus vim-sexp, I've used both fireplace and iron.nvim


I like iron expecially lately, a compromise where the repl is easy to send code to, but it doesn't try to be an IDE

Matthew Lemon16:05:13

How comparable is it to Cider, etc?


but many people love fireplace as well


fireplace offers more IDE style features, and fireplace uses the cider tooling


I find it too "magic" and brittle


but that's just my opinion

Matthew Lemon16:05:35

Never heard of fireplace or iron. Will check both out. Want to avoid too much tinkering at this stage.


There's also the #vim channel to checkout.

Matthew Lemon16:05:41

@UJF10JP8A Ah, yes. Thanks.

👍 4
Daniel Stephens17:05:17

Hi, I'm having some trouble with reify, wanted to use it to mock out a kafka consumer in a test (I'm aware MockConsumer exists but it doesn't implement some functions), simplified down the following to just the bit that complains:

  (poll ^org.apache.kafka.clients.consumer.ConsumerRecords [_ ^long delay]
    (org.apache.kafka.clients.consumer.ConsumerRecords. {(TopicPartition. "topic-name" 0)
There are two methods in consumer that look like
     * @see KafkaConsumer#poll(long)
    ConsumerRecords<K, V> poll(long timeout);

     * @see KafkaConsumer#poll(Duration)
    ConsumerRecords<K, V> poll(Duration timeout);
I'm therefore trying to add the hints to point to that first one however my code current errors with
Syntax error (IllegalArgumentException) compiling reify* at (form-init1303277116252072083.clj:1:1).
Mismatched return type: poll, expected: org.apache.kafka.clients.consumer.ConsumerRecords, had: java.lang.Object
If I don't include hints I get errors telling me to hint, the return type hint seems to make no difference, and I get the same error with or without it. Fully qualified things just to prove out that I'm using the correct types everywhere but I don't need it like that. Anyone know what's going wrong? Thanks!


reify type hints the return type on the method name, instead of the args

Daniel Stephens17:05:27

ahh okay, so I have to swap poll with the type hint like (^org.apache.kafka.clients.consumer.ConsumerRecords poll [_ ^long delay] ...) Seems to be compiling thanks!


yup, try to resist doing that anywhere else, pretty sure it's only reify that puts the type hint in front

👍 4

also, I find it much more readable if you use import (in fact that's all import does - just referencing the class causes the load, but the import makes it more readable)

Daniel Stephens17:05:46

mm yeah, I think that's what caught me out as I'm used to doing it the other way around, I wonder what the reason for the difference is. @noisesmith > Fully qualified things just to prove out that I'm using the correct types everywhere but I don't need it like that Yeah I do agree, just was trying to make sure I wasn't putting the wrong types in anywhere, as I thought the error might have been because I'd had mismatched types from the wrong import


I missed that, apologies

☺️ 4
Markus Kiili18:05:01

Hi. Why does the last line give an error? i.e. why cannot I use qualified symbol although the symbol exists in the corresponding namespace?

(def x 5)
x ;; 5
user/x ;; 5
(in-ns 'test)
(refer 'user)
((ns-map 'test) 'x) ;; #'user/x
x ;; 5
test/x ;; CompilerException java.lang.RuntimeException: No such var: test/x


I don't think refer does what you think it does


using refer doesn't put the var in your ns, it just makes it so your ns will look it up if referenced in that ns


when you use test from another ns, they don't check the ns-map, they check the ns-publics


(ins)test=> (ns-publics 'user)
{x #'user/x, array-of #'user/array-of}
(ins)test=> (ns-publics 'test)
(ins)test=> (def y 6)
(cmd)test=> (ns-publics 'test)
{y #'test/y}


it's rare that you need this, but there is the function ns-resolve that looks up 'x not based on being owned by the ns, but rather the way the ns would look it up

David Pham20:05:48

Clojure is really a beautiful language, I wanted to ask how you could make a file-seq while excluding some directories, so I went and look at the source code, and it was a trivial task to perform. Such a beautiful language.

👍 8

i am also finding that using the source TM is often worthwhile - even if i don't initially understand much of what i see the first time :)


question: I have a 75mb (big?) XML file which I want to convert into CSV and later a database. The XML is 6 levels deep. I have sometimes identical tags on level 2 and level 4 and level 6. Over the recent days I tried to break open the structure using xml-zip. So far I find it extremly challenging. I wonder if it would be better to use clj-xpath. Any opinions?


it depends on the transformation you’re trying to do. I would porbably use something like and just use normal clojure data transformations


75mb shouldn’t be too much to handle unless you’re processing a lot of xml files frequently or are running in a constrained environment


after parsing the csv file, I personally would prefer something like over clj-xpath

Charles H20:05:39

I've been going through the Clojure Koans and enjoying that as an intro, does anyone know of a collection of more advanced problems/puzzles for Clojure?

David Pham20:05:56

In deps.edn , how can we have a local git repository?


Try searching for :local/root on this page, and see if it answers your question?


I believe :local/root can point at anything local, whether it happens to be a clone of a git repository or not. i.e.. the local files need not have anything to do with git.

David Pham21:05:03

So basically you would copy the repos locally and put it to the correct commit?


I believe so, yes.


If you want to specify a commit in the deps.edn file, you can put in the URL and use :git/url instead, assuming there is URL that you can use to point to, which I suppose could be a private repo if you did not want it to be public.

Mario C.23:05:56

I have a route defined as (POST "/saml" [:as req] handler) . Its basically a cut-n-paste from Anyways, everything seems to work fine up until I get the POST response. I get a 404 /saml not found. But if I allow all origins in :cors-allowed-origins then it works. I guess my question is why can't my app find the route /saml on a POST. If its a CORS issue, wouldn't the error have been related to cors instead of not found? Why does it work when I allow all origins?

Mario C.23:05:06

Could this be an issue of http vs https?


@mario.cordova.862 CORS uses an OPTIONS request so the most likely problem is that you have your cors middleware composed in the wrong order.


(although if changing the allowed origin makes it work, there may be another issue at play here)


Can you show how you are building your middleware stack and how your app/routes are added into that stack?

Mario C.23:05:16

(def app
  (-> (apply routes [home-routes
                     (saml-routes sso-config)
      (wrap-cors :access-control-allow-origin (cors-allowed-origins)
                 :access-control-allow-methods [:get :put :post :delete]
                 :access-control-expose-headers ["Location"])
      (wrap-json-body {:keywords? true})

Mario C.23:05:31

This is how the routes are composed


Move cors to the end. It usually needs to be the outermost middleware

Mario C.23:05:11

If I replace (cors-allowed-origins) to [#".*"] it works


Hmm, what is (cors-allowed-origins) ? That may actually be too restrictive.


(but, regardless, cors can be problematic in various ways if it isn't the outermost middleware in my experience)

Mario C.23:05:00

It returns a vector of allowed origins. So something like [[#"localhost:8080"] [#""]]

Mario C.23:05:31

After moving the cors to the outer edges it still returns not found


I think you should be returning a vector of regexes, not a vector of vectors.

Mario C.23:05:03

yes that what it returns, my mistake

Mario C.23:05:48

Interestingly enough, I am getting 500. Ring handler returned nil

Mario C.23:05:30

Seems if I add "null" to the allowed origins it works. Since the redirect was sending null in the origin header.


Hmm, that seems... odd...


that would be very easy for an attacker to exploit