Fork me on GitHub
#clojure
<
2016-07-31
>
ezmiller08:07:58

how would i wait for an i/o operation in clojure? i’m used to javascript, where we’d use a promise or callback. not sure how to proceed in this case.

yonatanel08:07:24

@ezmiller: which io operation? Do you use any library for that? Do you want your program to run other calculations while io is running or can you just block everything until it returns?

ezmiller09:07:36

pretty simple case here. i want to import a rather large csv. once it is imported i will do some manipulations, and then return the result in fn. the io problem is that this is a server sending content to a client, so i don’t want to return until the data is prepared.

ezmiller09:07:50

I’m using the http://clojure.java.io and clojure.data.csv libraries.

yonatanel09:07:40

@ezmiller: without getting into which server you're using and how long your operation takes, I can only say that these IO calls are blocking (unlike node.js) so code lines will be executed synchronously in order. You don't have to use promises or async libraries

ezmiller09:07:37

Fyi, I’m working with the preconfigured server that comes with the reagent base project.

ezmiller09:07:11

All pretty new to me, so I’m not sure what packages that means, but it seems to rely on libraries called ring and compojure.

pesterhazy10:07:47

@ezmiller: depending on your you case, you may be able to just slurp a url or file

pesterhazy10:07:13

hi ethan by the way 🙂

mpenet11:07:56

The latest ring has async handlers

mpenet11:07:11

It s probably in the latest compojure, if not it s possible to explicitly depend on it

mpenet11:07:07

But that doesnt make csv parsing async, either your lib supports it or you need to wrap the op in a future like context

pesterhazy11:07:51

people in the clj world generally eschew asynchronicity unless there's a compelling reason for it

akiroz13:07:19

or rather JS (& friends) are the only ones with async everywhere because they only have 1 thread so blocking calls usually isn't an option.

lvh14:07:36

Asynchrony can be a powerful force for helping you not hide some I/O in the middle of a function that would be much better pure, though.

lvh14:07:37

As an extreme example, Haskell (sans unsafePerformIO) forces you to do that with its type system. Whether or not that’s as a whole desirable is a different question, but it definitely produces the same pressure.

lvh14:07:34

I think that’s interesting because it raises a point about languages where the type system does not enforce that, like Clojure; is synchronicity only easier because you get to hide IO in places? (Consequently, is not hiding IO in places intrinsically better?)

lvh14:07:49

I think the answer to both is “yes”, but I am an async nerd, so probably biased 🙂

lvh14:07:33

(Sorry, I buried the lede there a little bit: that is interesting because you don’t have to care if the IO is performed synchronously or asynchronously in Haskell.)

lmergen14:07:23

@lvh: i think that your assessment is correct, and this is a tradeoff that is made. haskell is more strict, and allows you to enforce a lot of things at compile time, while clojure mostly relies on runtime checks. honestly, as a fellow async nerd, i think the async situation in clojure needs to be solved, because it is simply too easy for people to make mistakes. but i don’t see a good solution either, that doesn’t introduce additional complexity.

lvh15:07:22

I like manifold a lot, but it definitely has the same problem as Twisted did in Python, that is, there are people who don’t use it

lvh15:07:32

Manifold’s focus on interop is important to remedy that a little bit though

mpenet15:07:23

well there's no magic bullet. imho clj async situation is just fine, and I don't think it's discouraged in general, it's more that it's misused very often

mpenet15:07:04

ex: ppl using the async part of a web server to later do blocking io in handler via some db driver

mpenet15:07:27

if you do it right clojure has everything to offer

mpenet15:07:35

well, libs at least

lmergen15:07:44

@lvh: for what it’s worth, juxt’s new web library yada uses aleph (which is based on manifold), and it’s slowly starting to move into the right direction

lvh15:07:55

yep; big fan of yada

lmergen15:07:09

great, me as well — probably not a coincidence

lmergen15:07:16

i think the problem with clojure’s async is that it isn’t enforced

lmergen15:07:23

all languages that are great at async, enforce it

lmergen15:07:39

there is no async-first mentality, which makes sense for the majority of the situations

mpenet15:07:43

appart from js I dont' see any other really

mpenet15:07:58

erlang doesn't really enforce it

mpenet15:07:08

ex: cast/call

mpenet15:07:26

the fact that everything is signals between processes yes, but it's a different thing imho

lmergen15:07:39

well you can get away with sync behavior in those languages, but what i mean is, that there is no way in clojure to tell “this function must be implemented async"

lmergen15:07:44

in other languages, it is possible

lmergen15:07:52

that’s what i meant with enforcing

mpenet15:07:09

it's possible too in clj, nothing prevents it imo

mpenet15:07:20

sure the default jdbc driver will probably be blocking

mpenet15:07:34

but you can find alternatives

lmergen15:07:43

well, async is just a second class citizen in the whole jvm world in general

lmergen15:07:00

anyway, this is slowly starting to become #offtopic material 🙂

mpenet15:07:30

I happen to work with a stack that's mostly async for the rest backend part, and very happy with it

mpenet15:07:50

we also have bits in erlang actually, but not really because of to the async "situation" in clojure, mostly because it's a better fit for some of our needs

lmergen15:07:30

yes you are right about that, when used by a team of disciplined developers, it’s easy to pull it off in clojure, but you have to start using non-standard libraries

lmergen15:07:36

(ring doesn’t work very well, for example)

mpenet15:07:04

there's actually a new ring version with async handlers in the works (it's in beta right now I think)

mpenet15:07:39

but yeah, the adoption by the "standards" like ring is slow, but core.async on the other hand has been here for a while for other contexts

mpenet15:07:07

jetty9 for instance has had async from the beginning, it was just a bit the wild west until now, many adapters, many mistakes etc. But manifold/aleph should be solid, it is/was used very heavily by some serious players

lmergen15:07:50

well, that’s the thing, rather than enforcing certain behavior from the standard, a new standard is added

lmergen15:07:06

this seems to be a common theme in clojure, and i’m not sure whether i like it

lmergen15:07:38

in haskell it seems to be much more common to just break things and let the community fix it

mpenet15:07:10

well haskell async ecosystem isn't much different from clojure's

mpenet15:07:19

there's a bit of everything, and no real standard

mpenet15:07:25

from what I recall

mpenet15:07:27

then again having choice is good imho (no matter the platform)

yonatanel16:07:35

Any suggestions on how to coerce one nested data structure to another? I can't for the life of me understand Prismatic Schema coercion, so maybe a good tutorial? Can it be done with pattern matching?

pesterhazy16:07:56

@yonatanel: can you be more specific?

Petrus Theron17:07:37

Clojure web apps: how are people sanitising/coercing input values into correct types, e.g. numbers/dates? prismatic/schema?

pesterhazy17:07:41

@petrus: input coming from html forms?

Petrus Theron17:07:57

Compojure :params

Petrus Theron17:07:06

or from API calls

pesterhazy17:07:51

I do it manually :)

(defn parse-long [s]
  (try
    (Long/parseLong s)
    (catch NumberFormatException e
      nil)))

pesterhazy17:07:59

if you do it a lot, it may be worth using something like https://github.com/metosin/compojure-api

gfredericks17:07:12

I used prismatic/schema coercions for a while

gfredericks17:07:30

they're good for what they try to do

akiva17:07:55

@petrus, I do what @pesterhazy did and wrote my functions manually.

radon17:07:55

Is there an easy way to get a sub-vector of a primitive array?

(subvec (vec "Hello") 1 4) => [\e \l \l]
(??? (char-array "Hello”) 1 4) => [\e \l \l]
Or should I just cast to a PersistentVector and back? (This is in the context of reifying a java.io.Writer.)

gfredericks17:07:24

I'd be surprised if you can

Alex Miller (Clojure team)19:07:04

JVM doesn't support that afaik

Alex Miller (Clojure team)19:07:42

You can use System.arrayCopy() though

ezmiller22:07:40

I’ve got a function:

(defn get-col-as-vec
  [col-key]
  (mapv #(get-cell-val % col-key) (range (count data))))
The data in question is 80000 rows about. It takes about a minutes or so to run. Anyone know how I can speed this up?

spei22:07:24

are you trying to get columns? you could try transposing the data first.

ezmiller22:07:30

@spei: yes, i am. what does transposing mean? not familiar.

spei22:07:44

yes, the

(apply map vector coll)
should transpose your data so that you can get at the columns easily. not sure if it's faster though

ezmiller22:07:18

will give it a shot @spei thanks.

radon22:07:35

@ezmiller: If you’re trying to do huge matrices fast, you should probably be using something like https://github.com/mikera/core.matrix. Pure Clojure vectors are really slow.

radon22:07:48

You want m/array to create a core.matrix matrix from whatever you started with (obviously don’t do this for every column you retrieve, but store your matrix this way), and m/get-column for getting the column. Indexing is m/mget.