Fork me on GitHub
#clojure
<
2018-11-20
>
jaawerth00:11:21

@cureadvocate there may be others, but I think https://github.com/clojure/math.numeric-tower has functions that deal nicely with the various numeric types

stephenwithav00:11:19

ty, jaawerth. I didn't think that worked for BigInteger, but it does. Yay!

yiwan02:11:59

any one get graal native-image working with clojure spec?

currentoor04:11:34

Is it possible to find out if a value is serializable? Like is there an interface/protocol serializable values implement?

Alex Miller (Clojure team)04:11:43

What do you mean by serializable?

Alex Miller (Clojure team)04:11:29

Java has a Serializable interface but not sure if that’s actually what you want

currentoor05:11:45

@alexmiller encodable to transit-json

orestis10:11:34

Transit allows you to specify your own serializer for any value.

currentoor05:11:50

thanks for responding!

didibus06:11:39

@jesse.wertheim There's some hidden gems under the clojure/ umbrella, that I think would benefit from more publicity. Like data.avl, data.priority-map, core.memoize, algo.generic, math.combinatronics, core.match, etc.

didibus10:11:48

How do you get the reference to an object? Say I want to know the reference to 10 ?

didibus10:11:56

As opposed to its value

didibus10:11:32

Hum, I guess maybe its not possible in Java to do that

didibus10:11:39

This is as close as it gets (System/identityHashCode [1 2])

andy.fingerhut12:11:27

@didbus I believe I once found a low level method to get the current address/pointer to an object in Java, but realize that such a value can change on every GC, and the times of GCs are unpredictable.

andy.fingerhut12:11:50

It looks like I experimented a few years ago briefly with a library called jol for "Java Object Layout" here: https://openjdk.java.net/projects/code-tools/jol/ It has a method VMSupport/addressOf that can return the current address of an object, after doing (:import (org.openjdk.jol.util VMSupport)). Note: I do not all the possible caveats of this method or what all might go wrong with it, but there is at least the issue that the value can change on every GC.

mseddon13:11:42

is there a way I can ask clojure to reload data_readers.clj from the repl?

athos14:11:52

I don’t know if there is a straight way to do it, but this should work:

(set! *data-readers* (into *data-readers* (map (fn [[tag f]] [tag (resolve f)])) (read-string (slurp ( "data_readers.clj")))))

mseddon15:11:50

Ah, yeah, of course, thanks!

borkdude14:11:52

Trying this example from https://clojuredocs.org/clojure.core/re-groups

(def phone-number "")
(def matcher (re-matcher #"((\d+)-(\d+))" phone-number))
(re-groups matcher)
According to the example it gives ["672-345" "672-345" "672" "345"] but I get:
Execution error (IllegalStateException) at java.util.regex.Matcher/group (Matcher.java:536).

borkdude14:11:03

what’s wrong here?

borkdude15:11:34

seems like you have to call (.find matcher) first

andy.fingerhut15:11:40

I get same error with Clojure 1.9.0 and JDK 1.8.0_192. Not clear to me yet whether that ever worked, or is changed behavior.

borkdude15:11:04

I tested all the way back to 1.1.0. maybe they changed something in Java?

Alex Miller (Clojure team)15:11:10

user=> (doc re-matcher)
-------------------------
clojure.core/re-matcher
([re s])
  Returns an instance of java.util.regex.Matcher, for use, e.g. in
  re-find.

andy.fingerhut15:11:18

Doubtful. More likely that the example never worked

Alex Miller (Clojure team)15:11:21

^^ designed for use with re-find

borkdude15:11:59

alright, I’ll edit the example 🙂

Alex Miller (Clojure team)15:11:41

user=> (re-find matcher)
["456-3212" "456-3212" "456" "3212"]

andy.fingerhut15:11:27

@borkdude Interested in correcting the example on http://ClojureDocs.org?

Alex Miller (Clojure team)15:11:31

then after that, you can:

Alex Miller (Clojure team)15:11:40

user=> (re-groups matcher)
["456-3212" "456-3212" "456" "3212"]

borkdude15:11:47

oh wait, it calls re-find on it first. I figured yes

Alex Miller (Clojure team)15:11:53

but it requires you to have previously called re-find, yes

andy.fingerhut15:11:42

Java Matcher objects are mutable.

andy.fingerhut15:11:50

so call sequence is important.

borkdude15:11:23

this stuff doesn’t exist in clojurescript (re-groups, re-matcher)

andy.fingerhut15:11:42

ClojureScript regex's probably have some way to get multiple "capture" substrings from a single regex match, or at least most regex libraries nowadays do, but I haven't looked. Just surprised if it doesn't enable that functionality.

borkdude15:11:04

That requires a global regex in JS and that’s generally avoided

Alex Miller (Clojure team)15:11:39

you may have heard that mutable objects are bad :)

andy.fingerhut15:11:53

make a table of tradeoffs 🙂

borkdude15:11:21

yeah. I’m writing a spec for re-groups now, that’s why I bumped into this. never actually used it

borkdude15:11:07

@andy.fingerhut interestingly via writing a spec for subs, I got into this: https://dev.clojure.org/jira/browse/CLJS-2979

borkdude15:11:37

no trade off there, only fix + speedups 😉

andy.fingerhut15:11:48

Is that ClojureScript-specific behavior, perhaps?

andy.fingerhut15:11:15

Just checked that Clojure/JVM throws exception on (subs "" 1) as I would have expected, although the exception message contains -1 instead of 1 which is a bit weird, but at least the exception is there.

andy.fingerhut15:11:39

Simultaneous fix + speedup for the win!

andy.fingerhut15:11:56

Does it make much sense to write a spec that checks return values of functions that take and modify mutable objects? I would guess that would be fraught with trouble.

borkdude15:11:47

I do it for completeness sake. you can unstrument it if you want.

mpenet15:11:08

good or bad: function/var names with : ? ex: find-thing:source-a find-thing:source-b (no I don't want/need to use a multimethod, it's just a naming thing here)

mpenet15:11:39

ok, that's clear, the reader doc states something different I think

Alex Miller (Clojure team)15:11:00

I didn’t say it was invalid

mpenet15:11:04

> Symbols beginning or ending with ':' are reserved by Clojure. A symbol can contain one or more non-repeating ':'s.

mpenet15:11:29

yeah I saw it recently during a review and I was wondering

mpenet15:11:56

understood

borkdude15:11:25

isn’t that how they namespace things in common lisp?

mpenet15:11:37

cider highlighting doesn't like it much

borkdude16:11:52

yay, I can now see the return “type”:

user=> (doc re-groups)
-------------------------
clojure.core/re-groups
([m])
  Returns the groups from the most recent match/find. If there are no
  nested groups, returns a string of the entire match. If there are
  nested groups, returns a vector of the groups, the first element
  being the entire match.
Spec
  args: (cat :matcher :speculative.specs/matcher)
  ret: (or :string :speculative.specs/string :seqable :speculative.specs/seqable-of-string)
nil

roklenarcic16:11:23

hm lein uberjar seems to completely ignore that some dependencies are marked as scope "compile" or "provided"

noisesmith17:11:53

is this clojure artifacts that are in compile / provided scope while doing aot / gen-class ?

noisesmith17:11:40

because that could lead to a situation where the source jar for the clojure code isn't in the uberjar, but the compiled result of the dep is - aot is transitive

john18:11:10

Dispatching on specs: (defpoly jump (partial s/valid? dog-spec) [animal-obj] ...) 😉

borkdude18:11:45

what’s defpoly?

seancorfield18:11:46

@borkdude I think that's @john’s predicate dispatch stuff?

john18:11:50

Yeah, I'm not beholden to the defpoly name

martinklepsch19:11:46

I'm curious to learn more about deploying a single-process Clojure app with zero downtime. Not sure if that qualifies as blue-green deployment but something in that direction. Are there any tools to make this easy? How did you solve this?

noisesmith19:11:25

if you're insane you could use tools.namespace/refresh and hot load the new code in the prod process

😂 8
dominicm21:11:13

@U050TNB9F fwiw, we do this on the JUXT website...

noisesmith21:11:37

and this works out for you?

dominicm06:11:25

About 1s of downtime

noisesmith19:11:49

I think the real answer is usually some variant of load-balancing and service discovery

☝️ 4
noisesmith19:11:10

which would not be different between clojure and another language as I understand it?

didibus19:11:52

Single process? Like you mean given one and only one process?

didibus19:11:31

Normally you have a fleet of hosts, and you rotate them in and out as new changes are deployed

martinklepsch19:11:31

I was thinking that perhaps there's something particularly easy to setup. Currently I'm just running a systemd process and nginx reverse proxying to a hardcoded port.... so service discovery and swapping processes sounds like it'll require a lot more components...

noisesmith19:11:00

right - to limit downtime you need multiple processes (at least for a minute or two at a time)

noisesmith19:11:12

and then load balancing or service discovery to make the swap seamless

martinklepsch19:11:33

> Normally you have a fleet of hosts, and you rotate them in and out as new changes are deployed Yeah, that particular app doesn't follow an "immutable infrastructure" style approach where you just cycle entire nodes (the node is stateful)

martinklepsch19:11:52

Right multiple processes for the transition time would be expected.

noisesmith19:11:14

I think this is part of why people end up using things like redis and kafka - to pull the stateful stuff out of the apps

noisesmith19:11:15

at @dayjob we use kafka to accumulate runtime state, then marathon to manage app instances, and the kafka topics are a mechanism of service discovery of sorts

didibus19:11:19

A statefull node? Like in memory state inside the process? Or disk persistence?

martinklepsch19:11:39

disk persistence

martinklepsch19:11:14

Yeah, definitely agree with the general motivation of having state in separate services but the project is OSS and I want to keep setup as easy as possible in the interest of contributors (using SQLite at this time)

didibus19:11:40

Ok, well, you can probably pull it off if you can dynamically change the nginx port. You could start a new process on a different port and then do the port swap, and then kill the old process.

noisesmith20:11:08

what about abstracting the sql layer, so people can use eg. postgres for seamless roll over, or sqlite for simplicity?

martinklepsch20:11:42

yeah this would be an option but not managing a DB process is also nice and something I guess I'm still reluctant to give up

noisesmith20:11:22

docker does tend to make this stuff easier - but that has some things you need to opt in to of course...

hiredman20:11:58

you might also look at something like envoy, likely overkill but I suspect doing the swap in envoy would be easier than in nginx

martinklepsch20:11:05

have a link to envoy? I assume you don't mean amperity/envoy?

didibus20:11:55

> NGINX configuration is captured in configuration files. When you change a configuration file and restart NGINX to pick up the new configuration, it implements a “graceful restart”. Both the old and new copies of NGINX run side by side for a short period of time. The old processes don’t accept any new connections and terminate once all their existing connections terminate.

noisesmith20:11:59

oh - so you could roll over nginx with an alternate port config

didibus20:11:13

Seems like that could work

martinklepsch20:11:46

I'm also looking at Caddy which seems like a nice reverse proxy with automatic HTTPS: https://caddyserver.com/docs/proxy It supports an upstream option that can be a port range... > try_duration is how long to try selecting available upstream hosts for each request. By default, this retry is disabled ("0s"). Clients may hang for this long while the proxy tries to find an available upstream host. This value is only used if a request to the initially-selected upstream host fails.

didibus20:11:36

Anyways, I think you got the gist

martinklepsch20:11:07

I did, thanks for your suggestions 🙂