beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Mohamed Aziz Knani 2020-10-22T03:21:01.329400Z

Hello, I use immutant with ring. I want to write something like "tail -f" with websockets. I pass an InputStream to send! but it doesn't do what I want. Does anyone have an idea of how to do this ?

sova-soars-the-sora 2020-10-22T03:21:43.329600Z

What does tail -f do?

sova-soars-the-sora 2020-10-22T03:22:23.329800Z

googles furiously

sova-soars-the-sora 2020-10-22T03:22:32.330300Z

It means tail -f command will wait for new strings in the file and show these strings dynamically. This command useful for observing log files .

For example try, tail -f /var/log/messages.

sova-soars-the-sora 2020-10-22T03:22:42.330600Z

alright... that might help get the ball rolling on that question

sova-soars-the-sora 2020-10-22T03:23:24.331100Z

Hmmm... you will probably have to send discrete packets through websockets... rather than a stream, but my confidence is only 55% on that statement

Mohamed Aziz Knani 2020-10-22T03:24:32.331600Z

> discrete packets Can you explain what this means ?

sova-soars-the-sora 2020-10-22T03:26:43.333Z

send one drop at a time instead of a river

Mohamed Aziz Knani 2020-10-22T03:27:34.334100Z

wait I will read more about inputstream, the stream part is confusing

2020-10-22T03:27:38.334300Z

I don't know immutant's websocket abstraction specifically, but the APIs I've seen expect to take objects that they then write to the socket

2020-10-22T03:28:21.335Z

in theory, just writing an inputstream to a socket should be possible with <http://clojure.java.io/copy|clojure.java.io/copy>

sova-soars-the-sora 2020-10-22T03:28:44.335400Z

oh neat.. yeah hopefully you get it resolved, 😃

Mohamed Aziz Knani 2020-10-22T03:28:59.335700Z

ah thanks let me try this

2020-10-22T03:30:09.336800Z

and I'd expect send! to be something more abstract, that tries to serialize the objects and do the writing for you - it's higher level than what you probably want if it's anything like the send! from sente for example

Mohamed Aziz Knani 2020-10-22T03:30:53.337500Z

wait you mean like do (io/copy inputstream channel) instead of (send! inputstream channel) ?

2020-10-22T03:31:15.337900Z

this really depends on what "channel" even is

2020-10-22T03:31:28.338300Z

sorry, I don't know immutant, but I've done this with other libs

Mohamed Aziz Knani 2020-10-22T03:32:06.338500Z

it's a org.projectodd.wunderboss.web.async.Channel

2020-10-22T03:33:58.339200Z

yeah, that's not an OutputStream, so you can't use io/copy

2020-10-22T03:34:18.339600Z

it wants to take an Object, which it then wraps up and puts on the socket

Mohamed Aziz Knani 2020-10-22T03:34:56.340100Z

okay so I think the easiest solution for me is to do what @sova said

Mohamed Aziz Knani 2020-10-22T03:36:26.341Z

so like I open a file, and then how do I know that it changed? is there like a callback to see if it changed?

Mohamed Aziz Knani 2020-10-22T03:36:44.341500Z

or should I just do a loop and check if it changed?

2020-10-22T03:41:06.342300Z

you can use a WatchService, I assume some clojure library is available to wrap it if you aren't comfortable using it directly

Mohamed Aziz Knani 2020-10-22T03:41:34.342700Z

I will look this up, Thanks 🙏

Mohamed Aziz Knani 2020-10-22T03:43:33.343900Z

I just straced this On linux "tail -f" uses the select syscall.

Mohamed Aziz Knani 2020-10-22T03:45:47.344600Z

I mean read should be blocking right? Until data is written?

Mohamed Aziz Knani 2020-10-22T03:46:17.344900Z

Oh or that's only in a fifo

Mohamed Aziz Knani 2020-10-22T03:49:27.345300Z

Yes I think watchservice would work @noisesmith thanks

Eugene Kiba 2020-10-22T08:32:42.353900Z

Is there a good comparison regarding modern IDE support of Clojure/ClojureScript ? Any default preferable options for commercial development?

Eugene Kiba 2020-10-23T07:57:20.395500Z

thanks everyone )

Eugene Kiba 2020-10-22T08:33:20.354500Z

thanks

0xclj 2020-10-22T08:54:00.355200Z

There’s Cursive for IntelliJ: https://plugins.jetbrains.com/plugin/8090-cursive

practicalli-john 2020-10-22T09:41:11.355500Z

Not specifically created to be a comparison, but this may help you understand the basic differences. http://practicalli.github.io/clojure/clojure-editors/ They all provide excellent support for Clojure and are free for commercial and non-commercial work (although sponsorship to the project maintainers is always appreciated) IntelliJ and Cursive requires a license. It also requires an annual fee for commercial work. Recommendation is to use the editor you prefer, to reduce the learning curve.

Dave Russell 2020-10-22T10:40:28.356300Z

Is there a more idiomatic way of writing if x x y?

ep 2020-10-22T10:42:44.356500Z

(or x y) ?

Dave Russell 2020-10-22T10:43:54.356700Z

I must have had a weak cup of coffee this morning 😛

👍 1
😜 1
Dave Russell 2020-10-22T10:43:55.356900Z

Thanks

2020-10-22T10:55:32.359Z

Anyone beginned clojure without any knowledge of java/javascript? What did you do to use clojure interop well?

practicalli-john 2020-10-22T12:31:30.359600Z

I mainly use reagent, so no need for much JavaScript interop unless you really want to. For more complex UI, then there is re-frame There are excellent courses on reagent and re-frame here: https://www.jacekschae.com/ To use npm packages, many use http://shadow-cljs.org/

Jim Newton 2020-10-22T12:56:14.361200Z

is there something special I have to do in a macro to inject meta data into the macro expansion? for example, I would like this macro to define a dynamic variable whose name is given by public-name .

(defmacro defn-memoized
  [[public-name internal-name] docstring &amp; body]
  (assert (string? docstring))
  `(let []
     (defn ~internal-name ~@body)
     (def ^:dynamic ~public-name ~docstring (memoize ~internal-name))
     )) 

Jim Newton 2020-10-22T12:59:19.361900Z

this is supposed to define a function which is memoized, but which I can rebind using binding to limit the dynamic extend of the memoization

Jim Newton 2020-10-22T13:00:07.362700Z

but at the binding-site, clojure complains the variable is not dynamic. not sure if this is a loading order problem, or a problem with my macro not injecting meta data correctly

alexmiller 2020-10-22T13:01:59.364200Z

In a macro the metadata is being applied at the wrong time - instead use with-meta to apply the metadata in the expansion

Jim Newton 2020-10-22T13:13:50.365800Z

@alexmiller can you give me an example? I looked at the doc for with-meta but it's not clear to me how the macro interaction is working with metadata. It would be nice if there were an example either in the defmacro docs or the with-meta docs. I can create such an example, once I understand it.

Jim Newton 2020-10-22T13:14:32.366400Z

I.e. do I need with-meta to be called a macro expansion time, or do I want the expanded code to contain with-meta ?

alexmiller 2020-10-22T13:20:07.366700Z

The latter

Jim Newton 2020-10-23T09:39:05.399900Z

I've added a https://clojuredocs.org/clojure.core/with-meta#example-5f92a7f6e4b0b1e3652d73e7 of with-meta. However, not sure this is the correct place for the example. Perhaps it is more appropriate as an example with defmacro ?

alexmiller 2020-10-22T13:24:35.367400Z

you'll want something like (with-meta ~public-name {:dynamic true}) here

Jim Newton 2020-10-22T13:37:09.367500Z

that doesn't work, at least as I understand your suggestion.

(defmacro defn-memoized
  [[public-name internal-name] docstring &amp; body]
  (assert (string? docstring))
  `(let []
     (defn ~internal-name ~@body)
     (def (with-meta  ~public-name {:dynamic true}) ~docstring (memoize ~internal-name))
     ))
This gives an error at the macro call-site that the first argument of def must be a symbol.

alexmiller 2020-10-22T13:40:31.368100Z

sorry, probably need to evaluate the outer expr ~(with-meta public-name {:dynamic true})

Jim Newton 2020-10-22T14:01:51.368300Z

seems the compiler is much happier with that.

Jim Newton 2020-10-22T14:02:26.368500Z

(defmacro defn-memoized
  [[public-name internal-name] docstring &amp; body]
  (assert (string? docstring))
  `(let []
     (defn ~internal-name ~@body)
     (def ~(with-meta public-name {:dynamic true}) ~docstring (memoize ~internal-name))
     ))

0xclj 2020-10-22T15:04:10.373300Z

What’s the Clojure equivalent for https://github.com/mperham/sidekiq or https://github.com/contribsys/faktory for background processing? There’s a 4 year old https://www.reddit.com/r/Clojure/comments/48ur9m/distributed_workers_with_retry_backoff_looking/ with some comments, looks like https://github.com/ptaoussanis/carmine is the only one under active development.

dharrigan 2020-10-22T15:12:01.373800Z

I use <https://github.com/lerouxrgd/celtuce> as my Redis client

0xclj 2020-10-22T15:28:10.374600Z

Can’t really tell if it supports background processing looking at the README, does it?

2020-10-22T15:28:19.374800Z

I've never found a convincing one based on Redis. Or on anything. I'm not aware of any Clojure dep that would come with a web-ui and a deployment cookbook. Because Clojure (and really, the JVM) has solid multi threading support, lots of the things you would defer out of process in a GIL-VM like Ruby's or Python's can be done in-process instead. (future (sendmail ...)) In-process retry/backoff you'll have to deal with yourself, I'm pretty sure I've seen a nice library for this recently but I can't recall the name .. This being said, there are many good reasons to distribute tasks on several processes. For such cases, I use RabbitMQ (with http://clojurerabbitmq.info/articles/guides.html). It provides the retry feature, and better (ACK, NACK) semantics than Sidekiq, imo - if a worker disappears without terminating message processing, message will be made available again, no need to requeue on exceptions. Setting up RabbitMQ for a Sidekiq-like queue processing is probably the simplest RMQ use case - don't let the documentation confuse you 🙂 The backoff thing is however https://www.brianstorti.com/rabbitmq-exponential-backoff/. Apache Kafka seems to be the rock solid, all powerful solution for this. It might be worth starting with Kafka right away and spare yourself some of the Rabbit nonsense. I have yet to try it. I've chosen RabbitMQ because it looked simpler to operate and develop with and my needs are modest (no HA, no high throughput).

0xclj 2020-10-22T15:51:39.375500Z

@zor, Thanks for the detailed response. I’m merely looking for a background processing lib. Using RabbitMQ for this could be something I’d explore if there’s no reliable library to handle background jobs. Will also read upon (future (,,,)) to see if that suits my need. The use-case is indeed to send emails as notifications upon an update.

☺️ 1
2020-10-22T15:52:47.375700Z

There is also https://clojure.org/reference/agents, which comes with a pre-made Thread pool, clearer semantics, and more pre-made useful things for you to build on.

0xclj 2020-10-22T15:55:26.376Z

Thanks, will read up on it too.

2020-10-22T16:01:58.376300Z

And ... finally the "Message Queues" bits of https://www.clojure-toolbox.com/ 🙂 Notably https://github.com/Factual/durable-queue seems a nice in-between agents and rabbit. My gut feeling is that you can get stuff done with Agents today, and move to something more robust if you need to.

0xclj 2020-10-22T16:08:30.376900Z

Noted this as well. https://www.clojure-toolbox.com/ is awesome! Thanks again! 😄

1
0xclj 2020-10-22T16:11:08.377400Z

Also, is there any relevant channel here that you’re aware of for discussion of system designs by any chance?

Day Bobby 2020-10-22T17:10:08.378100Z

What is the limitation of carmine as a messages queue I might ask? I'm looking for something similar myself. I also found clj-faktory (https://github.com/apa512/clj-faktory) but carmine is under more active development. I know it doesn't have a web ui but I can do without one.

Day Bobby 2020-10-22T17:10:34.378400Z

for system designs I think there is #architecture

👍 1
haywood 2020-10-22T17:45:26.379600Z

potentially dumb question, I need to pretty-print an edn map to a file, including any meta-data, basically doing what (binding [*print-meta* true] (pr my-cool-map)) would do

alexmiller 2020-10-22T17:57:13.381400Z

(spit "foo.edn" (with-out-str (binding [*print-meta* true] (pr my-cool-map)))) is one way

alexmiller 2020-10-22T17:58:29.382200Z

there are more cumbersome ways if you need better performance (open a stream to a file and bind out to that)

haywood 2020-10-22T17:58:50.382900Z

Performance isn’t an issue, but when I open the file it’s not pretty printed

alexmiller 2020-10-22T18:00:55.383100Z

well use, pprint then

haywood 2020-10-22T18:01:24.383700Z

pprint doesn’t seem to abide by the *print-meta* binding

haywood 2020-10-22T18:02:05.384Z

perhaps I need to look into creating a custom writer

alexmiller 2020-10-22T18:09:29.384500Z

interesting. there is actually an old ticket for this https://clojure.atlassian.net/browse/CLJ-1445

alexmiller 2020-10-22T18:10:01.384800Z

the attached patch there seems to work

alexmiller 2020-10-22T18:12:05.385100Z

if you'd like to vote for this: https://ask.clojure.org/index.php/3315/pprint-prints-some-metadata-when-print-meta-bound-true-but-not

alexmiller 2020-10-22T18:12:18.385600Z

can't say I've ever noticed this before

haywood 2020-10-22T18:16:24.386100Z

Oh nice, thanks for finding that, voted! Also, maybe I’m just missing it, but where can I find the attached clj-1445-workaround-v1.clj file?

alexmiller 2020-10-22T18:17:37.386300Z

it's on the CLJ ticket

haywood 2020-10-22T18:21:19.386500Z

ah, derp, cheers Alex 🙂

2020-10-22T18:31:42.386900Z

One limitation of the Carmine's Message-Queue is that it doesn't seem easy to interop with non-Clojure workers - something that would be doable with RabbitMQ or Kafka. No CLJS support either, so even if you're interop needs are with Node.js processes, you seem to be out of luck. clj-faktory - as part of a faktory system, is inherently polyglot, so this solves that. And you get the nice faktory UI and scheduler, and commercial support options. I wouldn't be worried about active or inactive development. It's rather common in Clojure to have stuff that works and is in a finished state 🙂

👍 1
dharrigan 2020-10-22T19:39:13.388600Z

I'm seeing this when I turn on (set! *warn-on-reflection* true) : Reflection warning, foo/bar/policy.clj:0:0 - call to java.lang.IllegalArgumentException ctor can't be resolved. Yet, nowhere in my codebase do I use IllegalArgumentException. Would it be a 3rd party dependency issue?

seancorfield 2020-10-22T19:49:10.390400Z

It could be something that foo.bar.policy is requiring, but normally reflection reports the correct filename. Maybe a macro expansion (but, again, I'd expect the filename/line number to be a bit more meaningful).

dharrigan 2020-10-22T19:53:42.390800Z

It's a puzzler

alexmiller 2020-10-22T19:55:03.392Z

I dropped an actual patch on the clj ticket too to actually fix this

1
seancorfield 2020-10-22T19:55:10.392300Z

I guess: comment out everything in policy.clj except the ns form and if you still get the warning, start commenting out required nses?

dharrigan 2020-10-22T19:56:07.392600Z

Worth a shot, will give it a whirl 🙂

Day Bobby 2020-10-22T20:34:17.392800Z

Useful stuff, thank you! Gonna check out clj-faktory more to see if it implements all the stuff I need from faktory

Александр Стоянов 2020-10-22T22:52:03.393900Z

Hello! I have problem. Can run frontend but can't run backend cause "project/server.clj couldnt locate on classpath"

2020-10-22T23:30:31.394Z

You are using a shadow-cljs template? I know someone recommended you ask in #beginners, but I just wanted to point out that there is also a #shadow-cljs channel where a larger fraction of people might be familiar with that template.

Александр Стоянов 2020-10-22T23:38:44.394200Z

thank you

2020-10-22T23:41:45.394400Z

Sorry, I misled you again 🙂

2020-10-22T23:41:54.394600Z

but you should be getting closer

Александр Стоянов 2020-10-22T23:57:00.394800Z

im here 😉