Fork me on GitHub
#beginners
<
2020-05-05
>
Aron00:05:56

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

dpsutton00:05:10

Is that hx or helix?

dpsutton00:05:26

Not familiar with who is providing the hooks wrappers

Aron00:05:22

is that relevant here?

Aron00:05:46

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

dpsutton00:05:53

I was gonna try to recreate if I knew which lib

Aron00:05:00

it's helix

Aron00:05:28

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 🙂

dpsutton00:05:22

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?

Aron00:05:19

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.

Aron00:05:13

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

dpsutton00:05:53

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

Aron00:05:11

I don't know how to use repls

noisesmith00:05:41

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

noisesmith00:05:04

@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)]
    (hooks/use-effect
     [channel on-take]
     (go-loop []
              (if-some [msg (when (not @cancel-signal)
                              (<! channel))]
                (do (ontake msg)
                    (recur))
                (reset! cancel-signal true)))
     #(reset! cancel-signal true))))
I think that would behave the same as your original

noisesmith00:05:13

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

Aron00:05:46

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

noisesmith00:05:48

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

noisesmith00:05:23

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)

Aron00:05:33

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

noisesmith00:05:38

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

Aron00:05:45

less nesting of macros : ) ok

Aron00:05:05

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

noisesmith00:05:29

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

Aron00:05:26

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

hiredman01:05:14

use-effect also appears to rewrite the body

noisesmith01:05:34

oh that would explain it

hiredman01:05:12

Or maybe I misread it

ander01:05:57

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?

noisesmith01:05:33

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

ander01:05:17

Gotcha, thanks for the help!

noisesmith01:05:54

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

seancorfield01:05:10

@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: https://github.com/seancorfield/dot-clojure/blob/master/deps.edn#L147-L164 so I can just do clj -A:deps and then I have a REPL I can dynamically add new dependencies to.

seancorfield01:05:18

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

seancorfield01:05:34

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

ander12:05:59

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

ander00:05:13

This rocks! Thanks again

seancorfield00:05:05

You have add-lib working? 🙂

ander00:05:05

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

seancorfield01:05:23

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

dpsutton02:05:14

@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?

didibus18:05:44

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

didibus18:05:05

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

didibus18:05:35

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

seancorfield03:05:18

@jings.bill Not sure where you're looking but https://github.com/clojure-emacs/clj-refactor.el/commits/master 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.

seancorfield03:05:42

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

seancorfield03:05:41

(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.

dpsutton03:05:36

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

dpsutton04:05:59

its quite nice

Aron08:05:51

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

Aron08:05:00

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

Aron08:05:12

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

Aron09:05:24

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

Aron09:05:15

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
kelveden15:05:43

At the risk of opening a can of worms... If you're used to vim but have some emacs knowledge too you might find https://www.spacemacs.org/ 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
dpsutton15:05:09

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

8
noisesmith16:05:14

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

noisesmith16:05:35

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

noisesmith16:05:07

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?

noisesmith16:05:25

but many people love fireplace as well

noisesmith16:05:43

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

noisesmith16:05:55

I find it too "magic" and brittle

noisesmith16:05:06

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.

kelveden16:05:10

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:

(reify
  org.apache.kafka.clients.consumer.Consumer
  (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)
     */
    @Deprecated
    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!

bfabry17:05:51

reify type hints the return type on the method name, instead of the args https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/reify

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!

bfabry17:05:58

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

👍 4
noisesmith17:05:05

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

noisesmith17:05:59

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)
(clojure.core/refer-clojure)
(refer 'user)
((ns-map 'test) 'x) ;; #'user/x
x ;; 5
test/x ;; CompilerException java.lang.RuntimeException: No such var: test/x

noisesmith18:05:41

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

noisesmith18:05:11

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

noisesmith18:05:59

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

noisesmith18:05:31

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

noisesmith18:05:05

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
sogaiu21:05:02

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

sroller20:05:56

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?

phronmophobic20:05:34

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

phronmophobic20:05:23

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

phronmophobic20:05:07

after parsing the csv file, I personally would prefer something like https://github.com/redplanetlabs/specter 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?

andy.fingerhut21:05:15

Try searching for :local/root on this page, and see if it answers your question? https://clojure.org/reference/deps_and_cli

andy.fingerhut21:05:03

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?

andy.fingerhut22:05:18

I believe so, yes.

andy.fingerhut22:05:19

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 https://github.com/quephird/saml-test. 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?

seancorfield23:05:30

@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.

4
seancorfield23:05:41

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

seancorfield23:05:09

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
                     model-routes
                     saml-main-routes
                     (saml-routes sso-config)
                     app-routes])
      (wrap-base-url)
      (wrap-cors :access-control-allow-origin (cors-allowed-origins)
                 :access-control-allow-methods [:get :put :post :delete]
                 :access-control-expose-headers ["Location"])
      (wrap-json-response)
      (wrap-json-body {:keywords? true})
      (wrap-multipart-params)
      (wrap-session)
      (wrap-params)
      ))

Mario C.23:05:31

This is how the routes are composed

seancorfield23:05:04

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

seancorfield23:05:43

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

seancorfield23:05:34

(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

seancorfield23:05:30

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.

seancorfield23:05:18

Hmm, that seems... odd...

noisesmith23:05:18

that would be very easy for an attacker to exploit