Fork me on GitHub
#clojure
<
2017-07-06
>
hiredman00:07:25

buffering is going to mask any problems with feedback you have

dealy00:07:26

ok, just got a big burst, it looks like I'm not blocking when I publish, the pre/postpublish log messages are all within the same millisecond

hiredman00:07:32

it sounds like you are interfacing regular thread using code and core.async, and my bet is you are either using put! to publish or (async/go (>! ...)), when you should be using >!!

noisesmith00:07:22

Also, go blocks can die without visible feedback or error messages, you could just get backed up as consumers silently fail.

dealy00:07:23

yes, I'm using async/go >!

hiredman00:07:44

the question is how you using it

dealy00:07:48

its funny but every example of pubsub I came across did it this way

hiredman00:07:24

if you create a go block from a normal thread, you should wait for its result using <!!

hiredman00:07:09

I mean, I am kind of guessing here and what are likely to be issues

hiredman00:07:42

I still think it is some kind of issue with your topic-fn, but you have assured me it isn't

qqq00:07:07

is identical? guaranteed to be an O(1) time pointer comparison

hiredman00:07:28

if the publishers aren't actually blocking, all the symptoms point to a disconnect between pub and sub, the likely reason is the result of topic-fn isn't what you think

hiredman00:07:25

so I might do something like replace the topic fn with (constantly 1) make a channel subbed to 1, and verify it is getting all the traffic

dealy00:07:59

@hiredman ok, but I think based on what @noisesmith was saying is that my usage of go (>! ...) could be the prob

dealy00:07:51

literally all of my topics are the same {:transformer-event :ev1 or :ev2 or ev3}

hiredman00:07:23

definitely, like I said, "if publishers aren't actually blocking" if they are blocking and you just can't tell, or they are just dying, then that would be your problem

dealy00:07:10

cool, I'm gonna change my publish to use >!! and see how that affects the situation

hiredman00:07:48

>!! is really blocking, not for use in go blocks, only for use on real threads

dealy00:07:12

yea I took out the go block

dealy00:07:38

doesn't seem to be making any different behavior

hiredman00:07:01

your producer threads are still not blocked?

dealy00:07:08

I have a log message before the publish and another after, and they are always within a millisecond

dealy00:07:18

doesn't look blocked to me

hiredman00:07:10

are you sure those aren't spurious log messages coming from threads left running from a previous attempt?

dealy00:07:13

valid question, I'll restart the whole shebang

dealy00:07:10

this is really puzzling to me.

dealy00:07:32

given that I'm not buffering what are the scenarious that would cause events to be dropped?

hiredman00:07:21

well, you could think events are being published when they are not, because your producers are just blocking. the topic-fn could be returning something you are not subscribed to so messages get dropped, or your subscribers do get the messages and just don't do anything

dealy00:07:40

givent that I only have 1 publication on one channel there should be no pub log messages that are publishing into nothing

dealy00:07:53

there are however of course several sub channels and loops

hiredman00:07:17

are you sure you are subscribing to the same pubsub you are publishing to?

dealy00:07:20

ok, now i'm finally seeing some blocking

dealy00:07:51

I see several pre publish logs, with no coresponding post publis logs

hiredman00:07:15

right, that blocking is back pressure being communicated back from the downstream async bits, which are stuck where or going really slow

hiredman00:07:37

are the down stream bits re-publishing to the same pubsub?

dealy00:07:45

no thats part of this whole business I've never been too clear on. I have no logic for re-publishing

dealy00:07:49

by downstream bits are you referring to the sub handlers?

hiredman00:07:06

yes, things downstream of the pubsub

dealy00:07:46

oh, well my sub handler loops publish on to the sub channels, is that what you mean?

dealy00:07:00

the sub channels are obviously differnt than the pub channel

hiredman00:07:14

that could be the source of deadlock

hiredman00:07:47

whenever you have a feedback loop (a process that feeds output back in to its input) it is really easy to deadlock

hiredman00:07:27

since the sub channels don't have a buffer, publishing to them blocks until someone else consumes from them

hiredman00:07:17

depending on what you are doing, adding a buffer might fix it, or might not, because a buffer is fixed in size, and if you feedback more than the size of the buffer, you are deadlocked again

dealy00:07:53

ok let me get this straight, my listener loops take off of the sub channel

dealy00:07:16

the clojure publisher logic puts on to the sub channel based on the topic-fn

dealy00:07:51

all of my sub loopse run forever taking from the sub channels and then calling a handler

dealy00:07:45

I think you're saying if my sub loops get stuck then that could be causing the deadlock, like handler never returning I guess

hiredman00:07:35

if you are calling a function that never returns that is another problem

hiredman00:07:45

you cannot do that kind of thing from a go block

dealy00:07:48

that would all make sense if the whole thing locked up and never recovered, but that doesn't happen

hiredman00:07:57

it will block the threadpool go blocks use

dealy00:07:00

no I don't thnk I'm calling a function that runs forever

dealy00:07:06

I'm not seeing anything like that

dealy00:07:30

if my handlers got stuck the whole system should eventually lock up, and that never happens

hiredman00:07:59

or if they run slow, or if they do blocking stuff on the async threadpool

dealy00:07:14

the handlers can be slow compared to the publishers, when there is lots of activity, they all run in their own go blocks

hiredman00:07:34

you are ddosing the async threadpool

dealy00:07:14

too much activity for the go blocks that the handlers are in?

hiredman00:07:24

I dunno about too much

hiredman00:07:54

it sounds like everything is behaving as designed, feedback is slowing your publishers to a rate that matches the consuming

dealy00:07:15

well except for the lost events

dealy00:07:23

that I still don't understand

hiredman00:07:29

in this case, the processes reading from the sub channels aren't able to get time on the threadpool to run

hiredman00:07:56

are you sure they are lost? or are they just waiting to run in a completely backed up system

dealy00:07:13

you see the thing is, my publishers are bursty, there are short periods of busy activity and long periods of relative calm,

dealy00:07:49

given that the system never locks up, all events should eventually be handled in the calm period, but that isn't what is happening.

dealy00:07:29

aggh, I'm gonna have head home soon, thanks for being a sounding board on this pub/sub stuff

hiredman00:07:12

you might want to look at one of the pipeline variants, it may simplify things a lot

dealy00:07:19

I didn't even know about pipelines, something new to learn tomorrow I guess

dealy00:07:58

cool, thanks, have a good evening (or what ever timezone appropriate part of day is appropriate)

joshjones03:07:46

@qqq if you didn't already look at the source a few hours ago, yes, identical? is just:

static public boolean identical(Object k1, Object k2){
	return k1 == k2;
}

kurt-o-sys07:07:54

Trying to flatten a nested map to a 'referenced nested map':

{:a1 {:b1 "val1" :c1 2}
 :a2 {:b1 "val2" :c2 {:d1 3}}}
to
[{<0> {:a1 <1> :a2 <2>}
  <1> {:b1 "val1" :c1 2}
  <2> {:b1 "val2" :c2 <3>}
  <3> {:d1 3}]
<n> being some value, doesn't really matter a lot - just a number would certainly do.

pseud08:07:03

I am somewhat bewildered by core-async terminology. pipeline is for computation (non-blocking all the way), pipeline-async is for "async" operations which seems to be operations which may park the statemachine and pipeline-blocking is used for straight up blocking ops. I am mostly confused about ´pipeline-async`. Am I right in assuming: * (#A1) some operations, say (a/<! (a/timeout 3000)) - would park for approximately 3 seconds - so operations like it (take from a channel) are OK inside of pipeline-async. * (#A2) the reason the af fn in pipeline-async receives a channel onto which the result should be delivered is because I can then easily wrap a typical callback-style async operation by letting the callback put a message onto this result channel ?

gmercer08:07:07

@tjscollins this might be better .. I think you need OAuth2 for google and this repo has a google example https://github.com/craygo/clj-oauth2/blob/master/src/clj_oauth2/google.clj

pseud12:07:23

No one has some thoughts / can confirm/deny my assumptions mentioned above ?

noisesmith12:07:03

@pseud the purpose of the chan passed to af is to allow N results (0 or more) onto to from each call too af

noisesmith12:07:06

Otherwise it would have to build and return a collection.

qqq16:07:52

@joshjones: (re identical? being pointer equality check) -- nope, haven't read source yet; thanks for checking for me 🙂

rinaldi18:07:09

Is there a exports.default equivalent (from Node.js) for Clojure? Use case, I have a file called config that loads an EDN file, parse it and store it to a variable called config. Whenever importing it I have to config/config which looks... Weird.

hmaurer18:07:55

@rinaldi what about refer? (require 'my-app.config :refer [config])

rinaldi18:07:52

@hmaurer Thanks, that could work. However, I am also exposing two other variables on this file that I later want to reference too. As far as I understand, with your solution, I would only be able to refer to the config variable and nothing else.

hmaurer18:07:24

@rinaldi you can add any number of variables/function in the vector after :refer

rinaldi18:07:43

@hmaurer Oh I see, let me try that.

hmaurer18:07:37

@rinaldi actually I got the syntax a bit wrong. It’s (require '[my-app.config :refer [config]])

noisesmith18:07:41

@rinaldi another thing to consider is that since good clojure style is to use the namespace prefix, you can use a name that isn’t redundant with the prefix

noisesmith18:07:46

for example if the ns were environment so it was environment/config and the other things in the ns were environment related but not the config data itself, or if the var were settings, so it’s config/settings and the rest of the ns is about things that are about config but not the specific settings

hmaurer18:07:48

@noisesmith is using :refer bad clojure style? I am new to clojure so I don’t really know

noisesmith18:07:31

@hmaurer it’s OK in moderation - but there’s a reason nobody writes ns forms with :use any more

rinaldi18:07:17

Since it only exposes 3 public vars for now, I'm going with :refer

noisesmith18:07:39

that’s the most I’d want in a client ns period

noisesmith18:07:48

not just from one ns - from all combined

hmaurer18:07:57

@noisesmith :use is an order of magnitude worse though, right? it just refers everything

noisesmith18:07:09

right, but it’s a matter of degree not kind

rinaldi18:07:27

@noisesmith What if I have a library that exposes a bunch of stuff but I just need a few of them. Still the best practice is to go with namespaces instead of using :refer and :only?

noisesmith18:07:31

unless you are using the function extremely frequently

rinaldi18:07:33

But :as would still load everything from that file into memory no?

noisesmith18:07:41

that has nothing to do with it

noisesmith18:07:51

all :as does is create an alias in your ns

bfabry18:07:59

the whole file is compiled and loaded into permgen regardless of how you refer to it

noisesmith18:07:11

not using :refer is not about memory usage, it’s about poluting a namespace with bindings that are irrelevant

rinaldi18:07:11

Gotcha, that's nice to know. Thanks.

noisesmith18:07:15

it’s about code readaiblity

rinaldi18:07:47

So I don't really see a use case for anything other than :as (perhaps only :use because can be handy on the REPL)

noisesmith18:07:02

yup - that’s almost always the right way to do it

bfabry18:07:13

yeah tht's the general consensus that's emerged

noisesmith18:07:15

but there are exceptions eg. if every function in your ns is using >! from core.async

noisesmith18:07:19

that makes sense to refer

dpsutton18:07:26

notable exceptions deftest and is

noisesmith18:07:55

@dpsutton yeah, to me that’s the same exception - every form in my test ns uses deftest once and is multiple times

noisesmith18:07:08

so it’s ubiquitous enough to drop the prefix

dpsutton18:07:32

for sure. i'm a big fan of the namespaced functions. common lisp gets difficult to read because of that. also emacs-lisp...

noisesmith18:07:53

it’s another flavor of the same problem overuse of inheritance causes - “where the hell is this name defined?”

noisesmith18:07:21

but inheritance tends to get into a worse state because it’s so common to rebind the same names

sundarj18:07:49

i quite like these principles

spieden18:07:04

i actually alias clojure.test, mostly to get completion and automatic require in cursive

bfabry19:07:34

yeah cursive actually makes :use/:refer even less appealing

dpsutton19:07:32

oh can it not suggest things that aren't in the current namespace if they don't have an alias?

souenzzo19:07:12

I'm writting a macro that transform a keyword into a symbol This symbol will be used on a (def ~symbol ...) There is a "default" way to normalize :foo.bar/quoo to a valid symbol?

csm19:07:55

(symbol (namespace kw) (name kw))?

noisesmith20:07:25

def can’t take namespaced symbols though

csm20:07:27

yeah, probably just munge the ns & name into a string, separated by some other string, if the namespace is important

souenzzo20:07:22

@csm I need a local symbol. Some like foo_bar__quoo

noisesmith20:07:40

if it needs to be “local” why is it going in a def?

noisesmith20:07:44

perhaps I misunderstand what you mean by local here, but by the standard clojure definition, def doesn’t and can’t be used to create locals

souenzzo20:07:14

(my-cool-macro :about.this/keyword [some cool dsl]) macro-magic> (def about_this_keyword :result-of-my-macro)

noisesmith20:07:38

That addresses the question, that doesn’t do anything with locals as clojure defines them. But given that in order for the macro to work :about.this/keyword needs to be a literal, why not just provide the symbol directly?

souenzzo20:07:27

noisesmith: because I'm talking about a a keyword. I will generate a rule for clara. Dynamic symbols will cause difficulties on debug

noisesmith20:07:13

what I am saying is that the macro won’t work unless the keyword is a literal in the form

noisesmith20:07:29

a symbol as a literal in a macro that becomes a binding does not cause any debug difficulties

noisesmith20:07:29

do you mean the keyword literal is the same as a keyword that gets used elsewhere?

bfabry20:07:53

@dpsutton no it suggests them fine, it just feels more useful when it narrows it down to a specific alias

dpsutton20:07:08

ah yeah. easier to browse

dpsutton20:07:22

CIDER has a browse namespace feature which is really nice

seako20:07:54

hello, i’m trying to take a sqlvec like

["SELECT * FROM ? WHERE (? = ? AND ? = ?)"
 "Aliens"
 "WritesPoetry"
 "True"
 "TheirPoetryIsGood"
 "False"]
and convert it into a sql string usually, i would be content with this as clojure.java.jdbc accepts this. but in my current situation i am communicating with AWS Athena which accepts a string representing a sql query.

bfabry20:07:12

replace ? with '%s' and [...] with (format ...)?

seako20:07:27

that would certainly do the trick

seako20:07:01

but sufficient to prevent against malicious input?

bfabry20:07:38

definitely not 🙂

seako20:07:34

therein lies the rub

bfabry20:07:36

if athena doesn't have prepared statements then you'll need a function that escapes sql in a manner that's safe for athena

hiredman20:07:39

the ? after FROM isn't actually valid jdbc if I recall either

hiredman20:07:09

jdbc, or all the jdbc drivers I have used, don't let you parameterize the table name

hiredman20:07:37

apparently the .toString method on a prepared statement for some jdbc drivers will give you the sql string

hiredman20:07:22

athena also has a jdbc driver, so you could just use that

seako20:07:57

as it turns out athena does have a jdbc driver

seako20:07:59

happy days

seako20:07:46

thanks all, much appreciated

cjhowe20:07:44

what clojure libraries exist for desktop ui's? is there anything like re-frame for clojurefx? not really interested in electron

cjhowe20:07:30

i found a lot of things that are out of date.... looking for something that's been maintained

tbaldridge20:07:26

@cjhowe I maintain fn-fx, but to push it much further we need users. Not a whole lot of people trying to do JavaFX with Clojure

tbaldridge20:07:14

That being said it's React for JavaFX and works fairly well for "normal" apps, the rough edges are around things like animation.

joelsanchez20:07:10

hi, just a quick question, how do you do comment blocks? do you just put a string inside (comment)?

cjhowe20:07:38

@tbaldridge i see... well, i'm a student trying to build a portfolio, so this seems like an interesting area that clojure could improve on... do you know if javafx is popular in the java world?

val_waeselynck20:07:40

@joelsanchez #_(this block is commented)

joelsanchez20:07:21

ok, i see, thanks!

tbaldridge20:07:25

@cjhowe there aren't a lot of Java desktop apps, but JavaFX is a really nice platform. It's fast, GPU accelerated, and the API is very uniform. Infact the vast majority of fn-fx is auto-generated code created by the library introspecting on the JavaFX API.

cjhowe20:07:14

@tbaldridge sounds interesting, i'll check it out! thanks

dpsutton21:07:08

@joelsanchez "comment block" is a little ambiguous. do you just want a block of comment text (like a multiline comment) or do you want to comment one or more sexp's?

bfabry21:07:03

@mbjarland without going too far into it, your filter example is lazy and your transducer example isn't, and you're only taking the first result. so the comparisons are going to be a bit meaningless

val_waeselynck21:07:12

@mbjarland are you sure of your measurements? The above benchmark code looks very questionable

bfabry21:07:09

also without showing what year-dirs-only-xf is defined as we can only really guess as to what's happening

joelsanchez21:07:17

@dpsutton yes, most of my project is commented like that but it's a little bit of a pain

dpsutton21:07:27

not sure which editor you're in, but most should have some way to format a long single comment

dpsutton21:07:37

what is the pain point in using the language's comment syntax?

joelsanchez21:07:03

it does not bother me to use it, it bothers me to write ;; all the time when i am writing it

dpsutton21:07:47

i'll bet cursive will do it for you

dpsutton21:07:59

but if that's what you prefer go for it

joelsanchez21:07:19

i'll try to activate something in cursive for that, because right now it does not

bfabry21:07:27

@mbjarland: ok then yes it looks like it's pretty much because your latter example is lazy and your format example is not

mbjarland21:07:41

@bfabry was trying to not spam the channel with too much code. Any easy way to keep the composability of transducers but stay lazy and fast?

dpsutton21:07:55

don't enter newlines? i'll bet the autoformatter takes care of it for you

bfabry21:07:42

if the situation/algorithm benefits from laziness my first instinct is to say "don't use transducers there"

joelsanchez21:07:50

doesn't look like it @dpsutton , there's an option to auto-wrap at the 80-columns limit but i don't want that for code, i will ask in the cursive channel

mbjarland21:07:52

@bfabry is non-laziness inherent for transducers or is it just the way I use them?

bfabry21:07:46

I believe so, one of the reasons that they're faster (in situations where laziness isn't a benefit) is because they don't have the overhead of keeping track of unrealised computations

noisesmith21:07:31

it’s a lot simpler to enumerate the things that are lazy (there’s very few), and sequence is the only built in lazy thing using transducers and I forget the details but saw it explained that sequence was sub-optimal in important was compared to other lazy functions

noisesmith21:07:40

a transducing function just transforms a single result, so would hardly benefit from laziness, a transducing context can be lazy or not (and sequence is the only lazy built in transducing context)

mbjarland21:07:43

@bfabry @noisesmith thanks, I will go back and meditate some more on transducers and laziness…

wei21:07:44

is there a way to access the value of the default ring memory store atom from the repl?

michaellindon21:07:49

(* 3 (/ 1 3))
=> 1N
I am confused why I would get a BigInt here

michaellindon21:07:44

is there a design choice which made the return value a BigInt and not an Int?

hcarvalhoaves21:07:21

@michaellindon

user=> (type (/ 1 3))
clojure.lang.Ratio

michaellindon21:07:05

ah ok, thank you

alex-glv22:07:15

@joelsanchez

#_(this s-exp will be entirely ignored)
?

joelsanchez22:07:03

@alex-glv yes, someone told me about that macro, thanks anyway

alex-glv22:07:43

Didn't realise where my scrollbar was at the time, too early 😉

matan23:07:47

Any book (or blog) recommendation, specifically for clojure concurrency? I've spent some time today wrangling atoms, agents, add-watch and promises, for managing a work queue. It has been a nice drill. I'm undecided what's the best queue management technique and might suspect clojure.async or even some Java implementation might be more performant/safe.

matan23:07:58

Maybe someone's written a book I'm not seeing about that?

tjscollins23:07:04

@gmercer Thanks. That second did the trick.

arthur23:07:10

one of these two expressions looks wrong to me:

user>  (* 2.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001M 1.0)
2.0
user>  (* 2.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001M 1.0M)
2.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010M

arthur23:07:37

are bigdecimals special in being coerced to a less precise type in * ?

hiredman23:07:23

user=> (.doubleValue (BigDecimal. "2.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"))
2.0
user=> 

hiredman23:07:44

basically, fixed precision floating point numbers are dirty and their dirtiness will contaminate any math they are used in

hiredman23:07:45

1.0 in that expression is a fixed precision float (a jvm double), and that is what causes weirdness

hiredman23:07:38

clojure, encoded as a big honking class file, has rules about how you convert types to do math operations, and doubles as a type dominate pretty much everything, meaning if you have doubles in your expression, internally numbers that are not doubles are going to be turned in to doubles when doing math

arthur23:07:13

so long as it's done on purpose i guess