Fork me on GitHub
#clojure
<
2017-05-06
>
ragsboss01:05:39

hi guys I believe I found a potential bug with https://github.com/clojure/core.match

user=> (def ACTIVE true)
(def ACTIVE true)
#'user/ACTIVE
user=> (match [nil] [ACTIVE] 1)
(match [nil] [ACTIVE] 1)
1
or perhaps i may be doing something wrong.. any clues? whereas the same thing, if I use true directly works as expected
user=> (match [nil] [true] 1)
(match [nil] [true] 1)

IllegalArgumentException No matching clause:   user/eval6529 (form-init8320221599224080614.clj:1)

qqq02:05:32

@ragsboss : I am NOT a developer of core.match. However, (1) I can replicate the problem you have reported and (2) I agree with you in that I'm not expecting it to match.

ragsboss06:05:34

qqq: @qqq thank you for your input on this. I realized what I was doing wrong. The way I’m using it ACTIVE inside the match will bind to the matched value instead of what we naturally expect.. this is explained in https://github.com/clojure/core.match/wiki/Overview#Local scope and Symbols.. I found this unintuitive but not sure how to report it as I see no way to contact the authors of this package..

qqq08:05:41

@ragsboss : oh, so the point is "ACTIVE" is a global, NOT a local, thus it binds ACTIVE instead of looks up the vaule of ACTIVE ?

Oliver George12:05:00

I suspect the clojure JIRA server has a place for core.match but I can't see a solution to avoid the surprise short of improved documentation.

Oliver George02:05:15

I think the confusion is "matching literal" vs "binding"

xiongtx04:05:02

I’ve a map like:

{k1 v1
 k2 v2}
where k1 and k2 are strings and the (nonzero) values of v1 and v2 should sum to 0. Given such a map, I’d like to destructure it and bind the k for positive v to a var (call it to) and k for negative v to another var (call it from). However, either v1 or v2 could be the pos/neg value. Is there a way to do this without an if? core.{logic, unify} maybe (though that seems a bit heavy-handed)?

noisesmith04:05:57

(let [[[k1 v1] [k2 v2]] (sort-by val m)] ...)

xiongtx19:05:11

noisesmith: An elegant solution--thanks!

noisesmith04:05:50

or with the other names (let [[[from v1] [to v2]] (sort-by val m)] ...)

noisesmith04:05:55

+user=> (let [[[from v1] [to v2]] (sort-by val {:a 2 :b -2})] [from to])
[:b :a]

qqq05:05:45

(defn foo [^:bar x]
  ... is there anything I can do here
  ... which will get me the value :bar
 )

gmercer06:05:37

(defn foo [^:bar x] (prn x)) (defn get-hint [the-fn] (map meta (first (:arglists (meta the-fn))))) (get-hint #'foo) ({:bar true}) you can outside but maybe it is very unlikely whilst the var is being defined

gmercer06:05:21

i.e (defn foo [^:bar x] (let [qqq (get-hint #'foo)] (prn qqq))) won't work

qqq06:05:00

@gmercer : in summary: outside; possible inuside :not obvious how to do the (:arglists (meta the-fn)) 'trick' is realy cool

qqq06:05:06

I never thought of that; thanks!

gmercer06:05:09

@qqq see last statement of (source defn) for clues

qqq08:05:28

however, is there a book of common 'clojure patterns' ?

qqq08:05:49

I often feel when coding that I have working, but ugly code; whereas there should be some idiom that solves the problem cleanly

matan09:05:26

@qqq until such a book is written, I think you can ask for per-case suggestions here once in a while. maybe there are books about "functional programming" or "lisp" patterns not necessarily clojure ones, the number of clojure practitioners might be too small to yield books.

lsenta10:05:05

Joy Of Clojure? "Thinking the Clojure way" seem's to be the premise you're looking for @qqq

matan11:05:22

read this book several years ago, I am not sure it is the best functional patterns dictionary out there. more of a high-level tour for the simple idioms. I might be wrong of course.

matan11:05:36

in clojure, in jargon and otherwise, what are the differences between a form and an expression?

gmercer12:05:51

@qqq possibly a bit way out .. The Little Schemer - actually do the exercises in Dr. Racket, Practical Common Lisp - again Dr. Racket is your friend, How To Design Programs (Scheme) MIT Press ... these recommendations are relevant if you are referring to breaking your imperative programming habits - also watching MIT 6.001 Structure and Interpretation https://www.youtube.com/watch?v=2Op3QLzMgSY&amp;list=PLE18841CABEA24090

michaellindon14:05:16

If you were writing an user facing API for some software that you've written, and you wanted to add a verbose option, what would be the most elegant way to achieve this? My knee jerk reaction would be to litter my code with (if verbose print.... Etc but this seems messy and inelegant to me. Is there some other magic I could work with macros for instance to create verbose versions of my functions?

noisesmith14:05:41

doesn't this map directly to log levels?

noisesmith14:05:08

with the right log formatter it could work

michaellindon14:05:09

@noisesmith this looks very relevant, I haven't used or seen this before, thanks for the suggestion I'll check it out :)

oskar13215:05:15

hey everyone, I am new to clojure and STM and have a question, a ref's value is protected accross threads? that is if I have threads 1 and 2 and both execute a transaction in which they alter the same ref, one of those transactions will fail because a write was done before and retry? or is it only in a single thread? thanks a lot for your help

noisesmith15:05:52

you can't possibly have two transactions at once in one thread

noisesmith15:05:00

the point of STM is to protect data across threads

oskar13215:05:14

that's great! thanks a lot!

noisesmith15:05:20

also, in real code, we rarely need refs/transactions, usually our updates to shared state are rare enough that using an atom and the swap! function suffices

oskar13215:05:47

that was my next question, I have a very specific case in which I'm not sure if a ref is best option. Can I DM you and explain it?

noisesmith15:05:21

sure, but you can also discuss it here

oskar13215:05:06

I wish to create a course registration system that can be accessed by multiple students at the same time. So I have multiple schools which have multiple courses each. Each course has a number of available spots. Given that all the students should be able to register for courses at the same time (no matter the school), I thought that using a ref for each course should be the best option in order to avoid "overbooking of the courses" and also not blocking every course during a transaction.

noisesmith15:05:01

for something like a course, wouldn't you want the data to persist if the server restarted?

noisesmith15:05:10

this sounds more like a db thing

oskar13215:05:29

this is a personal project

oskar13215:05:35

I wish to do everything in memory

oskar13215:05:56

and mostly learn how to deal with parallelism and concurrency

noisesmith15:05:09

OK - the easier way to do this is to have an atom with a hash-map with keys for each course

noisesmith15:05:56

you can also use refs of course, but usually we don't turn to those until the contention on the atom is hurting performance

oskar13215:05:24

will try with an atom and see performance

oskar13215:05:31

then I'll try with a ref

oskar13215:05:56

thanks for your help

noisesmith16:05:11

there's very little to this, but I find it useful so I figured I'd share: it's a lein project with no code, only a few dependencies, designed to create an uberjar for running a stand alone clojure with a few favorite deps https://github.com/noisesmith/bench

noisesmith16:05:47

you probably would want a different list of static deps, but since it's a one file repo that's a pretty simple thing to fix up

paulspencerwilliams18:05:02

Can anyone offer any advice on why attempting to open a website using up to date Selenide using

(import [com.codeborne.selenide Selenide])
(Selenide/open "")
opens the website using Firefox, but after around a minute closes WebDriver down with
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeUnusedWebdrivers
INFO: Thread 20 is dead. Let's close webdriver FirefoxDriver: firefox on ANY (da9dc339-3f7f-bb4f-aeec-953fefd1bf52)
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeWebDriver
INFO: Close webdriver: 20 -> FirefoxDriver: firefox on ANY (da9dc339-3f7f-bb4f-aeec-953fefd1bf52)
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeWebDriver
INFO: Close proxy server: 20 -> null
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer$CloseBrowser run
INFO: Trying to close the browser FirefoxDriver ...
1494095275784	Marionette	INFO	New connections will no longer be accepted
[Child 5121] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2143
[Child 5121] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2143
May 06, 2017 7:27:56 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeWebDriver
INFO: Closed webdriver in 264 ms
It appears to be something about the Repl. Native Java invoking the same api works fine.

noisesmith18:05:39

how are you starting clojure?

noisesmith18:05:45

my hunch is that clojure itself is unlikely to break the tool, but something in nrepl, REPLy, or leingengen, or boot etc. is more likely to be the culprit

paulspencerwilliams18:05:13

lein repl or creating a repl using Cursive.

noisesmith18:05:23

right, and cursive is using lein

paulspencerwilliams18:05:31

lein new repl
and adding
[com.codeborne/selenide "4.4.3"]

noisesmith18:05:36

I'd try lein trampoline repl which elminates the nrepl factor

noisesmith18:05:19

and you can also try making an uberjar and running it with java -cp target/foo-standalone.jar -m clojure.main which also eliminates leinengen from the picture

paulspencerwilliams18:05:41

@noisesmith trampoline hasn’t resolved it. Will try and uberjar. Cheers!

noisesmith18:05:33

just fixed that uberjar invocation, and if the problem continues, I'd be interested to see what gdb says the program was doing around where that error happens...

paulspencerwilliams18:05:32

@noisesmith just running using ..

(ns selenium-exploration.core
  (:import (com.codeborne.selenide Selenide))
  (:gen-class))

(defn -main
  [& args]
  (Selenide/open "")
  (Thread/sleep 100000))

paulspencerwilliams18:05:04

actually, that was a

lein run
than ran for 100 seconds fine.

paulspencerwilliams18:05:56

Died invoking (-main) in the repl.

paulspencerwilliams19:05:19

Odd,

lein repl
running
(defn -main
  [& args]
  (Selenide/open "")
  (Thread/sleep (* 3 60 1000)))
loads the browser, which sits around for 4 minutes (3 minutes during Thread.sleep) and then a minute after. It always appears to last a minute after being in scope….

noisesmith19:05:55

(shutdown-agents)

noisesmith19:05:26

anything which used clojure's agent pools needs to call that to exit promptly

paulspencerwilliams19:05:30

Not following. You suggest I call this? How would shutting anything down help to keep something (the web driver or associated thread) alive? I’m new to (shutdown-agents)

paulspencerwilliams19:05:42

Unless you’re basically advising a change to keep it ‘in scope’. I’m just trying to assign the driver to an atom.

noisesmith19:05:54

oh - sorry - I mean not calling (shutdown-agents) is what makes it last another minute after that

paulspencerwilliams19:05:17

okay, that makes a bit more sense. Thank you 🙂

noisesmith19:05:54

maybe you just need for -main not to exit? if that's the case you can just do @(promise) - guaranteed not to exit

paulspencerwilliams19:05:01

Trying that, the atom attempt failed.

paulspencerwilliams19:05:30

That seems to be working.

noisesmith19:05:32

for something more sophisticated, if you have other stuff running too, you can have the main block on a promise, and then deliver to the promise when you are OK with it exiting

noisesmith19:05:24

my assumption is that Selenide is somewhere starting a thread that's set as a daemon, so that if all the non-daemon threads exit it does too

paulspencerwilliams19:05:09

So would a repl start a new thread for each command possibly?

noisesmith19:05:20

no, not at all

noisesmith19:05:33

so clearly something different is going wrong in the repl...

paulspencerwilliams19:05:16

Selenide specifically isn’t a requirement for me, Selenium that it wraps is, so I’ll try with that. Maybe Selenide adds a more complex threading model.

paulspencerwilliams19:05:06

Thanks for the help, I’ll keep digging for a while and try selenium direct.

bradford23:05:30

Is there a Ring to Netty adapter that's more up-to-date than https://github.com/RallySoftware/netty-ring-adapter ? I'm having to do some ... unsavory things