Fork me on GitHub
#beginners
<
2020-11-20
>
sove00:11:25

So I'm trying to get the size of a file ... (.length (io/file "filename")) is not working ;/

sove00:11:35

am i missing something?

phronmophobic00:11:37

are you getting an error?

sove00:11:28

Aha. I was getting zero as the file size. but it's because I did not have the full path "resources/"

sove00:11:39

because I'm also using resource-response (which adds in "resources/" on its own)

sove00:11:14

I'm trying to get this .m4a to play on iOS mobile [webkit] and apparently it needs 3 headers set,

sove00:11:44

it works on desktop firefox and stuff... but on iOS mobile it just doesn't want to play nice. It used to say "Live Broadcast" and now it just says "Error" where there ought be a seek bar x/

noisesmith00:11:06

mixing files / resources sometimes works accidentally, but it's not going to work in the general case

sove00:11:11

(GET "/members/:filename" [filename :as r]
  	(let [file-size-in-bytes (.length (io/file (str "resources/members/" filename)))
  		  content-range (str "bytes 0-" (dec file-size-in-bytes) "/" file-size-in-bytes)]
    (println filename ": " file-size-in-bytes ": " content-range ": " )
      (->
  		(response/resource-response (str "members/" filename))
  		(response/header "Content-Length" file-size-in-bytes)
  		(response/header "Content-Range" content-range)
  		(response/header "accept-ranges" "bytes") 
  		)))

noisesmith00:11:42

small thing, you don't need that str call, io/file already composes varargs into a path

sove00:11:07

hmmm okay, let's do that...

sove00:11:06

Is very weird ... webkit just says "Error" where there ought be a seek bar. And so I try and undo the code I have added, and it doesn't go back to saying "Live Broadcast" but remains on "Error" x/

phronmophobic00:11:20

it probably doesn't matter, but I would also capitalize

Accept-Ranges

sove00:11:36

πŸ˜„ open to any suggestions

sove00:11:51

anybody got Tim Cook on speed dial?

sove00:11:00

I have words.

phronmophobic00:11:45

are accessing the page from iOS safari?

phronmophobic00:11:27

if so, I believe you can pull up a dev panel using safari on your computer and connecting to the safari running on your iOS device

phronmophobic00:11:38

that dev panel might be able to give you more information

sove00:11:12

whaat that's awesome i gotta figure out how to do that.

phronmophobic00:11:03

yea, it's quite useful

sove00:11:32

welp, I can see the error now, apparently it doesn't know the file type. it just says "other" and it shows a failure

st3fan01:11:20

Is there an easy way to benchmark some code?

st3fan01:11:37

ideally a single function in the repl

phronmophobic01:11:07

time: eg.

> (time (count (range 1e7)))
"Elapsed time: 1466.041527 msecs"                                                                                                                                                       
10000000  

alexmiller02:11:43

but note that a) Java uses a just in time compiler, so code gets faster as you run it more and b) garbage collection can throw unexpected pauses into the mix

alexmiller02:11:23

so even doing a repeated series of (time (dotimes [_ 1000] (whatever))) will give you a much better sense than timing one op

st3fan02:11:28

Yeah that is what I did .. it is good enough for an indication ...

seancorfield03:11:28

criterium is a good library for benchmarking

seancorfield03:11:13

If you're using the CLI and my dot-clojure file, you can just use the :bench alias to bring that in:

[email protected]:~/clojure$ clj -M:bench
Downloading: criterium/criterium/maven-metadata.xml from clojars
Downloading: criterium/criterium/0.4.6/criterium-0.4.6.pom from clojars
Downloading: criterium/criterium/0.4.6/criterium-0.4.6.jar from clojars
Clojure 1.10.1
user=> (require '[criterium.core :refer [bench quick-bench]])
nil
user=> (defn foo [n] (* n n n))
#'user/foo
user=> (quick-bench (foo 13))
Evaluation count : 71598534 in 6 samples of 11933089 calls.
             Execution time mean : 2.927325 ns
    Execution time std-deviation : 2.830385 ns
   Execution time lower quantile : 0.853802 ns ( 2.5%)
   Execution time upper quantile : 7.650605 ns (97.5%)
                   Overhead used : 7.242216 ns

Found 1 outliers in 6 samples (16.6667 %)
        low-severe       1 (16.6667 %)
 Variance from outliers : 83.1399 % Variance is severely inflated by outliers
nil
user=>

practicalli_john09:11:22

criterium is excellent for producing more accurate results than time as it warms up the JVM and runs testsany times to give tha average. I also use memory meter too https://github.com/practicalli/clojure-deps-edn#performance-testing

st3fan18:11:26

Oh that is very nice

st3fan21:11:02

I have not figured out what the deal is with deps.edn yet - i'm "simply" using lein now because that is what I know - but it looks like I need to investigate πŸ™‚

practicalli_john23:11:53

With Leiningen and Clojure CLI tools (deps.edn), the Clojure code is the same (unless lein plugins are writing code for you). However Clojure CLI is a simple wrapper around the JVM with some tools to manage dependencies. One advantage is this is faster than Leiningen, which spins up two virtual machines. The list of community tools that are in practicalli/clojure-deps-edn are used instead of a specific plugin system like Leiningen, so it's easier to add all sorts of tooling to Clojure CLI. This approach is being extended via Clojure exec (and there are whispers about something called tools.build...)

william10:11:58

this query using clojure core.logic baffles me:

(logic/run* [what]
  (logic/membero '(a b ~what) '((a b c))))
it returns () when I would have expected '((a b c)) . Could you explain me why?

william10:11:30

I see that

(logic/run* [what]
  (logic/membero '(a b c) '((a b c))))
is always satisfied, so there must be something wrong in the way I'm using the logical variable

william10:11:26

nevermind, figured it out. The correct form is:

(logic/run* [what]
  (logic/membero ('a 'b what) '((a b c))))

william10:11:39

hindsight is 20/20 πŸ˜‚

william10:11:39

but why is ('a 'b what) not equivalent to

`(a b ~what)
?

delaguardo10:11:48

because a and b will be transformed into (quote user/a) not to simple symbol a

william10:11:10

I see, so I probably should use keywords instead of symbols in this case, right?

william10:11:25

wait who transforms a in (quote user/a)?

william10:11:01

oh I see, the backtick... why does it do that?

delaguardo11:11:18

Inside of backtick symbols expand to fully qualified form. Unless symbol is not quoted

william10:11:05

when I'm in emacs with cider, how do I get documentation for a library function?

william10:11:52

cider-doc unsurprisingly

william10:11:06

I'd like to know why in:

(logic/run* [what]
  (logic/membero (:a :b what) '((:a :b :c))))
I don't need to quote (:a :b what) , and in fact why quoting it is wrong, and how should I have known

delaguardo11:11:07

I guess because membero is macro and expects a form.

william11:11:04

but where is that documented? How would I know? By reading the source code of membero?

william11:11:36

(defne membero
  "A relation where l is a collection, such that l contains x."
  [x l]
  ([_ [x . tail]])
  ([_ [head . tail]]
    (membero x tail)))

william11:11:30

(defmacro defne
  "Define a goal fn. Supports pattern matching. All
   patterns will be tried. See conde."
  [& rest]
  `(defnm conde [email protected]))

william11:11:46

it's unclear for me where I should get that information

bronsa11:11:19

membero is not a macro

delaguardo12:11:47

Just checked with source code. You right this is not a macro but it meant to work in macro context as a function transforming unevaluated arguments into a form.

bronsa11:11:26

the only macro there is run* , and that's what defines the evaluation semantics of its whole body

Iulian12:11:28

Is there any way to add an "id" attribute to a re-com component? I tried all the combinations of adding the :id in a map or straight into the component, but it does not work. This is my component:

[single-dropdown
    :width     "200px"
    :choices (reagent/atom tags)
    :model (reagent/atom nil)
    :placeholder "Issue Group"
    :filter-box? true
    :on-change #(print "Dropdown: " %)]

uosl12:11:47

Did you try using the :attr param? e.g. :attr {:id "myid"}

Iulian12:11:44

I did not, and it worked πŸ™ˆ Thank you!

πŸŽ‰ 1
gregg01:11:49

Regarding :model (reagent/atom nil), every time through the render loop, the component will be passed a new reagent atom with value nil, so while I haven't tested it, I don't think that's what you want. I would move the atom to a let block, using a Form-2 component: https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-2--a-function-returning-a-function

Lyderic Dutillieux14:11:11

Hey guys, I just checked my system's deps.edn located at /usr/local/lib/clojure/deps.edn and I found this :

:aliases {
    :deps {:replace-deps {org.clojure/tools.deps.alpha {:mvn/version "0.9.833"}
                          org.slf4j/slf4j-nop {:mvn/version "1.7.25"}}
           :ns-default clojure.tools.cli.api}
    :test {:extra-paths ["test"]}
  }
Does anyone know what the :deps alias can be used for ?

kschltz15:11:07

It seems to me it is there to provide some tooling to mess around with your project dependencies/structure

Lyderic Dutillieux15:11:15

You mean for editor integration for example ? So it should not be used manually

alexmiller15:11:12

no, it should :)

alexmiller15:11:09

it provides a number of built-in apps you can run

alexmiller15:11:45

probably will be more over time

Lyderic Dutillieux15:11:14

Alright, great ! Thanks, it will be usefull

Rebecca Nzioki15:11:25

Hey guys, how else can you write this code without using macros?

(defn hex->rgb [[_ & rgb]]
  (map #(->> % (apply str "0x") (Long/decode))
       (partition 2 rgb)))

dpsutton15:11:47

defn is a macro but you're probably ok with that one? Do you just want to not use the threading macro ->>?

dpsutton15:11:49

(fn [rgbs] (Long/decode (apply str "0x" rgbs)) should do it then as the function you are mapping

andy.fingerhut15:11:09

The expression (->> % (apply str "0x") (Long/decode)) is equivalent to (Long/decode (apply str "0x" %))

dpsutton15:11:25

# is the dispatch macro so i got rid of that one too πŸ™‚

dpsutton15:11:23

why did you want to get rid of the macro? just curious

Rebecca Nzioki15:11:33

thanks! it's just for learning, i'm reading the web-dev-with-clojure and I read that you can choose to use the threading-macros or not..

dpsutton15:11:43

great reason! πŸ™‚ Take some time to see how that worked as threading macros are pretty much everywhere and often used interchangeably with what they expand to

dpsutton15:11:23

also try evaluating (macroexpand '(->> (range 3) (map inc) (map dec)))

βœ”οΈ 1
st3fan18:11:40

What is the deal with globals in Clojure? Are they acceptable because they are mostly immutable? Or should I work on eliminating them?

dgb2318:11:16

> Are they acceptable because they are mostly immutable? @st3fan As I understand you can manipulate just about everything in Clojure at any time. Your vars, namespaces and so on.

st3fan18:11:49

I now realize that what I am really asking is probably more about how do I structure an application that has some state associated with it. Both static (configuration settings) and dynamic (a redis connection). In Go I usually create an application struct to capture these things .. create one in main, then call functions on that struct.

st3fan18:11:09

Understanding how this maps to Clojure is a gap in my knowledge

dgb2318:11:05

There is a distinction of side-effects, like opening and closing connections, writing to sockets etc. And state, which lives inside your application.

st3fan18:11:37

Are there some good examples available?

dgb2318:11:44

There are patterns and libraries that are specifically used to deal with side-effects and configuration in a nice way like integrant. But generally yes, you’d use (def…) and store your connections there

dgb2318:11:30

Generally people don’t concern themselves too much with making stuff inaccessible. Its rather a matter of communicating clearly what your public API is

st3fan18:11:27

I am not so worried about visibility (inaccessible) - more about good structure and being able to test properly.

Darin Douglass18:11:06

the standard trifecta for application state usually are: β€’ https://github.com/stuartsierra/component β€’ https://github.com/weavejester/integrant β€’ https://github.com/tolitius/mount each has their drawbacks/paradigms so you'll have to find what suits your needs best

πŸ‘ 2
Darin Douglass18:11:44

there are others like https://github.com/juxt/clip and https://github.com/aroemers/mount-lite (my current fav, though i haven't tried clip yet)

edye19:11:54

Is there a way to destructure a map parameter to get the remaining keys? I thought it might look like this:

(defn f [{:keys [a & remaining]}] remaining)

dgb2319:11:00

(let [[item1 :as all] names]
  (println "The first name from" all "is" item1))

dgb2319:11:29

you mean this?

edye19:11:48

Yes like that but for a map rather than a vector

dorab19:11:58

Not quite what you want, but close (defn f [{:keys [a b] :as all}] (println "All: " all)) ?

alexmiller19:11:36

no, there is no way to do that

edye19:11:48

ok makes sense, I couldn't find a section on it. I'll just dissoc the other keys from map

st3fan19:11:21

Probably preaching before the choir here - but the thing I love the most about working in Clojure is the REPL - I just figured out a weird base64 decoding bug by augmenting my server code to store data in a temp var and then I figured out the problem by just playing around with that interactively.

πŸ‘ 4
Xarlyle019:11:42

Heyo! I'm looking to improve my more professional coding skills, so I completed question 140 on 4clojure with the goal of creating the most understandable solution, with concise documentation that can lead someone through a difficult problem. Would anyone be willing to take a look at my solution and give feedback with regards to that goal? My username on 4clojure is xarlyle0.

noisesmith19:11:00

I think #code-reviews is the right place for that, you can post it there without asking permission

andy.fingerhut19:11:06

This message is perfectly appropriate for the #beginners channel. I also wanted to point out #code-reviews channel.

Xarlyle019:11:48

Cool! I didn't know about the #code-reviews channel. Good to know, thanks

Xarlyle019:11:34

There are a lot of helpful people in the #beginners channel so I figured this would be a good place

Xarlyle019:11:08

But I don't know if people can actually access my code on 4clojure, so I didn't know if I would need to post the code here or not.

noisesmith20:11:10

people can access it based on your user name, if they have an account that has solved the problem already

noisesmith20:11:14

probably best to share the code here

Xarlyle020:11:48

okay. Here is the code.

(fn [s]
  (letfn [; take a set #{A b c D}, and make #{#{A b c "D"} #{A b "C" D} #{A "B" c D} #{"A" b c D}}, note both lower and upper case symbols become capital Strings
          (get-subsets [coll] (set (map #(conj (disj coll %) (clojure.string/upper-case (str %))) coll))) 
          
          ; for each set #{A b c D}, make a map entry: {#{A b c D}, #{#{A b c "D"} #{A b "C" D} #{A "B" c D} #{"A" b c D}}}
          (get-subset-map [sets] (into {} (map #(vector % (get-subsets %)) sets))) 
          
          ; take one of the subsets #{A b c "D"} #{A b "C" D} #{A "B" c D} #{"A" b c D} and filter them by if they have a copy in the other subsets
          (get-intersect [subset-map pair] 
            (clojure.set/intersection
              (second pair)
              (apply clojure.set/union (vals (dissoc subset-map (first pair))))))
          
          ; #{A b "C" D} -> #{A b D}
          (remove-strings [i] 
            (set (map #(set (filter (comp (partial not= java.lang.String) type) %)) i)))
          
          ; for each answer, filter the original sets by whether none of the other answers is a subset. If the result is empty, then that answer is redundant, and is removed
          (remove-redundant [sets] (set 
            (filter (fn [ex] (seq
              (filter
                (fn [entry] (not-any? (fn [a] (clojure.set/subset? a entry)) (disj sets ex)))
                s)))
              sets)))
          
          ; Create a subset-map and use get-intersect on the values of each entry to see if there are any copies in the subsets.
          ; If not, then the key for that entry is NOT SIMPLIFIABLE. Then, remove the strings from the intersection to get the new simplified sets.
          ; Repeat until all sets are NOT SIMPLIFIABLE
          (simplify [sets]
            (let [subsets (get-subset-map sets)
                  intersect (partial get-intersect subsets)
                  final-entries (set (keys (filter (comp empty? intersect) subsets)))
                  remaining-entries (remove-strings (apply clojure.set/union (map intersect subsets)))]
              (if (empty? remaining-entries)
                final-entries
                (clojure.set/union (simplify remaining-entries) final-entries))))]
  
    (remove-redundant (simplify s))))

Stuart21:11:26

For lein projects I use lein test-refresh, is their an equivalent test runner that watches for changes and re-runs tests for deps.edn projects?

seancorfield21:11:12

@qmstuart Most CLI tools are listed on this page https://github.com/clojure/tools.deps.alpha/wiki/Tools#testing and it looks like Kaocha has a "watch" mode...

Stuart21:11:59

@seancorfield, thank you, wasn't aware of that page

seancorfield22:11:08

...that said, I think it's a better workflow to get used to evaluating code as you write it and running tests against them from your editor, so you don't need to switch contexts, and you don't need to worry about saving partially edited code causing a test watcher to fail etc. If you're evaluating code as you write it (and have "test" expressions in Rich Comment Forms) you can get fast, localized feedback directly in your editor (against the REPL), and you can eval and test code without even needing to save it to disk.

seancorfield22:11:30

I stopped using test watchers completely after I'd been doing Clojure for a couple of years. I still run test suites from the command-line as sanity checks on features/bug fixes before I push a branch, but mostly I run tests in my editor, as I'm working on code.

Stuart22:11:08

by rich comment blocks you mean (comment ,,, )

seancorfield22:11:32

Yes. A term coined by Stu Halloway to describe Rich Hickey's use of (comment ,,,) forms in code to contain scratch code/setup/REPL-based tests etc. I'd been doing that myself for quite a while before I heard Stu call them that -- has a nice ring to it!