Fork me on GitHub
#clojure
<
2018-03-13
>
didibus00:03:57

Which I think is a safe use of eval, but its unclear

pablore00:03:43

If I have a bunch of futures in a list, is it a good idea to (map deref) on it to wait for everyone? Or is there a better way?

mfikes00:03:55

@pablore Perhaps (run! deref futures) to avoid map laziness

pablore00:03:54

@mfikes yeah that look better than composing doall and map

mfikes00:03:35

If you just want to wait, and aren't going to consume the future values as a result of the map call, yeah run! is about as succinct as it can get

pablore00:03:15

run! doesn't return the value from the futures though

pablore00:03:36

I'm concatenating them all and then writing the result to a file, but it may be better for each future to write to the file since order doesn't matter...? Or may it cause problems if I do that?

noisesmith00:03:57

if they are in futures for performance reasons, consider that writing to a file might be the slowest part

pablore00:03:44

So I did it, I scraped the entire MTGMarket website for card names and their price. Each future was meant to deal with one specific page of a giant table.

xiongtx01:03:54

Is :gen-class’s :methods still the only way to add annotations to methods, as shown here: https://github.com/clojurebook/ClojureProgramming/blob/master/ch09-annotations/src/main/clojure/com/clojurebook/annotations/junit.clj It’d be nice if the annocations can be added to the functions instead…

noisesmith01:03:58

@xiongtx functions aren't methods, they are objects that extend IFn (which has an invoke method and applyTo)

noisesmith01:03:23

@xiongtx you can make an annotated method without a gen-class, but then you need something that defines a method (eg. reify, proxy, defrecord ...)

xiongtx01:03:22

@noisesmith What I’m wondering is if, by using :gen-class, I have to add the annoations in the :gen-class bit, like:

(:gen-class
 :name foo.bar.WithdrawalApprovedTest
 :methods [[^{cucumber.api.java.en.Given {:value #"^a withdrawal is in the DB$"}}
            a-withdrawal-is-in-the-db [] void]])
Or whether the annotation can be added to the function instead.

noisesmith01:03:45

what would you annotate on a function?

noisesmith01:03:14

if you need an annotated method, you can't use a function for that - you don't have control over how function objects create methods

xiongtx01:03:22

Hmm, yeah, that makes sense. Then :gen-class doesn’t know anything about the function until it looks it up, so annotations on the function can’t inform :gen-class, I suppose.

noisesmith01:03:27

the gen-class ends up creating a stub method that just uses the function, and it won't use annotations on the function (even if you figured out how to put it here)

noisesmith01:03:42

as far as I know at least

didibus01:03:38

I'll go ahead and use the eval, resolve seems harder, since it can't work with locals and non symbols

seancorfield02:03:50

@xiongtx I've written (Java) annotated functions in Clojure for New Relic agent tracing... let me get the blog post about that...

xiongtx03:03:32

:thumbsup:, I’ll take a look

seancorfield02:03:06

I used definterface and deftype to create a framework in which to place annotated methods.

xiongtx03:03:21

When using :extends in a :gen-class, is there a way to access fields of the extended class?

misha13:03:41

greetings! is https://github.com/scgilardi/slingshot still a thing? is it actually noticeably useful compared to regular try/catch? and when?

bronsa13:03:05

@misha it’s more idiomatic to use normal try/catch with ex-info now

misha14:03:05

I invite everyone, who agrees with this, to click that thumbs-up reaction

Alex Miller (Clojure team)14:03:00

it is most common to use normal try/catch. But additionally, slingshot provides additional functionality that is useful and I’ve gotten a lot of value out of that too.

manuel14:03:02

for instance, with clj-http I found this pattern useful:

(try+
  ,,,
  (catch [:status 401] {:keys [request-time headers body]}
     ))

alexstokes16:03:53

does anyone have a repo they can point me to w/ a test suite they love? i want to get a sense for how the clojure community thinks about granularity of tests, organization of tests, etc

qqq16:03:58

What is the CLJ view of https://www.lively-kernel.org/ ? An idea worth copying, or no fundamental ideas / misguided ?

alexk17:03:01

Reminds me of http://hashify.me/IyBIYXNoaWZ5CgpIYXNoaWZ5IGRvZXMgbm90IHNvbHZlIGEgcHJvYmxlbSwgaXQgcG9zZXMgYSBxdWVzdGlvbjogX3doYXQgYmVjb21lcyBwb3NzaWJsZSB3aGVuIG9uZSBpcyBhYmxlIHRvIHN0b3JlICoqZW50aXJlIGRvY3VtZW50cyoqIGluIFVSTHM/XwoKIyMgRG9jdW1lbnQg4oaUIFVSTAoKSGFzaGlmeSBpcyBkaWZmZXJlbnQgZnJvbSB2aXJ0dWFsbHkgZXZlcnkgb3RoZXIgc2l0ZSBvbiB0aGUgV2ViIGluIHRoYXQgKipldmVyeSBVUkwgY29udGFpbnMgdGhlIGNvbXBsZXRlIGNvbnRlbnRzIG9mIHRoZSBwYWdlKiouCgpUaGUgYWRkcmVzcyBiYXIgdXBkYXRlcyB3aXRoIGVhY2gga2V5c3Ryb2tlIGFzIG9uZSB0eXBlcyBpbnRvIHRoZSBlZGl0b3IuCgojIyMgQmFzZTY0IGVuY29kaW5nCgpPbmx5IGEgdGlueSBmcmFjdGlvbiBvZiBhbGwgVW5pY29kZSBjaGFyYWN0ZXJzIGFyZSBhbGxvd2VkIHVuZXNjYXBlZCBpbiBhIFVSTC4gSGFzaGlmeSB1c2VzIFtCYXNlNjRdWzFdIGVuY29kaW5nIHRvIGNvbnZlcnQgVW5pY29kZSBpbnB1dCB0byBBU0NJSSBvdXRwdXQgc2FmZSBmb3IgaW5jbHVzaW9uIGluIFVSTHMuCgpUaGlzIHRyYW5zbGF0aW9uIGlzIGEgdHdvLXN0ZXAgcHJvY2VzczogW1VuaWNvZGUgdG8gVVRGLTggY29udmVyc2lvbl1bMl0gYXMgb3V0bGluZWQgYnkgSm9oYW4gU3VuZHN0csO2bSwgZm9sbG93ZWQgYnkgYmluYXJ5IHRvIEFTQ0lJIGNvbnZlcnNpb24gdmlhIFtgd2luZG93LmJ0b2FgXVszXS4KCiMjIyMgRW5jb2RpbmcKCiAgICA+IHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudCgnw6dhIHZhPycpKQogICAgIsODwqdhIHZhPyIKICAgID4gYnRvYSh1bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoJ8OnYSB2YT8nKSkpCiAgICAidzZkaElIWmhQdz09IgoKIyMjIyBEZWNvZGluZwoKICAgID4gYXRvYigndzZkaElIWmhQdz09JykKICAgICLDg8KnYSB2YT8iCiAgICA+IGRlY29kZVVSSUNvbXBvbmVudChlc2NhcGUoYXRvYigndzZkaElIWmhQdz09JykpKQogICAgIsOnYSB2YT8iCgojIyBVUkwgc2hvcnRlbmluZwoKU3RvcmluZyBhIGRvY3VtZW50IGluIGEgVVJMIGlzIG5pZnR5LCBidXQgbm90IHRlcnJpYmx5IHByYWN0aWNhbC4gSGFzaGlmeSB1c2VzIHRoZSBbYml0Lmx5IEFQSV1bNF0gdG8gc2hvcnRlbiBVUkxzIGZyb20gYXMgbWFueSBhcyAzMCwwMDAgY2hhcmFjdGVycyB0byBqdXN0IDIwIG9yIHNvLiBJbiBlc3NlbmNlLCBiaXQubHkgYWN0cyBhcyBhIGRvY3VtZW50IHN0b3JlIQoKIyMjIFVSTCBsZW5ndGggbGltaXQKCldoaWxlIHRoZSBIVFRQIHNwZWNpZmljYXRpb24gZG9lcyBub3QgZGVmaW5lIGFuIHVwcGVyIGxpbWl0IG9uIHRoZSBsZW5ndGggb2YgYSBVUkwgdGhhdCBhIHVzZXIgYWdlbnQgc2hvdWxkIGFjY2VwdCwgYml0Lmx5IGltcG9zZXMgYSAyMDQ4LWNoYXJhY3RlciBsaW1pdC4gVGhpcyBpcyBzdWZmaWNpZW50IGluIHRoZSBtYWpvcml0eSBvZiBjYXNlcy4KCkZvciBsb2

john18:03:43

Has benefits. The environment becomes a first class thing you can pass around, but then you end up with incompatible environments, as became the case with lisp and smalltalk "images"

qqq19:03:41

@U8ZA3QZTJ: I'm missing somethihng, what does smalltalk/clojure have to do with storing entire documents in an URL ?

alexk19:03:53

Hmm? I was replying to your post - your post is the one that asked opinions of lively-kernel, and I mentioned something closely related

alexk19:03:34

Storing stuff in a URL isn’t the point, it’s that self-contained bots are a possible future

kenrestivo17:03:21

thats.... unpleasant

dnaeon18:03:59

In Clojure is there a way to do protocol composition? Being able to create new protocols out of other protocols similar to how you can create new Go interfaces using composition?

Alex Miller (Clojure team)18:03:08

protocols are maps. it’s possible to programmatically manipulate them.

noisesmith18:03:03

@dnaeon: the way it's typically done is to make protocols that represent each aspect of a data type, then implement a group of them, you can look at the protocols / interfaces implemented by built in clojure types with supers

noisesmith18:03:40

user=> (supers (class {}))
#{clojure.lang.IFn clojure.lang.IObj clojure.lang.IMapIterable java.lang.Runnable java.io.Serializable clojure.lang.APersistentMap clojure.lang.AFn java.util.concurrent.Callable clojure.lang.ILookup clojure.lang.Seqable java.lang.Iterable clojure.lang.IHashEq clojure.lang.Counted clojure.lang.IPersistentCollection clojure.lang.Associative clojure.lang.IKVReduce clojure.lang.IMeta java.util.Map clojure.lang.MapEquivalence clojure.lang.IPersistentMap clojure.lang.IEditableCollection java.lang.Object}

dnaeon18:03:26

I'm working on project which would need to abstract things on the storage backend side, so that we can have different storage backend implementations. Currently the storage backend protocol consists of a few functions for getting a particular thing (e.g. get-user, put-user, etc.). While still evolving I suspect other things would show up as well (e.g. more functions like get-foo, put-foo, etc.), so my concern is to keep the whole protocol small and tight and was hoping to use some kind of composition. Another possibility I was thinking of is having a protocol for each type, e.g. defprotocol User with it's functions, another one defprotocol Foo, etc. Which way is better to go? Should I go with one big protocol, or separate protocols for each type and have each backend implementation implement only the protocols it is concerned about? What is considered most idiomatic in Clojure? Or am I going in the wrong direction as a whole? 🙂

noisesmith18:03:03

separate protocols is definitely better

mpenet18:03:20

ancestors dont list all protocols if i recall

mpenet18:03:06

Depends when/how a type is extended (inline vs with extend)

noisesmith18:03:55

right - in this case encestors and supers return the same thing

noisesmith18:03:05

user=> (= (ancestors (class {})) (supers (class {})))
true

mpenet18:03:06

(on mobile I can't play with a repl, but this should be easy to test)

noisesmith18:03:50

ancestors appears to be supers + derive

noisesmith18:03:30

ancestors calls supers, and adds to the results

noisesmith18:03:39

derive is what creates the global multimethod heirarchy

dnaeon18:03:03

@noisesmith is having separate protocols for each type something that is considered idiomatic in Clojure? Thanks for all the feedback so far! 🙂

noisesmith18:03:35

@dnaeon: yes, in idiomatic clojure the only reason to include two methods on one protocol or interface is if they are coupled

noisesmith18:03:54

clojure.core is made of a large number of very thin interfaces

dnaeon18:03:06

@noisesmith thanks a lot, I know what to do now. Was having some doubts myself, but your answers made things clear for me on how to move forward. Thanks again!

xiongtx19:03:12

It seems that the :exposes-methods option of :gen-class requires that the exposed-name be different from the super-method-name; otherwise the generated class will have methods w/ duplicate names / sigs. Is this just the way gen-class works? Don’t really see anything in the documentation about it.

madstap22:03:18

In this specific case, couldn't you just use normal recur?