Fork me on GitHub
#beginners
<
2020-06-20
>
adam03:06:20

Is there a room to optimize this little function (it's working fine):

(defn grab
  "When the predicate is true, use the first map to extract the key's value. Use the second map otherwise."
  [key pred? first-map second-map]
  (let [val-map (if pred? first-map second-map)
        keywordized (keywordize-keys val-map)]
    (key keywordized)))
Passing tests:
(deftest grab-test
  (testing "Order and keyword/string support."
    (is (= (grab :name true {:age 50 :name "Jack"} {"age" 10 "name" "Mark"}) "Jack"))
    (is (= (grab :name false {:age 50 :name "Jack"} {"age" 10 "name" "Mark"}) "Mark"))))
Note that first-map second-map keys may be strings or keywords, is it worth it to check or the check might be more expensive than the conversion?

noisesmith13:06:03

(or (m (name k)) (m (keyword k))) - the map acts as a function looking up a key

adam17:06:07

Ah this is great, thanks

sova-soars-the-sora03:06:29

what does keywordize-keys do in the let ?

adam03:06:32

(is (= (grab :name false {:age 50 :name "Jack"} {"age" 10 "name" "Mark"}) "Mark")) would fail without it since it's string indexed

seancorfield03:06:39

If key is always a keyword, you could do (if (contains? val-map key) (key val-map) (get val-map (name key))) (and avoid the keywordize stuff altogether.

seancorfield03:06:13

If it isn't, then you could do (let [k (keyword key)] (if (contains? val-map k) (k val-map) (get val-map (name k))))

seancorfield03:06:48

Calling keyword on a keyword just returns it. Calling name on a keyword returns the string version of it.

seancorfield03:06:13

Either way, no need to keywordize the val-map @somedude314

adam03:06:38

Awesome thanks, key is always a keyword

Hlodowig06:06:39

Hi y'all. I'm having this weird issue. I'm doing some Gmail stuff based on https://developers.google.com/gmail/api/guides/sending. I have these two dependencies in my project.clj among others:

[com.sun.mail/javax.mail "1.6.2"]
[javax.mail/javax.mail-api "1.6.2"]
And I get this error when tryng to build it:
Syntax error compiling at (dbc_balance/gugul.clj:43:51).
Unable to find static field: parse in class javax.mail.internet.InternetAddress
I tried this out in Java with the same dependencies and got no errors whatsoever. I built this stuff with leiningen and did a deps.edn project too w/o any success. Thanks in advance.

jumar10:06:49

@U01594NEC00 what is in dbc_balance/gugul.clj at given location? It looks like you're calling InternetAddress/parse incorrectly - see also https://stackoverflow.com/questions/35199808/clojure-unable-to-find-static-field

jumar10:06:26

In particular, it looks like you're treating the InternetAddress/parse method (https://javaee.github.io/javaee-spec/javadocs/javax/mail/internet/InternetAddress.html#parse-java.lang.String-) as a field

Hlodowig21:06:45

Thanks for your help @U06BE1L6T. This is what I was doing

(-> email (.setFrom (new InternetAddress from))
        (.addRecipients (Message$RecipientType/TO (map InternetAddress/parse to)))
        (.setSubject subject)
        (.setText body))))

Hlodowig21:06:33

Seems I must wrap InternetAddress/parse with an anonymous function in order for this to work..

Hlodowig22:06:52

Changed it to

(.addRecipients Message$RecipientType/TO (into [] (map (fn [x] (InternetAddress/parse x)) to)))

jumar06:06:15

You can also use the literal: #(InternetAddress/parse %)

Binny Zupnick07:06:23

Going through Brave and True, it defines data structures such as {:pegged true, :connections {6 3, 4 2}} .

Binny Zupnick07:06:52

Something tough to get used to, coming from OOP, is the lack of naming or clarity just by looking at things

3
Binny Zupnick07:06:01

on one hand I assume I'd get used to it, but it's hard not to think that it's inherently more readable to do something like:

{:pegged true, :connections [{:destination 6 :fly-over 3}  {:destination 4 :fly-over 2]}

sova-soars-the-sora12:06:23

this is more readable to me as well. maybe he is just demonstrating the flexibility of "maps" but i like your naming better.

Binny Zupnick07:06:57

but it seems pretty standard in Clojure to prefer minimalist variable namings and data structures where as in OOP it's been beaten into me NEVER to use names like 'x'. Maybe variable names and these types of data structures are two different conversations, though

David Pham08:06:42

Hi everyone, is there a way to load some namespace on start using deps.edn?

lsenjov08:06:16

As a main run entry? Or secondary?

lsenjov08:06:51

The former is declaring a (defn main- [& args] ...) and using -m namespace.core

lsenjov08:06:26

The latter is putting -i path/to/file.clj before your -m ... argument

lmergen10:06:27

is there some easy function that allows me to express 'double precision but not NaN or Inf' ?

lmergen10:06:47

my (small) problem is that i need it to work on clj + cljs, so i can't use Double/isNaN easily

lmergen10:06:08

and i was a bit surprised that here are no functions for this out of the box

David Pham11:06:21

Did you try double-in with specs?

lmergen11:06:04

this is exactly what i was looking for!!

David Pham11:06:16

My pleasure :)

Michael J Dorian12:06:59

Hey friends, I'm using http-kit to handle a post request for a form (basically a single text input field and a submit button) In the request map I get back :body which is a org.httpkid.BytesInputStream, which I can treat as a java input stream and convert to a string with

(defn BytesInputStream-to-string
  "This _must_ be the wrong way to do this"
  [^org.httpkit.BytesInputStream bytes offset]
  (.skip bytes offset)
  (apply str
         (map
          #(char %)
          (loop [acc []]
            (let [byte (.read bytes)]
              (if (not= byte -1)
                (recur (conj acc byte))
                acc))))))
But I feel like this can't possibly be the intended way to read posted form data with httpkit. For reference the caller to this function looks like this:
(defn print-post-handler
  [request]
  (let [pass (BytesInputStream-to-string (:body request) 9)] ; skip the "inputVar=" portion of the input with an offset of 9
    pass))

sveri13:06:35

There are several middlewares that do stuff with the incoming request. One would be ring.middleware.json which contains: wrap-json-body wrap-json-response that wrap the request and response body, converting the input stream into clojure datastructures and the return response into json

Michael J Dorian13:06:40

Ah, excellent. Thanks simple_smile

jacklombard16:06:23

Am I doing something wrong here (js/window.getEventListeners <dom-node>) throws window.getEventListeners is not a function

Kelsey Sorrels16:06:26

(.getEventListeners js/window <dom-node>)`

phronmophobic17:06:13

where is getEventListeners coming from? doesn’t seem to be a built in function, https://developer.mozilla.org/en-US/search?q=getEventListeners

jacklombard17:06:58

Aaron tried that too, doesn’t work

phronmophobic17:06:10

if it did exist, (js/window.getEventListeners <dom-node>) should work fine

jacklombard17:06:20

window.getEventListeners(node) works in chrome

phronmophobic17:06:29

it appears to be part of the google chrome console utilities

jacklombard17:06:45

Yup just figured

Kazuki Yokoyama18:06:42

In Elixir, atoms (keywords in Clojure, e.g., :some-identifier) are kept in memory for the application's lifetime. Does the same happen in Clojure?

Alex Miller (Clojure team)18:06:09

They are interned and gc’ed if needed

vlad_poh20:06:26

Howdy y'all

👋 3
Michael Stokley21:06:19

if i s/def a spec in a given namespace, how should i refer to it from another namespace?

seancorfield21:06:56

@michael740 By it's name. Specs have (qualified) keywords as their "names".

seancorfield21:06:23

If you use ::foo that resolves to foo in the current namespace. If you use ::bar/foo that resolves according to the alias bar (i.e., per a require [some.namespace :as bar] -- so ::bar/foo would resolve to :some.namespace/foo)

seancorfield21:06:03

Spec names do not have to correspond to namespaces.

seancorfield21:06:33

So we have things like (s/def :something/whatever ...) and that is referred to as :something/whatever everywhere.

Michael Stokley21:06:01

spec names are global, and can be referred to from any namespace, regardless of which namepace the spec was s/def-ed in?

seancorfield21:06:18

Specs are held in a central, global registry, accessed via their name -- either a keyword or a symbol (s/fdef some-fn ...)

seancorfield21:06:51

(you can actually s/def on a symbol too but that would be very unusual)

Michael Stokley22:06:19

great, this is working! thanks again, Sean.

juniusfree22:06:37

First time asking here. I'm confused with this: ((hash-map :a 1, :b 2, :c 3) :b). Why is this a correct syntax? I'm still in chapter 3 of brave clojure, so I'm not sure if it'll be discussed on other chapters. Examples in chapter 3 only uses keyword lookup like in (:b {:a 1, :b 2, :c 3}) to get the value from the map. TIA.

nate22:06:40

You can use a map as a function, so the first form is doing that. It's the same as ({:a 1, :b 2, :c 3} :b). Also, keywords act like a function that looks themselves up, which is why the second form (`(:b {:a 1, :b 2, :c 3})`) works. Usually in code the map is not right in there, so it looks more like this (for a map called users): (users 123). You can also use the get function to make it more explicit if that's clearer: (get users 123)

👍 3
juniusfree23:06:42

@nate What's the underlying principle behind "map as a function"? I just can't get my head around it yet. Thank you.

noisesmith13:06:37

if you look at the mathematical definition of "function", a hash-map is closer to meeting that definition than most functions are

nate23:06:16

I think it comes from the idea that a map maps from keys to values, and so they're kinda like functions in that you give them the key (like an argument) and you get a value (like a return value).

👍 3
nate23:06:46

so because it looks like a function, might as well use it like a function

👍 3