Fork me on GitHub
#clojure
<
2018-01-03
>
kidpollo01:01:29

I hear proto-repl-charts is a great way to work with data this days

qmrw02:01:39

I’m trying to do something similar from intelliJ, gorilla forces you to type in the browser..

jgh04:01:32

ot: i gave proto-repl a try but it doesnt seem to keep a repl history

mchampine06:01:45

Not sure this is sensible/useful in any way, but I was wondering if there’s a particularly good way of modifying a single element of an infinite sequence. You can’t just assoc with an index. I came up with:

(defn assoc-nth [s n v]
  (let [[l r] (split-at n s)]
    (concat l (vector v) (rest r))))

(take 10 (assoc-nth (repeat 0) 3 7))
(0 0 0 7 0 0 0 0 0 0)
.. but was wondering if there’s a better way. Googling yielded nothing.

onionpancakes07:01:37

I would just store the "modifications" in a map. Then take values from the map at that index if it exists, otherwise take from the stream.

onionpancakes07:01:02

`(let [m {3 7}] (->> (repeat 0) (map-indexed #(m %1 %2)) (take 10)))`

onionpancakes07:01:52

(let [m {3 7}]
  (->> (repeat 0)
       (map-indexed #(m %1 %2))
       (take 10)))

rauh07:01:24

@scallions No need for the anonymous function

mchampine07:01:34

Interesting. Nice in that you can supply any number of updates at once.

mchampine07:01:50

So without the anon.

(let [m {3 7 5 9}]
  (->> (repeat 0)
       (map-indexed m)
       (take 10)))
(0 0 0 7 0 9 0 0 0 0)

onionpancakes07:01:57

Yea works the same! I should of seen it coming with those args in sequential order.

dpar09:01:27

Hi, what would you use to make a gui? Fn-fx seemed interesting but also now abandoned, with issues on github going unanswered. Also cljs+electron is not looking much used. As a beginner with clojure I was looking for something straightforward and with many resources. But there doesn't seem to be anything.

dpar09:01:20

(I need to make a desktop gui)

gklijs10:01:39

@teikfaiv what do you need? you could use hiccup to send html as response, you might not needs cljs?

dpar10:01:56

I don't think just html would be enough

gklijs10:01:02

Maybe you could start with a luminus with re-frame, it give you both a back and front-and and some usefull tools like re-frame out of the box? It’s kind of how I started getting into clojure.

dpar10:01:13

I really need to make a desktop gui, it cannot be in a browser

schmee10:01:03

there is https://github.com/daveray/seesaw, I’ve made some toy projects with it and I had a pretty good experience, can’t comment on it for serious production use though

kah0ona11:01:34

Quick compojure-api question: I want to send a date to the server, and have my spec based route coerce it to a java.util.Date, using spec/inst?. I send application/transit+json, and encode the param like this; http://some-url?myParam=Wed Dec 27 2017 11:48:05 GMT+0100 (CET) What is the recommended way of doing this, because I get a spec validation error on my route. I basically just send a javascript Date directly to the server. What format should I send it in such that it is automatically coerced to a java.util.Date? cc @ikitommi

h.elmougy11:01:00

[immutant.web.internal.undertow$create_http_handler$reify__17886 handleRequest undertow.clj 239] [org.projectodd.wunderboss.web.undertow.async.websocket.UndertowWebsocket$2 handleRequest UndertowWebsocket.java 109] does immutant/undertow upgrade to websockets by default?

jita11:01:41

What would be the easiest IDE setup for clojure on linux ? For someone coming from sublime text / vs code

Petri11:01:37

VS Code is available also for Linux, I think. But if you want “full” IDE, I’d look into IntelliJ IDEA with Cursive plugin: https://cursive-ide.com/

jita11:01:13

Hey, thanks which one would be better for a beginner ?

souenzzo11:01:10

+1 to idea-community + cursive

kah0ona13:01:33

Thx, okay.

pithyless14:01:58

Is there any way to enforce certain options must be passed explicitly in clojure.tools.cli? As far as I can tell, this is no longer possible: https://github.com/clojure/tools.cli/commit/47984bc7413d7a675ea9586d08d461d4a016060e

pyr14:01:20

Hi! To circumvent CLJ-1814, I'm trying to avoid calling satisfies? at runtime

pyr14:01:36

My usual approach in several facades was to build several protocols

pyr14:01:52

and write a proxy which for each method would check for a satisfied? protocol

pyr14:01:06

pending resolution of CLJ-1814 this is inefficient

pyr14:01:22

so instead, I'm trying to write code at compile time

pyr14:01:40

my naive first approach was to do

clojure
(defmacro make-proxy [proto-impl]
   (let [forms (make-forms proto-impl)]
     `(proxy [MyClass] [] [email protected])))

pyr14:01:28

This doesn't work since proto-impl is a form and not the protocol implementation at compile time.

pyr14:01:11

Would there be a variant to this approach that would allow me to build forms only once and thus have a proxy which does not need to rely on satisfies? ?

pyr15:01:16

So it seems somewhat possible to do with a variant like this:

pyr15:01:43

(defn make-forms [x]
   (cond-> []
     (satisfies? Foo x) (conj '(getFoo [] (get-foo x)))
     (satisfies? Bar x) (conj '(getBar [] (get-bar x)))))

(defmacro make-proxy [proto-impl]
   `(let [forms# (make-forms ~proto-impl)]
       (concat '(proxy [MyClass] []) forms#)))

pyr15:01:24

I seem to lose all hinting capacity along the way though, which is a big loss for facades.

uwo16:01:25

why would (clojure.data.json/read-str (slurp filename)) throw java.lang.StringBuilder cannot be cast to java.io.PushbackReader,?

pyr16:01:22

If anyone is interested, I reverted to a non-macro based approach, which remains fast but is somewhat inelegant: https://github.com/pyr/net/commit/a489eb71f5ff4ab474ff0408d898581a67902b62

bronsa16:01:44

@pyr a vote on CLJ-1814 could help btw :)

ghadi16:01:52

I dislike CLJ-1814 and wish satisfies? was slower (jokingly) to discourage its use.

ghadi16:01:30

But I can't make a negative vote

pyr16:01:26

You can't make a negative vote but can try to explain (in the ticket or here) why you dislike it and how you'd approach this

mikerod16:01:09

it’s not that clear to me what help satisfies? really is anyways

mikerod16:01:26

Also, there is nothing I know of to check for unsupported functions on a protocol

mikerod16:01:57

This has actually been a dilemma of mine: Protocols are nice that they are open to extension later However, all older impl’s do not support newly added functions and you have no way to check that - so you still are broken

mikerod16:01:11

Well, you can try-catch check, but that’s not great

bronsa16:01:12

@ghadi right, I get your point but there are times when you actually need satisfies? and it often happens to be in hot paths

mikerod16:01:39

I don’t see where satisfies? really helps with anything since it doesn’t tell you about unsupported operations anyways

ghadi16:01:41

It encourages a bit of an abuse of polymorphism, making tests for specific classes of things rather than implementing and calling the polymorphic method

pyr16:01:51

@mikerod the code emanating from cognitect and friends seems to favor few signatures

pyr16:01:59

you need a new one, you add a protocol

ghadi16:01:09

@mikerod unsupported methods is a separate thing to this

mikerod16:01:13

@pyr I understand to favor “small interfaces”

pyr16:01:14

making signatures mandatory (in a ad-hoc way)

bronsa16:01:18

i.e. tools reader needs it to know whehter it can annotate output with line/col info or not -- I had to work around it by hardcoding instance checks

mikerod16:01:23

However, if that’s the case, then just enforce all functions are impl’ed

mikerod16:01:05

@ghadi I don’t know. I think it relates in some ways.

mikerod16:01:18

In terms of, what is the point of satisfies?

bronsa16:01:42

there's the workaround of extending protocols to Object for the catch-all case rather than testing with satisfies? and using the else branch

mikerod16:01:44

even if you wanted to use it for potential polymorphism violations or whatever

pyr16:01:50

@ghadi I understand your point from an ideal PoV

bronsa16:01:50

but sometimes that's not the behaviour you want

pyr16:01:06

@ghadi my need always emerges when writing facades

mikerod16:01:13

@bronsa you can’t interleave Object with a more specific impl ?

mikerod16:01:22

I’m talking about an older impl that already is written

bronsa16:01:38

there's no get-method for protocols

mikerod16:01:42

A already implements P function f1. Later P adds f2. A hasn’t bee upgraded

mikerod16:01:55

You can put f2 on Object, but A will “override Object”

mikerod16:01:13

So that idea would be awesome - if A fell back to Object for missing function impl’s

mikerod16:01:39

I just struggle to see how you can grow a protocol at all since it seems to just break everything that exists - or at least make them all incompatible

bronsa16:01:45

you can't redefine a protocol really

bronsa16:01:53

all weird things will happen

bronsa16:01:03

i mean, you can do it at the repl, but don't do it in code

mikerod16:01:03

Yes, so if they are not really open to extension later, I wish you couldn’t have partial impl’s

mikerod16:01:20

I don’t mean redefine like at runtime or something, just like a new version

mikerod16:01:35

so instead I guess you make P2 when you want to change P

mikerod16:01:47

and you impl P2 on Object for all those that don’t support it because they are old and use P

mikerod16:01:58

that’s how you impl your compatibility layer I suppose

mikerod17:01:29

I wouldn’t use satisfies? for any of that though

pyr17:01:13

@mikerod at the moment it's the only tool I have, bar ugly workarounds like the one I used above

pyr17:01:07

and when possible, single-method protocols with an implementation on Object

pyr17:01:17

which allows the default behavior to fall-through

mikerod17:01:27

(defprotocol P2 (old-f-from-p [this]) (new-f [this]))

(extend-type Object
 P2
 (old-f-from-p [this] ::no-impl) 
 (new-f [this] ::no-impl))

(defn using p-or-p2 [o]
  (let [v (new-f o)]
   (if (= ::no-impl v) (compat-layer (old-f o)) v)))

bronsa17:01:34

that assumes that you can capture a default behaviour

bronsa17:01:51

sometimes you just can't

pyr17:01:08

agreed hence the when I can

bronsa17:01:47

sorry, I skipped over that :)

mikerod17:01:19

I mean, I don’t even try on Object for some cases like this, just make them a faster “satisfies” check that can actually check at the fn level. hah

mikerod17:01:39

I guess I’m just missing the bigger picture here 😜

mikerod17:01:13

However, I see really no good reason to not fully implement a protocol. I think you are supposed to anyways from some docs (have to check). Perhaps it isn’t checked just for pragmatic reasons etc

bronsa17:01:38

i don't understand what you're point is, satisfies has nothng to do with partial protocol implementations

mikerod17:01:16

Sure, leave that part out of the satisfies conversation then

mikerod17:01:15

Focusing purely on the satisfies part of my comments here (since I guess no one wants to talk about extending protocols right now, hah)

(defprotocol P
  (foo [this]))

(extend-type Object
  P
  (foo [this] ::no-impl))

(defn maybe-use-p-on-x [x]
  (let [v (foo x)]
    (if (= v ::no-impl)
      (do-not-do-stuff x)
      (do-stuff v))))
Something like that can be used in place of satsifies? right? Also, I’d think that is fast.

luskwater20:01:55

I have used satisfies? in

(defprotocol SomeOps
  (-foo [this x] "Establish the fooness of x for this"))
(s/def :some-ops/subject #(satisfies? SomeOps %))
(s/def :some-ops/x any?)
(s/fdef foo
  :args (s/cat :this :some-ops/subject
               :x    :some-ops/x)
  :ret boolean?)
(defn foo
  "Establish the fooness of x for this (wrapper for `-foo`)"
  [this x]
  (-foo this x))
in order to make sure I got the right sort of thing inbound

dominicm20:01:19

I'm having interop issues with https://docs.oracle.com/javase/8/docs/api/javax/tools/SimpleJavaFileObject.html#SimpleJavaFileObject-java.net.URI-javax.tools.JavaFileObject.Kind-

user=> (javax.tools.SimpleJavaFileObject. (.toURI (io/resource "ClojureMainBootstrapJarClassLoader.java")) javax.tools.JavaFileObject$Kind/SOURCE)
CompilerException java.lang.IllegalArgumentException: No matching ctor found for class javax.tools.SimpleJavaFileObject, compiling:(NO_SOURCE_PATH:36:1)
I don't understand how I am getting this wrong.

bronsa20:01:12

that ctor is protected

dominicm20:01:05

Ah, is that what protected means 😄

dominicm21:01:09

Is there a clojure equivalent to:

class MyFileObject extends SimpleJavaFileObject {
        MyFileObject() {
            super(URI.create("myfo:///Test.java"), SOURCE);
        }
    }
It can be anonymous, I can't understand how to do it with proxy though.

dpar21:01:20

@dominicm as far as I know proxy returns an istance not a class

bronsa21:01:03

@dominicm (proxy [javax.tools.SimpleJavaFileObject] [(java.net.URI/create "") javax.tools.JavaFileObject$Kind/SOURCE]) for an instance

noisesmith21:01:29

you might need to explicitly call class on that thing to return the class created though right?

noisesmith21:01:16

also @bronsa there’s a question in #beginners about gen-class you might be able to help with - I thought I understood the issue and it appears it’s beyond me

dominicm21:01:27

Oh, I apparently mixed up proxy with reify. Great!

vemv21:01:52

I have no idea what this clojure.core.match code does:

(match [v t-p]
      [(true :<< nil?) tp] (g tp)
      [(true :<< i?) :r] v
      [(false :<< i?) :r] (g :r)
      [(false :<< i?) _] v
      [(true :<< i?) tp] (g tp)
      :else(...)
(variable names redacted)

vemv21:01:05

the :<<s are the odd part

bronsa21:01:46

I believe (true :<< nil?) is equal to pattern matching against nil in this case

bronsa21:01:24

probably there in this form just for stylistic purposes, to match the shape of the other patterns

bronsa21:01:50

what that syntax means is, apply the function to the right of :<< to the argument at that position, and match the return type against the value to the left

vemv21:01:52

thanks for the input! still a bit lost

vemv21:01:02

let's take [(true :<< nil?) tp] (g tp) as example

vemv21:01:08

what is nil? fed?

vemv21:01:10

ah nice, I see now!

vemv21:01:24

does this mechanism correspond to something described in https://github.com/clojure/core.match/wiki/Overview ?

bronsa21:01:00

it's in here

bronsa21:01:11

scroll to "function application"

vemv21:01:24

ace 👌

mping23:01:56

hi, how can I macroexpand a function that calls a macro?

arrdem23:01:40

Functions can’t call macros. They can return lists which could be macroexpanded, or they can be implemented using macros which are fully expanded within their definition.

noisesmith23:01:31

@mping you can quote the function form and macroexpand the whole thing

noisesmith23:01:56

=> (clojure.walk/macroexpand-all '(defn foo [x] (or x 1)))
(def foo (fn* ([x] (let* [or__5238__auto__ x] (if or__5238__auto__ or__5238__auto__ 1)))))

noisesmith23:01:11

I should have mentioned clojure.walk/macroexpand-all (forgot that it would be needed for this)

bronsa23:01:41

beware of macroexpand-all

bronsa23:01:48

it doesn't track lexical scoping

bronsa23:01:15

it's usually ok

bronsa23:01:25

but in the rare case where you shadow a macro

bronsa23:01:27

it won't work properly

noisesmith23:01:36

ahh, that makes sense

bronsa23:01:40

also it won't work correctly with macros that use &env

mping23:01:41

why can’t I do (macroexpand-all '(foo 3)) ?

bronsa23:01:25

you need to refer it from clojure.walk

mping23:01:30

yeah but even so it doesn’t pick up the fn body

mping23:01:39

well it kinda makes sense but its a bit unexpected

noisesmith23:01:05

you can macroexpand (foo 3) but you wont’ get anything useful - because foo isn’t a macro

noisesmith23:01:31

macros are functions that take forms and return new forms, expansion makes sense in that context

noisesmith23:01:46

expansion can’t do anything useful with something that doesn’t operate on forms

mping23:01:58

makes sense