Fork me on GitHub
#clojure
<
2018-11-09
>
todo04:11:09

I need to embed a cljs repl into a webpage. There's no server support, everything needs to happen server side. Is lumo, klipse, planck, or something else the best choice?

zane06:11:04

Assuming you meant "everything need to happen client-side."

zane06:11:59

For what you're describing you don't need any libraries, but Klipse might do what you want out of the box: https://github.com/viebel/klipse

zane06:11:15

Also, you might want to send follow-up questions to #clojurescript.

todo08:11:41

Yes, I meant "everything happen client side." Thanks for inferring that. 🙂. Sure, will move to cljs.

andrea.crotti08:11:33

is there any SLOC counting tool that works well with Clojure?

andrea.crotti08:11:05

I tried a few and the best one (cloc) is still not great because it also counts docstrings as lines of code

andrea.crotti08:11:20

the others don't even attempt to detect blank lines or comments instead

jimmy08:11:04

hi guys what is a good coding style for function that returns future?

eoliphant14:11:16

Not sure that there's much in the way of a future specific style. I think the idea behind the future is to 'lift' threading, etc into nice clojury value-orientation so that all you need to follow are your general style, best practice, etc guidelines

mccraigmccraig09:11:31

@andrea.crotti my cheesy solution: find . -name \*.clj -o -name \*.cljs -o -name \*.cljc | grep /\*/src/ | xargs cat | grep "^.*\S.*$" | grep -v "^\s*;.*$" | wc

leonoel09:11:21

@nxqd suffix with !, as it's likely to be effectful

jimmy10:11:17

@leonoel it’s a good one.

roti11:11:20

it seems that (.getClass obj) is called via reflection. why is that? should it be possible without reflection, since getClass is there for all objects?

stathissideris11:11:02

so we tried evaling 700kb of (generated) Clojure code and the compiler died with a stack overflow

stathissideris11:11:09

known limitation?

mpenet11:11:40

I did hit "method size too large" in the past doing some hairy code gen

mpenet11:11:13

usually it's solvable by breaking it appart and doing it chunk by chunk or just avoiding eval (better)

souenzzo12:11:39

Ratio is not part of edn specification. In cljs repl, if you try to write a ratio, it throws Exception in thread "main" clojure.lang.ExceptionInfo: failed compiling constant: 1/2; clojure.lang.Ratio is not a valid ClojureScript constant. {:constant 1/2, :type clojure.lang.Ratio} But if you (pr-str 1/2) it returns "1/2", which is a "invalid" edn ( pr-str should always print edn, right? transit-clj read and write Ratio transit-cljs dont say anything about Ratio Is it a tracked issue?

noisesmith18:11:56

there are plenty of values from pr-str that are not parsible as edn

noisesmith18:11:15

(eg. Exception, Object, arrays)

souenzzo18:11:44

(pr-str (new Object))
=> "#object[java.lang.Object 0x45463dad \"java.lang.Object@45463dad\"]"
- It's a tagged'y thing. Can fit in the edn spec. - behaves in the same way clj and cljs (cant read by default) - both transit throws when tryies to serialize.

noisesmith18:11:20

speaking of transit - it does seem to handle 1/2 in a way that cljs could handle

(cmd)user=> (def baos (java.io.ByteArrayOutputStream. 4096))
#'user/baos
(ins)user=> (cognitect.transit/write (cognitect.transit/writer baos :json) 1/2)
nil
(ins)user=> (.toString baos)
"[\"~#ratio\",[\"~n1\",\"~n2\"]]"

souenzzo18:11:08

So probably I will need to handle with

{:handlers {"n"     (fn [v] (parse-bigint v))
            "f"     (fn [v] (parse-bigdec v))
            "ratio" (fn [v] (parse-ratio v))}}
Nice. I will try to suggest some extra-docs on transit-cljs README

souenzzo18:11:57

But how about edn spec? Is Ratio a clojure special syntax or it's from edn ?

noisesmith19:11:28

have you tested? I would assume if clj transit generates #ratio, that cljs transit would read it

noisesmith19:11:50

That's an interesting question - I was surprised to see that cljs couldn't handle 1/2

souenzzo19:11:25

(str (transit/read (transit/reader :json) "[\"~#ratio\",[\"~n1\",\"~n2\"]]"))
=>
"[TaggedValue: ratio, [#object[Transit$TaggedValue [TaggedValue: n, 1]] #object[Transit$TaggedValue [TaggedValue: n, 2]]]]"
(pr-str (transit/read (transit/reader :json) "[\"~#ratio\",[\"~n1\",\"~n2\"]]"))
=>
"#object[Transit$TaggedValue [TaggedValue: ratio, [#object[Transit$TaggedValue [TaggedValue: n, 1]] #object[Transit$TaggedValue [TaggedValue: n, 2]]]]]"
It can handle. But it's a bit useless without some custom methods

souenzzo19:11:07

(Imagine that you expect a number and just (str "My number is: " my-number)

souenzzo19:11:45

(transit/read (transit/reader :json {:handlers {"ratio" (fn [[k v]]
                                                          (/ (js/parseInt (.-rep k)) (js/parseInt (.-rep v))))}})
              "[\"~#ratio\",[\"~n1\",\"~n2\"]]")
I will use something like this

souenzzo19:11:19

you can also do some protocol stuff. But then you always need to use your IToString/->str and it need to be extended to bigint, bigdec, ratio...

noisesmith19:11:44

smells like a multimethod almost...

noisesmith19:11:55

I'm surprised this isn't sorted already, frankly

souenzzo19:11:23

I had a problem with bigint few months ago. My application simply stopped working because a number get too big and clojure turns it into bigint

polymeris13:11:54

I was wondering, what are -- in your opinion -- the bad parts of Clojure -- stuff you should not use, ever? And why?

polymeris13:11:26

To be clear, I am talking about things that you could stop doing today (or could be enforced by a linter), not stuff that would need changes to the language. I.e. if you don't like S-expressions, that doesn't qualify.

ccann15:11:59

might be a better question for reddit or clojureverse, as it will probably get lost in the conversation here

val_waeselynck15:11:13

So let's talk about the ns form... :p

val_waeselynck15:11:44

I don't see a lot of things that I would stop doing; I do see a lot of things than you can abuse (e.g dynamic Vars, lazyness, eval, macros...)

polymeris16:11:02

As an example I was thinking of stuff like structs

polymeris16:11:14

Or the mentioned implied :refer :all (@U06GS6P1N?)

👍 8
polymeris16:11:41

You are probably right, @U0BAS2E13

leonoel18:11:58

I have stopped using dynamic vars. When I need thread local state, I use java.lang.ThreadLocal, it's simpler and faster.

didibus20:11:35

I'd say the use of use, or an abuse of :refer :all. Can't think of anything else

didibus20:11:33

Or, maybe declare also, but there are exceptions

rickmoynihan22:11:59

I’ve been using clojure for 10 years and have honestly tried my best to think of something… and I can’t really think of anything… structs are basically deprecated; simply because there’s a better mechanism these days but they still work fine…. :use as an ns form is also basically deprecated, and :refer :all can be an anti pattern but sometimes it’s totally warranted. declare is definitely ok too; but it should only be used where you can’t restructure forms to break a mutual dependency. So the only two things I can really think of is calling realized? on anything other than future/`promise`, e.g. a lazy-seq. And I guess also #= reader eval, but that also has a few uses. So I think that just leaves us with a few standard Lisp aphorisms, like “eval is evil” (except where you need it — e.g. to implement a REPL), and don’t abuse macros 🙂

💯 4
Alex Miller (Clojure team)22:11:36

I think we’ll fix the realized? thing btw

Alex Miller (Clojure team)22:11:50

and #= is officially not public so you shouldn’t use it anyways :)

rickmoynihan22:11:25

I have often wondered what Rich’s biggest regrets about clojure might be… what he’d do differently if he could go back and do it again. I’m guessing putting protocols at the bottom would be quite high on that list (but he fixed that in clojurescript, right? 🙂)

rickmoynihan23:11:17

lmao it’s funny you mentioned that… I almost said that too!

rickmoynihan23:11:54

“Clojure would be great if it wasn’t for our **ing users” 😉

rickmoynihan23:11:28

One has to wonder how many times you folk at Cognitect say this 😉

Alex Miller (Clojure team)23:11:51

Clojure was always made to be shared. There’s no point in putting years of work into something just for yourself.

rickmoynihan23:11:52

Of course, I’m just being facetious; we’re all very much in debt to your generosity!

emccue14:11:51

proxy has the wierd implicit this. Not a "don't" use, but definitely a wart.

rickmoynihan14:11:28

Sure, clojure isn’t perfect… but I’d probably call the imperfections blemishes rather than warts, as they’re usually not that ugly. if we’re talking blemishes there are a few but nothing major… e.g. inability to add docstrings in defrecord (because there’s no var for them), then sometimes you need to define a new constructor for them so you may want to mark the implicit constructor private (which you can do with alter-meta!) so people don’t use it rather your one etc… I also wish spec had docstrings too… though hopefully that’s coming.

sneakypeet14:11:01

before I go dig, does anyone know what kind of rounding will happen here (format "%.2f" some-double)

sneakypeet14:11:43

seems like HALF_EVEN

noisesmith18:11:57

I would be surprised if the docs for Formatter don't make it explicit

noisesmith18:11:29

user=> (doc format)
-------------------------
clojure.core/format
([fmt & args])
  Formats a string using java.lang.String.format, see java.util.Formatter for format
  string syntax
nil

noisesmith18:11:43

from the doc for Formatter:

The number of digits in the result for the fractional part of m or a is equal to the precision. If the precision is not specified then the default value is 6. If the precision is less than the number of digits which would appear after the decimal point in the string returned by Float.toString(float) or Double.toString(double) respectively, then the value will be rounded using the round half up algorithm. Otherwise, zeros may be appended to reach the precision. For a canonical representation of the value, use Float.toString(float) or Double.toString(double) as appropriate.

jaawerth15:11:42

I find myself using the clojure REPL a lot for doing data manipulation - before I go implementing this myself, anyone know of an existing way to print data from the REPL but pipe it through a pager or less or other interactive shell tools? I couldn't find anything, so I'll likely try to implement it myself - I'm probably either going to need to launch it as a child process from clojure and figure out how to hook the child's stdio to the REPL's stdio, OR maybe manipulate it on the readline/rebel-readline/rlwrap level...

val_waeselynck15:11:28

@jesse.wertheim Haven't used it, but you may be interested in datawalk: https://github.com/eggsyntax/datawalk

😍 4
jaawerth15:11:44

I'll check it out, thanks!

val_waeselynck15:11:01

Not really what you asked, but could serve the same purpose

jaawerth15:11:23

definitely serves a similar usecase and looks like it could come in handy even if I get the pager thing working

guillaume15:11:33

@jesse.wertheim how about the tee command? https://www.howtoforge.com/linux-tee-command/ you could tail the resulting file and fwd that to another process

jaawerth15:11:02

@guillaume.carbonneau in this case it's more that I deal with some big data sets (and a few wide ones if processing from a spreadsheet rather than a DB), and am looking for a way to temporarily give up stdio control from the REPL to some other shell program, then switch back - kinda like psql's behavior with opening what you've configured in the $PAGER env var if the query output is too large. tee could certainly play a factor if I also want it to output to a file ,but in this case it's more about the terminal UI

jaawerth15:11:33

while looking into this I DID try out clojure 1.10's inspector stuff though, which kinda serves a similar purpose, just graphically. pretty neat!

currentoor19:11:23

Is there a way to spec a map to contain a particular value? I’ve got this

(s/def ::canceled-result-code (s/with-gen #(= "1" %) #(s/gen #{"1"})))
(s/def ::approved-result-code (s/with-gen #(= "0" %) #(s/gen #{"0"})))

(s/def ::canceled-response
  (s/merge
    (s/map-of #{::ResultCode} ::canceled-result-code)
    (s/or
      :emv ::emv-response
      :swipe ::swipe-response)))

(s/def ::approved-response
  (s/merge
    (s/map-of #{::ResultCode} ::approved-result-code)
    (s/or
      :emv ::emv-response
      :swipe ::swipe-response)))

jaihindhreddy-duplicate19:11:49

A minimal self contained example would be more helpful.

currentoor19:11:34

but it’s not able to generate data

currentoor19:11:03

the only difference between cancelled-response and approved is the value of the ResultCode

jaihindhreddy-duplicate19:11:47

Because there isn't any difference b/w cancelled and approved response, why not just do

(s/def ::ResultCode #{"0" "1"})
(s/def ::emv-response (s/and int? even?))
(s/def ::swipe-response (s/and int? odd?))
(s/def ::response (s/keys :req [::ResultCode (or ::emv-response ::swipe-response)]))
; Generate some responses
(gen/sample (s/gen ::response))

currentoor19:11:51

I get this error

currentoor19:11:55

CompilerException clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries. 

jaihindhreddy-duplicate19:11:43

Can you conform any manually written example?

jaihindhreddy-duplicate19:11:08

Can you show us the definition of ::ResultCode?

jaihindhreddy-duplicate19:11:15

Also FYI, Because sets implement clojure.lang.IFn, you can define ::canceled-result-code and ::approved-result-code simply as,

jaihindhreddy-duplicate19:11:42

(s/def ::canceled-result-code #{"1"})
(s/def ::approved-result-code #{"0"})

jaihindhreddy-duplicate19:11:20

Also, I believe this is not an idiomatic use of map-of.

noisesmith19:11:26

as long as the data isn't nil or false yeah that's the ticket

jaihindhreddy-duplicate19:11:35

A multi-spec might be more appropriate here.

currentoor20:11:32

@jaihindh.reddy yeah i think you’re right

currentoor20:11:25

does multi-spec work with generators?

jaihindhreddy-duplicate20:11:54

@currentoor sorry for rambling there a bit. I think the error there was because s/merge expects the args to be map-conforming specs and s/or doesn't give you such a spec.

jaihindhreddy-duplicate20:11:11

Yeah multi-spec works with generators just fine.

currentoor20:11:45

can you specify which “type” in the generators?

currentoor20:11:05

like i want a an approved-response instead of either

currentoor20:11:55

no worries, this is helpful simple_smile

jaihindhreddy-duplicate20:11:07

Here's what I came up with:

(s/def ::ResultCode #{"0" "1"})
(s/def ::emv-response (s/and int? even?))
(s/def ::swipe-response (s/and int? odd?))
(defmulti response ::ResultCode)
; These two method impls would be identical and contain (or ::emv-response ::swipe-response) Haven't written it like that to distinguish the difference b/w the two.
(defmethod response "0" [_] (s/keys :req [::ResultCode ::emv-response]))
(defmethod response "1" [_] (s/keys :req [::ResultCode ::swipe-response]))
(s/def ::response (s/multi-spec response ::ResultCode))
Now because response is just a multi-method that ignores the argument and return the spec for a particular variant, to get a generator for approved result codes ("0" cases), all we need to do is to get at the method that we want. (def approved-response-generator (s/gen ((get (methods response) "0") 42))) We can then call it as usual. (gen/sample approved-response-generator)

jaihindhreddy-duplicate20:11:28

^ The 42 here is of no significance. We can pass anything there because it's ignored.

jaihindhreddy-duplicate20:11:05

@currentoor Turns out we can specify it.

currentoor20:11:44

oh nice! thanks! @jaihindh.reddy

👍 4
currentoor20:11:58

very kind of you to help like this