Fork me on GitHub
#clojure
<
2020-09-20
>
st3fan00:09:46

What is the Clojure equivalent of Python’s Iterable? For example say I wanted to implement “paging” in a REST API client. So that the next result set is loaded once you are at the end of a page?

rutledgepaulv00:09:07

clojure.core/lazy-seq or clojure.core/iterate are decent options for implementing such a thing. ghadi also wrote a patch to add a function called iteration that might make it into clojure.core some day

hiredman00:09:26

Lazy seqs are sort of the classic approach people have used for that kind of thing since the initial release of clojure, but lazy seqs have inherent problems managing things like connection state

👍 6
hiredman00:09:45

https://ce2144dc-f7c9-4f54-8fb6-7321a4c318db.s3.amazonaws.com/reducers.html is a at this point dated screed about using reduce based things instead, specifically there reducers, but there are core protocols and interfaces for defining reducible things

hiredman00:09:36

https://gist.github.com/hiredman/4d8bf007ba7897f11594 unfold or something like it is what I like for this kind of thing, and it is a similar kind of thing that what those patches might add to core some day

potetm00:09:45

Wait, @U0NCTKEV8. I didn’t know we were only one degree apart! I worked w/ Joe Gallo at Elastic for a minute.

hiredman00:09:07

A lot of the "past and present co-workers" from the time that was written ended up at elastic after sonian

potetm00:09:31

that’s what I hear 🙂

emccue03:09:46

@U4T7GE7PE java.lang.Iterable and java.lang.Iterator, basically. lazy-seqs and whatnot are a convenient way to implement those interfaces, but have drawbacks around chunking and resources that might end up "closed" when you leave the context the lazy-seq was created in. You can always reify an Iterator directly with whatever internal state you need if those drawbacks apply to you. Something that isn't equivalent, but can accomplish the same goal would be reducible things. Defining and using a reducible would probably lead to more idiomatic code, depending on what you are doing. https://juxt.pro/blog/ontheflycollections-with-reducible

ivana10:09:02

Maybe I'm not familiar with Python, and think that its iterables and other stuff cames from the point, that we prefer ORM than raw database queries? F.e. we have just simple sql queries with limit&offset, and make next http (and therefore sql) query on each page. Why it needed to do some more complex than it?

suren10:09:32

Hi how do we remove table name from jdbc responses? I am using postgres.

accounts/email: "email",
accounts/created_on: "2020-09-20T09:33:23Z",
accounts/last_login: "2020-09-20T09:33:23Z"
I want to just get
email: "email",
created_on: "2020-09-20T09:33:23Z",
last_login: "2020-09-20T09:33:23Z"

schmee10:09:06

what library are you using? next.jdbc?

suren22:09:21

yup its next.jdbc

Pradeep B11:09:58

Hi there !! I have recently written a clojure app using lein + compojure + clj-http and created an uberjar. Now wondering if i can enable the nrepl on the built jar file? Something like - having an api endpoint to start/stop nrepl inside the uberjar. That will help me debug issue in the built jar file when it interacts with test data. P.S.: I am doing this in my UAT environment debugging and Production will be getting rid of this (security concerns).

rutledgepaulv11:09:10

Yes, by adding code to your app that starts an nrepl server when you hit your api endpoint and then connecting to that nrepl server with your local client. https://nrepl.org/nrepl/usage/server.html#embedding-nrepl

Pradeep B11:09:38

thanks @U5RCSJ6BB i am trying that only currently.

Pradeep B12:09:57

it is stuck in compiling while running lein uberjar

Pradeep B12:09:44

following is how code looks like - one route added to call the start-nrepl method

Pradeep B13:09:07

found the silly mistake in my code (calling (start-server server) and (defonce server) also contained the same command 😞 . Fixed it now and able to do it.

stephenmhopper12:09:57

Is it possible to use something like with-redefs except swapping out entire namespace definitions?

teodorlu12:09:27

Hi! Is there something like add-watch on the namespace level, so that I can subscribe to when vars on a namespace are added / changed, etc?

teodorlu12:09:24

Follow-up: Can I watch for redefinitions with (def ...)? add-watch seems to pick up only redefinitions with alter-var-root. I assume that's because def creates a new var instead of changing the previous var.

Daniel Tan12:09:06

cljsrn seems abandoned

Daniel Tan12:09:20

anyone can point me to a more updated resource on making ios apps with clojure?

Daniel Tan14:09:03

@teodorlu it works! 🎉

👍 3
Daniel Tan14:09:11

spend way too much time finding one that works

Gleb Posobin16:09:33

1. I do lein new test-project, create a file src/user.clj with content

(ns user
  (:require [clojure.java.shell :refer [sh]]))

(sh "ls")
2. Now when I do lein repl, it hangs on the sh call. If I remove the call and just do (sh "ls") in the repl, it works fine. Why?

Gleb Posobin17:09:11

3. If the :init-ns is set to user2 and the file above is changed to be user2 ns, it doesn't hang anymore.

andy.fingerhut17:09:06

I tried reproducing the hanging behavior following the steps you gave above, but do not get any hanging behavior. Nor does it load that namespace named user, either, when I do lein repl. I am using this version of Leiningen and JDK, in case that might make any difference:

$ lein version
Leiningen 2.9.3 on Java 1.8.0_192 Java HotSpot(TM) 64-Bit Server VM

andy.fingerhut17:09:20

Actually, I guess it does load that namespace named user, but it is not obvious because (sh "ls") does not print anything. If I change it to (println (sh "ls")), then run lein repl, it does print the return value before starting the REPL.

Gleb Posobin17:09:24

Updating clojure from 1.10.0 to 1.10.1 fixed this!

andy.fingerhut17:09:53

Hmm. I was testing with Clojure 1.10.1. There were some changes in Clojure 1.10.1 to fix some bad performance issues with loading user.clj with some JDK versions: https://github.com/clojure/clojure/blob/master/changes.md#11-workaround-java-performance-regression-when-loading-userclj

Gleb Posobin17:09:35

I am using OpenJDK 14, which is not mentioned there. I also had a problem before with cognitect's aws library where it would hang if loaded from the namespace, but worked ok if loaded from a function after startup, I guess that's the same problem.

andy.fingerhut18:09:19

If a change from Clojure 1.10.0 to 1.10.1 makes a difference, and it is is code in a file named user.clj in your classpath, then likely it is the performance issue I linked to. JDK 14 wasn't explicitly mentioned there at the text I linked to, probably because it wasn't released yet at the time the note was written. I would expect that if the issue exists in JDK 11, 12, and 13, it is likely to be common JDK code that interacts poorly with Clojure 1.10.0 that continues on into JDK 14 and probably later versions, too.

Gleb Posobin18:09:22

Yeah, makes sense.

Pradeep B19:09:34

@UQ4RJ22EA you should try babashka maybe.

Gleb Posobin19:09:07

This interop with sh is not my primary goal, one of the libraries I am using was preventing the repl from starting and I tried to find the reason why.

🆗 3
nickt18:09:51

Hey folks, is it possible to generatively define functions in a given namespace? For example, I have a function (defn createNode [type props] ...dostuff...) and for a known set of types, I would like to create aliases in my namespace. That is, I might write (createNode "myNode" {:hi "bye"}), but I would like to alias (myproj/myNode {:hi "bye"}) to invoke the previous form. I have a list of these types... "myNode, myOtherNode, coolNode," etc

nickt18:09:28

Sketching out what I'm imagining...

(doseq [i ["myNode" "myOtherNode" "coolNode"]]
  (make-alias i (fn [props] (createNode i props))))

nickt18:09:11

I imagine a macro could do this?

Gleb Posobin18:09:13

I think you are looking for intern: https://clojuredocs.org/clojure.core/intern

👍 1
Gleb Posobin18:09:29

It should be (intern 'myproj (symbol i) (fn [props] ...)).

Gleb Posobin18:09:08

Found thanks to hugsql, it generates functions from an sql-like file, and fills a namespace with them. https://github.com/layerware/hugsql/blob/master/hugsql-core/src/hugsql/core.clj#L500

nickt18:09:40

yesss thanks @UQ4RJ22EA!

👍 3
João Galrito22:09:45

Hello everyone, started learning clojure a few weeks ago, can I pick someone's mind on a project I'm working on?

seancorfield00:09:17

@U01AYHBG413 Welcome! If you're just getting started with Clojure, ask lots of questions in the #beginners channel -- that's where folks have opted in to helping new Clojurians and you'll find lots of willing minds to pick there.

seancorfield00:09:19

If you have questions about specific libraries, there are likely library-specific channels where you can ask those questions (e.g., #sql for database stuff, #honeysql #hugsql for specific ilbraries, #ring #component #integrant #hiccup etc -- some of them can be pretty quiet but that means there's also more chance that an expert can help there).

João Galrito00:09:28

@U04V70XH6 thank you. I'd say I'm past the beginner phase. In this case I'm looking for an opinion and some tips/suggestions on a project I'm working on. Mainly if my approach and use of the language is sound

João Galrito14:09:56

@U3JH98J4R are you familiar with the Magic: the Gathering TCG?

emccue14:09:56

(more into yugioh, but I've played magic a few times)

João Galrito14:09:39

so, I'm building a MTG compiler

João Galrito14:09:15

it reads through the card text and generates clojure code to be executed later by a rules engine

João Galrito14:09:19

i have a parser that reads though the text and generates a Parse tree

João Galrito14:09:27

then I traverse that parse tree to generate code

João Galrito14:09:11

each node of the parse tree is represented by an object of class Parser$<RuleName>

João Galrito14:09:04

so I created a "visit" multimethod that dispatches on the class of the node being visited

João Galrito14:09:49

created a few convenience macros as well

João Galrito14:09:14

for example, here's the part that generates code for an effect that applies to a game object

João Galrito14:09:33

(defrules
   effectObjectEffect `(~@(visit-rule objectEffect) ~(visit-rule object)))

João Galrito14:09:03

my plan is to then later either AOT compile the generated code

João Galrito14:09:12

or have it interpreted by the game engine

João Galrito14:09:55

(or both, that will probably be the case)

emccue15:09:16

so, generally speaking you will have a better time if you design a data structure to represent the parsed effects

emccue15:09:25

and then have a function interpreret that data structure

emccue15:09:51

than generating code in macro

emccue15:09:21

its usually an antipattern to do a defthing macro

emccue15:09:26

there are a lot of side benefits - being able to test your code and maybe even persist parsed rules to a file

emccue15:09:14

but generally speaking "data structure describing complex behavior" is preferred over "object which encapsulates complex behavior"

3
💯 3
João Galrito19:09:57

well, in this case I wanted to take advantage of the "code = data" property of lisps

João Galrito19:09:15

the code itself is a data structure that represents the parsed effect

João Galrito19:09:25

and the interpreter is the JVM itself

João Galrito19:09:52

how is that different from outputting maps (for example) and having an interpreter execute that

João Galrito19:09:18

also why would this approach prevent me from doing any of the things you said (testing, persisting rules)?

João Galrito19:09:47

I know it might sound like I made up my mind already, but I really want to understand if and why I might be looking at this the wrong way

João Galrito19:09:41

maybe I didn't explain myself correctly

João Galrito19:09:58

I'm not outputting the game engine logic itself

João Galrito19:09:29

for example, if an effect is "Destroy target creature" the generated code might be something like (destroy (target {:type :creature}))

João Galrito19:09:56

then in my game engine I'll implement the destroy and target functions that do their thing on the game state

João Galrito20:09:29

also another advantage is that I'm able to get some static analysis on the generated code because I'm referencing functions from the game engine

João Galrito20:09:35

also code suggestion/documentation in the IDE

emccue13:09:35

Hmm, so for the testing bit (sorry for the late response)

emccue13:09:30

if your rules are just a data structure, you can test your parsing logic via just (is (= (parse-card text) {:destroy {:target {:type :creature}}}

emccue13:09:11

you can reasonably macro expand and test code is what you expect as well, but its harder to test a "slice" of it, partially by the linked-listedness of generated code but also because it can be pretty fragile to changes

emccue13:09:19

you are right that you can potentially generate, dump, and load+eval code though - I didn't consider that seriously enough

emccue13:09:13

so if security isn't an issue then it would probably work - it just is a large surface area for code injection