Fork me on GitHub
#clojure
<
2020-08-25
>
dominicm10:08:49

I vaguely recall a Clojure socket/prepl client written in Clojure. But now I can't find it! Does anyone know the project I'm referring to?

dominicm10:08:13

Hmm, no. I want to connect to one, rather than start one.

flowthing10:08:30

Propel can connect to one, too.

flowthing10:08:51

But yeah, there might be another tool than can just connect to one — not sure.

flowthing10:08:53

I wrote this a while ago after banging my head against the wall trying to figure out the whole prepl thing: https://gist.github.com/eerohele/e06551b115c6a31d1280a115c4c2abb2 But you might be looking for something more complete.

dominicm10:08:17

That looks very useful 🙂

flowthing10:08:44

(Note that I don’t fully know what I’m doing there — some examples I found use PipedInputStream and PipedOutputStream instead of PipedWriter and PipedReader. I’m not sure how much of a difference that makes. I just wanted to come up with the simplest possible thing that works.)

dominicm10:08:24

reader/writers are character aware

flowthing10:08:26

Right, now I remember — if you use streams, you have to turn them into readers/writers anyway. So I figured I could just straight up use PipedReader instead of (io/reader (PipedInputstream.)) etc.

dominicm17:08:02

Maybe that's what I saw :)

👍 3
peter hull11:08:16

I've got a thing with a mini query language which looks like ".resistors.0.value>470" and I want to generate a callable predicate (an Ifn, I suppose) from it at run time - for example (fn [rec] (> (get-in rec [:resistors 0 :value]) 470). I'm OK with the parsing (and sanitizing) part but how do I make a function - is eval the best option? Is it safe?

vemv11:08:27

reify IFn ... seems preferable

alexmiller12:08:03

I would use eval - that’s what you’re doing

✔️ 3
alexmiller12:08:19

Otherwise you’re building an interpreter

peter hull12:08:01

Thanks both. I tried reify and got as far as (*defn* maker [op path val]   `(case op`     `:lt (reify clojure.lang.IFn (invoke [this rec] (< (get-in path rec 0) val)))`     `:gt (reify clojure.lang.IFn (invoke [this rec] (> (get-in path rec 0) val)))`     `:eq (reify clojure.lang.IFn (invoke [this rec] (= (get-in path rec 0) val)))))`

peter hull12:08:20

but seemed to be 'swimming against the tide' somewhat

vemv12:08:46

defmacro would easily DRY that code up. Alex's feedback is interesting though, OTOH I'm not sure what to make of it (compiler vs. interpreter might be perceived as merely semantics; whereas eval has practical nuances and risks)

alexmiller12:08:50

It’s not just semantics - it has big performance impacts here. Peter said earlier that he was ok with sanitizing, so I assumed those risks are being managed

alexmiller12:08:05

If not, something like clojail is designed for this

alexmiller12:08:56

The whole idea of lisp is that we can build programs as data and eval them

peter hull12:08:48

Interesting. I think I had "don't use eval" in my head from Javascript - but in JS I'd be building a string to eval, which is not as neat as Clojure/LISP's symbolic way of working.

alexmiller13:08:22

using eval is fine. using eval on arbitrary data provided by a user is dangerous, so that's the place to act carefully

alexmiller13:08:29

if you are doing any read type operation, I would either prefer clojure.edn/read-string or bind *read-eval* to false around the read to disable read-eval and arbitrary java object construction

jumar19:08:04

What's wrong with this simple approach?

(def ops
  {:lt <
   :gt >
   :eq =})

(defn maker [op path val]
  (fn [rec] ((get ops op) (get-in rec path) val)))

(comment
  ((maker :gt [:resistors 0 :value] 470)
   {:resistors [{:value 480}]}))
@U7KD4HQ1W btw. in your maker implementation you have incorrect order of args passed to get-in

peter hull07:08:58

I can't see why it wouldn't work. I believe that approach would be 'building an interpreter' as described by Alex above.

peter hull07:08:38

Re. get-in - I ought to have it tattoo'd on my knuckles, I just can't get the correct order to stick in my mind! 🙃

Daniel Schlager14:08:55

Hi! I' working with clojure.data.xml to parse a xml file. The xml elements all have an xml:id attached. How to get the value of the attribute? #:xmlns.http%3A%2F%http://2Fwww.w3.org%2FXML%2F1998%2Fnamespace{:id "3"} Thanks.

delaguardo14:08:28

https://github.com/clojure/data.xml/blob/master/src/main/clojure/clojure/data/xml.clj#L111-L130 check option available for parse-str function. :namespace-aware false could help

Daniel Schlager07:08:05

Thanks, but accordingly to the javadocs, the property "javax.xml.stream.isNamespaceAware" has True as a default value. Which means, it should work without setting it.

delaguardo08:08:34

true as a default option force parser to include namespaces into tag itself.

(parse-str "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
            <foo:html xmlns:foo=\"\"/>")
;; => #xml/element{:tag :xmlns.http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml/html}

(parse-str "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
            <foo:html xmlns:foo=\"\"/>" :namespace-aware false)
;; => #xml/element{:tag :foo:html, :attrs #:xmlns.http%3A%2F%2Fwww.w3.org%2F2000%2Fxmlns%2F{:foo ""}}

delaguardo08:08:00

try to parse xml with :namespace-aware false

Daniel Schlager08:08:42

Great. Now it works. Thanks alot!

deadghost15:08:10

Given a :foo/bar spec in my-lib, a :foo/bar spec in my-service, and my-service has my-lib as a dependency, will the my-service :foo/bar spec always shadow the my-lib :foo/bar spec?

deadghost18:08:03

Unfortunately, service spec does not always appear to shadow lib spec.

alexmiller15:08:43

which is why you should use sufficiently unique namespaces to avoid collisions

cpmcdaniel15:08:49

multi-methods can not be spec'd ala fdef, correct?

cpmcdaniel15:08:47

just making sure, as I was reading about multi-spec (implemented with multi-methods in the example) and got a little confused

ghadi15:08:35

you can make a defn that delegates to a multimethod, and spec the defn

dominicm16:08:55

Correct. They cannot.

marciol17:08:00

Hi people, I’m in a process to convince an old dinosaur about the benefits of Clojure and Datomic. This person has a lot of scars about how to scale monolithic systems using C# and SQL Server, and when I showed Clojure and Datomic he expressed the feeling that he was suffering without knowing the cause. I want to present to him at least the three best talks from Rich Hickey, that conveys the philosophic view of why Clojure is the best way to build situated programs or more generally, situated systems.

phronmophobic17:08:40

if he would prefer a written form, the HOPL paper is really good, https://download.clojure.org/papers/clojure-hopl-iv-final.pdf

marciol17:08:33

yes, the HOPL is a classic

seancorfield17:08:21

(doesn't have The Database as a Value but has others about Datomic)

parrot 3
andy.fingerhut18:08:28

Ah, looks like the last time I scrubbed the list of Rich Hickey videos against the already-published transcripts, I noticed "Database as a Value" is not transcribed yet: https://github.com/matthiasn/talk-transcripts/issues/96. Good, I'm not losing my mind completely 🙂

potetm19:08:22

Language of the System

mruzekw20:08:08

He might need the Dhammapada instead 😛

marciol23:08:03

Nice, the Language of the System will be on my list

Karol Wójcik20:08:30

Is there some library which provide enums for clojure?

hiredman20:08:16

what do you want from enums?

hiredman20:08:31

keywords are basically enums, but an open set instead of closed

hiredman20:08:19

you can create your own closed set by making a set of key words

gekkostate23:08:46

Hi all! Is it possible to exclude a namespace from :aot? Basically, one of our namespaces as a def which creates an object that spawns some threads. During aot (we believe), this def is called and as a result, lein uberjar hangs (since it’s waiting on the threads). So, the idea is that if we can skip this namespace during :aot then we can avoid the issue. What are some other approaches to a problem such as this?

phronmophobic23:08:54

leiningen allows you to specify :aot using a vector or a regex. you can either manually specify the namespaces in a vector or it might be easier to generate a regex that matches anything except the offending namespace

👍 3
alexmiller23:08:06

better would be to wrap that def in a delay and then deref when you use it

😄 6
alexmiller23:08:39

as a general rule, you should never have top-level def's that eagerly side effect on load

gekkostate00:08:40

Right, that makes sense. So, we went with the delay and it works great! Thank you!

gekkostate17:08:12

Out of curiosity, how can we achieve this without a top level def and no delay?

phronmophobic17:08:50

what are you trying to achieve?

phronmophobic17:08:06

based on your description, it seems like the spawning of threads should be kicked off from your app's main function

phronmophobic17:08:59

or if it's a library, it should probably be an function the user can call in their main to initialize the threads

gekkostate18:08:35

The issue with the introduction of the delay is that after the delay is deref-ed, we get an NPE because the threads have yet to be spawned. If we add the object creation to main then the issue is that we need to access the object in another namespace and this creates a circular dependency problem.

phronmophobic18:08:42

what if you make an init! function that spawns the threads and call that from main?

phronmophobic18:08:42

you may also benefit from something like https://github.com/stuartsierra/component

👍 3
alexmiller19:08:42

if you require things to be initialized at startup, then initialize them at startup :)

alexmiller19:08:04

even better, hand them to the things that need them, rather than storing them in defs

alexmiller19:08:23

component is one of many tools that can help you do this, but that's the important thing

👍 3
gekkostate21:08:33

So, we decided to initialize at startup and this solves the issue. I’ll check out component. Looks really cool!

Nassin23:08:52

completely avoiding AOT 😉