Fork me on GitHub
#clojure
<
2018-01-19
>
noonian02:01:13

Are there performance implications (other than startup time) for running applications with the cli as opposed to an uberjar? Is the cli a reasonable way to run a program in production?

kenrestivo03:01:36

how to do deploy a jar? let me count the ways

kenrestivo03:01:02

running in cli as uberjar from shell script. running in tomcat as a war. applogic. hell, could be anything

kenrestivo03:01:14

running as lein run. sky's the limit

noonian04:01:12

Sorry I was unclear. By cli I mean the recently released clojure and clj programs and the tools.deps library https://clojure.org/guides/deps_and_cli

seancorfield04:01:44

@noonian Yes, we run a number of processes in production by just running clojure.main and specifying the entry point with all the dependencies available.

seancorfield04:01:03

We're mostly moving to uberjars these days, primarily for ease of managing the build/deploy process, but we've done source deploys for years,

Alex Miller (Clojure team)04:01:54

clj and clojure (other than the building of the classpath) nothing more than running java -cp $COMPUTED_CLASSPATH clojure.main my.main

seancorfield04:01:47

(and works with both source deploys and with uberjars)

Alex Miller (Clojure team)04:01:49

if it’s an uber jar then you don’t need clj at all as the classpath is … the jar

Alex Miller (Clojure team)04:01:20

clj -Spath can be used to just print the classpath, suitable for echoing into a file and using directly too

Alex Miller (Clojure team)04:01:39

so there are many ways to assemble these pieces

seancorfield04:01:00

We were using Leiningen to run stuff at first, then we switched to Boot. If clojure / clj had been available, we'd likely have used that.

seancorfield04:01:12

(now we just use java -jar ... 🙂 )

noonian04:01:04

Yeah, thats how I do it 🙂 I’ve been playing with deps.edn and I’d like to avoid bringing in lein or boot just to build an uberjar. I haven’t found a focused tool that will explode+combine jars to create an uberjar though

seancorfield05:01:00

clj is not a build tool -- that's what lein and boot are for. Why try to reinvent that?

noonian06:01:48

I’m just experimenting. I’ve been enjoying https://github.com/juxt/mach and I’m exploring using it as the primary build tool for some projects. It makes it very easy to leverage shell commands as well as cljs via lumo/node and supports building incrementally. I am happy to leverage existing tooling but I’d prefer to avoid another file in my project just to specify the jar build. Boot may be the answer here since it has pretty good command-line support (therefore easily invoked from mach) but I haven’t used it enough to know how that will work

Victor Ferreira04:01:27

someone can help me? I want filter my arraymap based on your key-value like this: I want check if in anyone position had :key with value "test" if my input are it [{:key ["test" "123"]} {:key ["test2" "123"]}] they will return true and if my input are [{:key ["tesasdasdat" "123"]} {:key ["teasdasst2" "123"]}] my function will return false how can I do it with filter?

nathanmarz04:01:42

@victtorferreiralima with specter it's (selected-any? [ALL :key ALL (pred= "test")] data)

noonian04:01:17

@victtorferreiralima you might checkout the #beginners channel. Here’s one way you could implement that function:

(defn has-key?
  "Check if the vector returned by (:key m) has key as an element."
  [key m]
  (seq
   (filter (partial = key) (:key m))))

(seq
 (filter (partial has-key? "test")
         [{:key ["tesasdasdat" "123"]} {:key ["teasdasst2" "123"]} {:key ["test" "123"]}]))

qqq09:01:12

I have a function, which maps a list, then applies a function to it. It is defined as:

(fn [mf af]
  (fn [lst]
    (apply af (map mf lst))))
now, the arg order can be eithe mf af or af mf I'm trying to figure out if I should name the function fam or fma argument for fam -- shows the order of (apply af (map mf lst)) argument for fma -- we are mappuing first, then we are applying I realize this sounds pedantic -- but anyone have advice on this ? [ one point of confusion is that people say "map reduce" all the time, but in clojure, it'd definitel be (reduce rf init (map mf lst)) ]

sundarj09:01:09

surely you could call that a sequence function, and so it can follow the argument order of every other sequence function, including map, which it is built upon (collection last)

qqq09:01:31

I don't know what a 'sequence function' is, but my inspiration is: https://en.wikipedia.org/wiki/Function-level_programming so I'm trying to build functions that: * take functions as arguments * returns other functions as arguments

qqq09:01:06

also, under 'sequence function' standards, which order would thsi be? f-apply-map or f-map-apply ?

sundarj09:01:55

i thought you were asking about the argument order, not the name

carkh09:01:21

that's aside the point but : surely af should take a collection since its parameters are regular enough to be mapped over ? It's very rare that we encounter such a function that makes sense (like the + function)

qqq09:01:45

@sundarj: I think I misunderstood your comment. Is your comment: "I'm not saying whether it should be f-apply-map or f-map-apply, but I'm saying that instead of (apply af (map mf lst)) it should be (af (map-mf lst))" ?

sundarj10:01:11

my comment was merely about the argument order. sorry about the confusion

qqq10:01:45

There's an abstraction here I want to write. I have no idea what the right way to write it is -- so if you're noticed a flaw that I did not even think of, I'd greatly appreciate you pointing it out.

sundarj10:01:56

in Clojure, every sequence function follows a consistent argument order: collection last

sundarj10:01:51

map, filter, reduce, group-by, partition, you name it

sundarj10:01:24

i was merely suggesting you keep with that convention, so that it integrates well with the existing standard library

sundarj10:01:25

how you name it and implement it is up to you, i make no comment on that aspect

qqq10:01:30

Ah, so instead of (fn [af mf] (fn [lst ...)) you are suggesting: (fn [af mf lst] ..) ? Is your argument: "instead of a 2-arg function which returns a function that takes an arg, it should be a 3-arg function with list as the third arg" ?

sundarj10:01:42

well if you don't want/need it to return a function, that would be my suggestion - if you do, i think it's fine to leave it as-is

qqq10:01:34

understood; thanks for sharing your perspective

sundarj10:01:55

it is worth noting that you could easily turn the [af mf lst] version into the function-returning version by using partial

sundarj10:01:58

but you cannot do the reverse with the function-returning version

qqq10:01:37

(fam af mf lst) -> ((fam af mf) lst) I think the "extra char used" is shorter than partial 🙂

sundarj10:01:44

if concision is a concern, you could use the #() syntax: (#(fam af mf %) lst)

qqq10:01:08

lol, I asked one design question, and now I have two design questions to resolve

sundarj10:01:23

the [af mf lst] version is more versatile, is what i'm saying 😛

sundarj10:01:34

sorry about giving you more questions than answers

carkh09:01:50

i find that i get quickly mired in conversions between apply and collections when i start using variadic functions

qqq09:01:54

yeah, I get confused all the time too

qqq09:01:31

@carkh @sundarj: if you don't mind, can either of you write the function in the way you consider most 'clojure idiomatic' ? I think I'd learn more from seeing it as how you would write it rather than as a 'patch' vs what I wrote

sundarj10:01:06

if you need it to return a function then i would say what you've written is plenty idiomatic

carkh10:01:18

> (defn afunc [mf af lst] (apply af (map mf lst)))
#'ping.cards.sqlite/afunc
> ((partial afunc inc +) [1 2 3])

carkh10:01:27

I think there is no added value to your closure, you're not closing over anything worth closing over

qqq10:01:45

Understood; thanks!

carkh10:01:07

> ((partial transduce (map inc) +) [1 2 3])
9
not quite it but close

carkh10:01:55

(->> [1 2 3] (map inc) (reduce +))
that's the one i prefer

carkh10:01:17

the intent is clear

sundarj10:01:13

function version would be (comp #(reduce + %) #(map inc %))

sundarj10:01:21

or #(->> % (map inc) (reduce +)), i suppose

pfeodrippe13:01:14

What's the clojure equivalent of

GenericAvroSerde.class
, maybe
(class GenericAvroSerde)
?

sundarj13:01:28

i think it's just GenericAvroSerde

pfeodrippe13:01:52

@sundarj Yes, I tried this before and again now... it works, the problem was with some dependency and it's solved now. Thanks!

qqq13:01:45

is there a builtin for #(%1 %2) ?

bronsa13:01:08

I mean, deliver has that exact implementation

bronsa13:01:13

but it’s an implementation detail

bronsa13:01:17

it’s not made for that

qqq13:01:22

is there a good name for such a function? (to avoid nested #%'s)

qqq13:01:46

lol, I like ap

qqq13:01:00

maybe I will call it appy, because it is missing the 'list component

bronsa13:01:01

@qqq ap is what monadic invoke is called in e.g. haskell

timgilbert15:01:12

Say, what's the distinction between (io/file "f") and (io/as-file "f")?

borkdude15:01:24

Is fill-paragraph from emacs available in some clojure string lib?

Alex Miller (Clojure team)15:01:37

@timgilbert as-file is the low-level protocol function for coercing something into a file

borkdude15:01:47

scanned through https://funcool.github.io/cuerdas/latest/ but couldn’t find it

Alex Miller (Clojure team)15:01:12

@timgilbert io/file is a higher-level op that takes N parts, coerces them all to files, and makes a file out of the result

Alex Miller (Clojure team)15:01:23

generally you want io/file

borkdude15:01:45

io/file rocks, it also adds platform specific delimiters to a filename: (io/file “foo” “bar” “baz”) ;;=> “foo/bar/baz” on linux, “foo\bar\baz” on windows

Alex Miller (Clojure team)15:01:32

well it returns a File, so technically there are no delimiters till you convert the File to a string path

Alex Miller (Clojure team)15:01:42

but when you do that, it uses the platform delimiter

borkdude15:01:06

well yeah, but I use it for that sometimes 🙂

borkdude15:01:43

boils down to the convenience that it supports varargs, unlike the Java File

Alex Miller (Clojure team)15:01:31

really that + the auto coercion so that you can munge together Strings and Files are the two things that make it really useful

matan16:01:38

Haven't been around for a while in clojure-world. Congrats for version 1.9

matan16:01:50

Any specific plans for 1.10 already? 🙂

Alex Miller (Clojure team)16:01:49

nothing to share atm. 1.10.0-alpha2 was actually released today, but really just some initial dev work, nothing worth being interested in yet.

johnj17:01:53

what would be the idiomtic way of this function: (defn bundle [n s] (when (seq s) (cons (apply str (take n s) (bundle n (drop n s)))))

johnj17:01:33

(defn bundle [n s]
  (when (seq s)
    (cons (apply str (take n s))
          (bundle n (drop n s)))))

johnj17:01:46

it takes a list and a number , produces a list of n chunks from the input list

johnj17:01:33

user=> (bundle 3 '(a b c d e f g))
("abc" "def" "g")

notid17:01:37

something like this?

(defn bundle [n s]
  (->> (partition-all n s)
       (map #(apply str %))))

notid17:01:02

partition-all does the ‘bundling’ part

johnj17:01:07

Ok, I must really sit down and learn all those functions 🙂

johnj17:01:51

Is the reason 'take' returns a lazy-seq because you might want to lazily take again from 'take'?

johnj17:01:16

a lazy-seq instead of a seq

stathissideris20:01:07

is it the case that you can’t :refer-clojure :exclude set! and redefine it in your namespace because it’s a special form?

sundarj20:01:28

that is correct

stathissideris20:01:12

any good synonyms? 😄

noisesmith20:01:26

for reference, it’s possible to find this out programmatically

=> (special-symbol? 'set!)
true

stathissideris20:01:13

thanks that’s useful!

sundarj20:01:19

@U050AACJB perhaps assign!?

stathissideris20:01:34

it’s actually wrapping some interop, the previous name is set-field! but I think it’s a bit too lengthy

sundarj20:01:14

i actually like set-field!

stathissideris20:01:20

yeah, maybe it’s not too bad

sundarj20:01:28

or maybe set!*

sundarj20:01:36

bit strange perhaps

stathissideris20:01:23

I’m going for fset!, thanks 🙂

Andy20:01:07

Hi, I am looking for a idiomatic solution for retry and reset. Something like com.grammarly/perseverance or robert/bruce or listora/again with an extra kick. I have an I/O depending on a connection maintained in atom which might fail and needs to be reestablished. However non of those libraries with awesome semantics otherwise does not let me have an extra "callback" to make it happen ... I wonder if a solution for my problem already exists ...

noisesmith20:01:40

@happy.lisper is there any state in the connection? eg. when you read are you assuming a position in the input? or is the connection something stateless that’s always usable if it’s open?

Andy20:01:58

it the later

noisesmith20:01:08

@happy.lisper often it makes sense to isolate code that deals with the connection and its IO semantics from the code that is determining what to read and write. This is easiest to do via a pair of queues (for input and output) - then you have one thread which uses the queues and manages the connection and reads/writes, and the other code can ignore all that stuff

Andy20:01:08

In my case, it is a DB connection I perform a mutable operations. It sometimes goes bad and I do not know until I do perform I/O on it. Then retry has to happen including reestablishing connection itself.

noisesmith20:01:34

OK, if you isolate the IO from the rest of your code, it’s just a question of tracking pending / attempted / completed messages, and if some problem happens it should just be a question of separating completed from attempted and redoing the attempted, then starting on pending - by using a queue you only need this restart logic in one place, instead of needing it in everything that provides data

Andy20:01:17

yes, and I was wondering if somebody captured that pattern in a library, similar to com.grammarly/perseverance or robert/bruce or listora/again...

noisesmith20:01:05

it’s not an error, as long as you use clojure.main to launch your code

noisesmith20:01:21

if you want java to find a main class other than clojure.main, you need to establish something to be aot compiled

hiredman20:01:04

@happy.lisper that sounds pretty much exactly what people use connection pool libraries for

hiredman20:01:21

c3p0 is common one used for sql

Andy21:01:23

it is not really a pool, as I deal only have one connection which occasionally goes bad. I think I will redirect my inquiry to aforementioned lib owners ... thx for taking a look

hiredman22:01:21

a pool isn't just about managing multiple of thing, it is also about reusing that something

hiredman22:01:11

one way to deal with your issue would be to create a new connection every time you do something, so you put open and close logic around every use

hiredman22:01:31

but creating a new connection each time can have downsides as well, so you keep the open/close logic around each use and replace it with taking and returning the connection from a pool, and each time you take the object from the pool, you can check if it is still good

bfabry22:01:20

connection pooling libs also deal with reconnecting connections that go bad

Andy01:01:11

but they do not deal with an automatic reconnect and retry on a specific failed operation

qqq22:01:17

map :: for == ??? :: doseq ?

qqq22:01:42

cool! I was thinking mapv, but https://clojuredocs.org/clojure.core/run%21 is definitely better

andy.fingerhut23:01:47

I added run! as a "See also" for map on clojuredocs. It wasn't already there.