clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
st3fan 2020-09-20T00:13:46.131200Z

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?

2020-09-20T10:03:02.134700Z

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?

rutledgepaulv 2020-09-20T00:19:07.131400Z

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

rutledgepaulv 2020-09-20T00:19:11.131600Z

https://clojure.atlassian.net/browse/CLJ-2555

st3fan 2020-09-20T00:22:14.131900Z

Thank you

2020-09-20T00:22:26.132100Z

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

👍 2
2020-09-20T00:27:45.132700Z

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

2020-09-20T00:33:36.132900Z

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

2020-09-20T00:48:45.133100Z

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

2020-09-20T00:57:07.133300Z

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

2020-09-20T00:58:31.133500Z

that’s what I hear 🙂

emccue 2020-09-20T03:39:46.133700Z

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

suren 2020-09-20T10:20:32.135600Z

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"

schmee 2020-09-20T10:30:06.135800Z

what library are you using? next.jdbc?

Pradeep B 2020-09-20T11:12:58.139500Z

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

rutledgepaulv 2020-09-20T11:18:10.139600Z

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 B 2020-09-20T11:20:38.139800Z

thanks @rutledgepaulv i am trying that only currently.

Pradeep B 2020-09-20T12:00:57.140Z

it is stuck in compiling while running lein uberjar

stephenmhopper 2020-09-20T12:02:57.140900Z

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

Pradeep B 2020-09-20T12:04:44.141Z

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

teodorlu 2020-09-20T12:27:27.142900Z

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?

2020-09-20T12:34:06.143100Z

cljsrn seems abandoned

2020-09-20T12:34:20.143500Z

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

teodorlu 2020-09-20T12:48:24.143600Z

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.

teodorlu 2020-09-20T13:11:44.144200Z

@danieltanfh95 perhaps Krell: https://github.com/vouch-opensource/krell

Pradeep B 2020-09-20T13:18:07.144500Z

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.

2020-09-20T14:26:03.145100Z

@teodorlu it works! 🎉

👍 1
teodorlu 2020-09-21T07:03:00.173400Z

Great!

2020-09-20T14:26:11.145400Z

spend way too much time finding one that works

2020-09-20T14:26:12.145700Z

thanks!

Gleb Posobin 2020-09-20T16:47:33.155700Z

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 Posobin 2020-09-20T17:07:11.157400Z

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

2020-09-20T17:39:06.158400Z

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

2020-09-20T17:43:20.159600Z

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 Posobin 2020-09-20T17:46:24.160Z

Updating clojure from 1.10.0 to 1.10.1 fixed this!

2020-09-20T17:47:53.161100Z

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 Posobin 2020-09-20T17:51:35.162700Z

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.

nickt 2020-09-20T18:00:51.165700Z

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

nickt 2020-09-20T18:03:28.165900Z

Sketching out what I'm imagining...

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

nickt 2020-09-20T18:12:11.166100Z

I imagine a macro could do this?

2020-09-20T18:23:19.166300Z

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 Posobin 2020-09-20T18:29:22.166500Z

Yeah, makes sense.

Gleb Posobin 2020-09-20T18:29:28.166700Z

Thank you!

Gleb Posobin 2020-09-20T18:31:13.166900Z

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

Gleb Posobin 2020-09-20T18:32:29.167100Z

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

Gleb Posobin 2020-09-20T18:35:08.167300Z

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

nickt 2020-09-20T18:35:40.167600Z

yesss thanks @posobin!

👍 1
Pradeep B 2020-09-20T19:13:34.168300Z

@posobin you should try babashka maybe.

Gleb Posobin 2020-09-20T19:18:07.168500Z

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.

🆗 1
João Galrito 2020-09-20T22:31:45.170300Z

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

João Galrito 2020-09-21T14:03:56.184400Z

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

emccue 2020-09-21T14:04:18.184600Z

yep

emccue 2020-09-21T14:04:56.184800Z

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

João Galrito 2020-09-21T14:18:39.185Z

so, I'm building a MTG compiler

João Galrito 2020-09-21T14:19:15.185200Z

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

João Galrito 2020-09-21T14:20:19.185400Z

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

João Galrito 2020-09-21T14:20:27.185600Z

then I traverse that parse tree to generate code

João Galrito 2020-09-21T14:21:11.185800Z

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

João Galrito 2020-09-21T14:22:04.186Z

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

João Galrito 2020-09-21T14:22:49.186200Z

created a few convenience macros as well

João Galrito 2020-09-21T14:24:14.186400Z

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

João Galrito 2020-09-21T14:24:33.186600Z

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

João Galrito 2020-09-21T14:25:03.186800Z

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

João Galrito 2020-09-21T14:25:12.187Z

or have it interpreted by the game engine

João Galrito 2020-09-21T14:26:55.187200Z

(or both, that will probably be the case)

emccue 2020-09-21T15:22:54.187600Z

hmm

emccue 2020-09-21T15:23:16.187800Z

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

emccue 2020-09-21T15:23:25.188Z

and then have a function interpreret that data structure

emccue 2020-09-21T15:23:51.188200Z

than generating code in macro

emccue 2020-09-21T15:25:21.188400Z

its usually an antipattern to do a defthing macro

emccue 2020-09-21T15:27:26.188600Z

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

emccue 2020-09-21T15:28:14.188800Z

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

💯 1
➕ 1
João Galrito 2020-09-21T19:33:57.209900Z

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

João Galrito 2020-09-21T19:34:15.210100Z

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

João Galrito 2020-09-21T19:34:25.210300Z

and the interpreter is the JVM itself

João Galrito 2020-09-21T19:34:52.210500Z

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

João Galrito 2020-09-21T19:49:18.210800Z

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

João Galrito 2020-09-21T19:53:47.211100Z

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 Galrito 2020-09-21T19:57:41.211300Z

maybe I didn't explain myself correctly

João Galrito 2020-09-21T19:57:58.211500Z

I'm not outputting the game engine logic itself

João Galrito 2020-09-21T19:58:29.211700Z

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

João Galrito 2020-09-21T19:59:56.211900Z

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

João Galrito 2020-09-21T20:49:29.212100Z

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 Galrito 2020-09-21T20:53:35.212300Z

also code suggestion/documentation in the IDE

emccue 2020-09-24T13:18:35.025500Z

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

emccue 2020-09-24T13:19:30.027600Z

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

emccue 2020-09-24T13:20:11.028300Z

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

emccue 2020-09-24T13:22:19.030600Z

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

emccue 2020-09-24T13:24:13.031700Z

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

suren 2020-09-20T22:41:21.170400Z

yup its next.jdbc