Fork me on GitHub
#beginners
<
2020-08-25
>
stopachka01:08:42

Okay, one more, trying to figure out what I need to typehint to get this one:

URL signUrl(BlobInfo var1, long var2, TimeUnit var4, Storage.SignUrlOption... var5);
I write:
(.signURL storage
          ^BlobInfo blob-info
          15
          ^TimeUnit TimeUnit/DAYS
          (Storage$SignUrlOption/withV4Signature))
And get:
No matching method signURL found taking 4 args for class com.google.cloud.storage.StorageImpl
My guess is that I am putting the last argument Storage.SignUrlOption... var5 incorrectly -- it requires an array. If I try [(Storage$SignUrlOption/withV4Signature)] have the same no matching method error. If I try
(into-array
  Storage$SignUrlOption
  (Storage$SignUrlOption/withV4Signature))
I get Don't know how to create ISeq from: com.google.cloud.storage.Storage$SignUrlOption (may be misunderstanding what intro-array is supposed to do, thought ^ would type a list of SignURLOptions

seancorfield01:08:32

(Storage$SignUrlOption/withV4Signature) is going to give you a single Storage.SignUrlOption. Varargs in Java collapses to an array under the hood but it uses syntactic sugar to hide that.

seancorfield01:08:01

So you may have success with (into-array Storage$SignUrlOption [ (Storage$SignUrlOption/withV4Signature) ])

seancorfield01:08:17

Note the extra [ .. ] to make an actual vector @stopachka

seancorfield01:08:08

I'm not sure that will avoid the need for a type hint as well but it will correct the error you're getting.

stopachka02:08:23

Ah, thank you @seancorfield !!

seancorfield03:08:19

@stopachka Did you have to type hint the array, or was that change enough?

stopachka15:08:59

Hmm, just tried...and it still seems to have trouble:

(.signURL storage
          ^BlobInfo blob-info
          15
          ^TimeUnit TimeUnit/DAYS
          (into-array
            Storage$SignUrlOption
            [(Storage$SignUrlOption/withV4Signature)]))
No matching method signURL found taking 4 args for class com.google.cloud.storage.StorageImpl
URL signUrl(BlobInfo var1, long var2, TimeUnit var4, Storage.SignUrlOption... var5);
🤔

seancorfield16:08:04

@stopachka Do you have a URL for the docs for this, so I can see what other overloads there are?

stopachka17:08:40

Thanks for the help Sean! https://googleapis.dev/java/google-cloud-storage/latest/com/google/cloud/storage/Storage.html --- It seems to have only one overload 🤔 --- To sanity check, here's what the repl tells me when i check for every type var:

stopachka17:08:42

storage
#object[com.google.cloud.storage.StorageImpl 0x2d9299b6 "[email protected]"]
jt.core=> blob-info
#object[com.google.cloud.storage.BlobInfo 0x2ba685e "BlobInfo{bucket=, name=f86f25c2-9937-4891-ad4c-19d01358812f/image.png, generation=null, size=null, content-type=null, metadata=null}"]
jt.core=> TimeUnit/DAYS
#object[java.util.concurrent.TimeUnit 0x31329080 "DAYS"]
jt.core=> (into-array
  Storage$SignUrlOption
  [(Storage$SignUrlOption/withV4Signature)])
#object["[Lcom.google.cloud.storage.Storage$SignUrlOption;" 0x2521fe86 "[Lcom.google.cloud.storage.Storage$SignUrlOption;@2521fe86"]

seancorfield17:08:54

Try hinting storage as ^Storage storage... that's about the only thing I can suggest.

seancorfield17:08:22

Given there's only one .signUrl in the interface, I'm a bit surprised that it is even needing reflection, but maybe the StorageImpl class has multiple overloads for some reason (and that implementation class is not documented, of course).

joel38004:08:23

(match [event auth]
      ["login" _] "LoginAttempt"
      ["login" "success"] "LoginSuccess"
      ["login" "failure"] "LoginFailure"
How can I coax clojure to return a list of matching results? For the above, ["login" "failure"], I'd want ("LoginAttempt" "LoginFailure") returned. I realize I could just make the result a list, but I'll be repeating this pattern, and for coding/readability, I'd prefer to be able to list each result separately.

seancorfield04:08:22

Pretty sure you can't do that with core.match -- it just finds the best match I think? core.logic would allow you to find all solutions that match.

joel38005:08:30

ok, i'm not aware of core.logic

joel38005:08:03

I thought maybe i could apply (map ...) to above somehow.

joel38005:08:16

really all i want though is the matching part... i don't see how core.logic is related.

joel38005:08:02

i feel like with match i could apply somehow to each pattern result pair, with :else as maybe nil... then with map get rid of nils. but kind of vague how i could split up the structure in that way.

joel38005:08:21

(defn matchlist [binding & rest] --- need to rip out the :else part and then for each pair in "rest", map match to each pair something like that.

smith.adriane05:08:50

it doesn't seem like you lose much by replacing with a case statement:

(case event
  "login"
  (case auth
    "success" "LoginSuccess"
    "failure" "LoginFailure"
    "LoginAttempt"))

joel38006:08:19

actually this has similar problem where I would need to make everything a list:

(case event
  "login"
  (case auth
    "success" ("LoginAttempt" "LoginSuccess")
    "failure" ("LoginAttempt" "LoginFailure")
    ("LoginAttempt")))

joel38005:08:52

ok, that's kind of what i was looking for: legible alternatives.

smith.adriane05:08:03

if you want an open system (ie. the ability to dynamically add/change/modify responses), then defmulti may be a better fit

joel38005:08:31

let me ask this though: how do i split a list like this (a b c d e f ...) into pairs ([a b] [c d] [e f] ...)?

seancorfield05:08:45

In reality, people rarely use core.match, but I figured if you were already off into that sort of match/unification territory then core.logic is the next more generic place to go.

seancorfield05:08:36

user=> (partition 2 [:a :b :c :d :e :f])
((:a :b) (:c :d) (:e :f))
user=>

smith.adriane05:08:41

and if you need predicates, but the system is relatively closed, then you can look into cond

smith.adriane05:08:43

(cond
  (or (= event "login")
      (= event "authorize"))
  (str event auth)

  (and (= event "number")
       (even? num))
  (/ num 2))

joel38005:08:45

(defn matchlist [x & rest] (filter some? (map (partition 2 rest :else nil ) (partial (match x)))) i feel like something like this though would let me use the match approach. ill give it a try.

qythium05:08:54

That won't work because match is a macro which takes its arguments at compile time

joel38006:08:55

is the macro handling the underscore (match anything)?

qythium06:08:40

yup, you can try macroexpanding to see what it does

qythium06:08:31

Here's what it might look like in core.logic

(let [inp ["login" "failure"]]
  (l/run* [res]
    (l/matche [inp res]
      ([["login" _]         "LoginAttempt"])
      ([["login" "success"] "LoginSuccess"])
      ([["login" "failure"] "LoginFailure"]))))
;; => ("LoginAttempt" "LoginFailure")

joel38006:08:34

i will say match is overkill, i likely will only do use essentially equivalence or match anything.

seancorfield06:08:06

Yeah, I haven't needed core.match in a decade of production Clojure work, but I thought if you were already using that, you might be interested in core.logic 🙂 Thanks to @ for the example of how your problem would look with that (which, yeah, is overkill for most stuff -- and another thing I've never used in a decade of Clojure 🙂 ).

joel38006:08:13

ah interesting.

qythium06:08:23

then core.logic is definitely more overkill, it's another totally different paradigm to learn

joel38006:08:08

yeah, planning on using Clara, but for this particular use case i like the pattern matching (Elm-esque)

seancorfield06:08:48

Multimethods will get you most of the pattern matching you'll probably need -- and it's all built-in and easier to read/understand.

seancorfield06:08:18

(but multimethods will also only provide a single match/dispatch)

ramblurr06:08:40

Is it possible to enable/disable spec instrumentation on certain namespaces? [the sym-or-syms arg](https://clojure.github.io/spec.alpha/clojure.spec.test.alpha-api.html#clojure.spec.test.alpha/instrument) seems to require a collection of function names

alexmiller12:08:16

You can use enumerate-ns to get the functions in an ns to instrument

endrebak8510:08:06

I am having newb problems in cljs. I send an xhrio GET with:

(defn get-messages [] 
  (GET "/api/messages" ; line 67
       {:headers {"Accept" "application/transit+json"}
        :handler #(rf/dispatch [:messages/set (:messages %)])}))
Still, in my developer console I see:
xhrio.js:627 GET  404 (Not Found)
From the stacktrace I know that it is line 67 which fails. Why does it try to get "/messages", not "/api/messages"? Where can I begin to debug this?

endrebak8510:08:49

I have tried deleting all the .js and recompiling 🙂 Might there be other compilation output somewhere?

michael.e.loughlin10:08:30

is that the cljs-ajax library?

endrebak8512:08:17

@michael.e.loughlin I am using (ajax.core :refer [GET POST]) 🙂 which is cljs-ajax :)

endrebak8514:08:45

I don't know if my problem was due to it, but I was using the Chromium-based https://brave.com/ browser. Turning off shields/AdBlock for localhost made my error messages a lot easier to read.

michael.e.loughlin14:08:33

Doesn't Brave automatically rewrite urls? The example I saw was adding their own referral querystring param to particular websites...

wordempire15:08:05

How can I define a macro that adds java annotations to a gen-class invocation? I tried playing around with vary-meta but it seems to not work 😕 . My snippet is as follows:

(gen-class :name ^{Deprecated {}} ThisWorks)

(defmacro gen-class-with-Goal [class-name]
  (let [cname (vary-meta (symbol class-name) merge {Deprecated {}})]
    `(gen-class      :name ~cname)))

(gen-class-with-Goal ThisDoesNotWork)

wordempire15:08:03

using cider-macroexpand-1 they seem identical where it matters, but I must be doing something stupid, as there is no annotation present on the ThisDoesNotWork class 😕

alexmiller15:08:48

I think you're evaluating that symbol in the syntax quote

alexmiller15:08:56

you want to get the vary-meta in the expansion

wordempire15:08:59

I can kind of see what you mean, but the expanded call to gen-class-with-Goal is already: (gen-class :name ^{java.lang.Deprecated {}} ThisDoesNotWork)

wordempire15:08:49

running cider-macroexpand-1 after (setq cider-macroexpansion-print-metadata 1) (in emacs) seems to indicate so, but perhaps I am not looking at things correctly

alexmiller15:08:06

user=> (macroexpand-1 '(gen-class-with-Goal Foo))
(clojure.core/gen-class :name Foo)

alexmiller15:08:09

you want that to instead expand to:

(clojure.core/gen-class :name (vary-meta Foo merge {Deprecated {}}))

alexmiller15:08:27

that is, vary-meta at runtime, not at compile time

wordempire16:08:17

I don't think that works as gen-class seems to generate a (vary-meta <rest-of-my-classname> class, even if I simply copy your code 😕

wordempire16:08:45

wow, I actually found a post that answers my specific issue: https://groups.google.com/g/clojure/c/Ee1bVwcUT-c . Thanks for putting me on the right track @

alexmiller16:08:56

common macro question

leftzav16:08:49

Hi undergrad and new to clojure , I recently had an interview and after the interview they sent me an assignment which a small program so that I do a code review, any hints on how to do this would be really helpful

jr0cket18:08:52

When I am reviewing code I open it in a Clojure editor and run a repl, then evaluate the code, first the whole code then specific functions and expressions, until I know what each part is doing. If I am unsure of particular expressions or functions, I will run a debugger and step through the code. I will also pull apart expressions and evaluate then with different values. Experimenting with the code leads to ideas of alternative approaches and using the REPL will provide instant feedback as you try different ideas. Use a rich comment block or a separate design-journal namespace to collect your thoughts and code, so that others can do the same with your feedback.

mimunzar17:08:50

Hello, :) I have a design question. I am writing a program for processing Ethereum transactions. The program processes block after block until it reaches current end of a block chain. Than it waits for a new block to appear. Do I stretch too much that I could model this using lazy sequence? Something like this in pseudo code:

(defn process-blockchain [blockchain]
        (process-block (first blockchain))
        (process-blockchain (rest blockchain)))


    (defn create-blockchain [block-number]
        (lazy-seq
            if (next-block-available? block-number)
                (fetch-block (inc block-number))
                (wait-for-block (inc block-number))))
Thank you. It is my first Clojure program. :)

alexmiller17:08:55

generally, if you care much about the exact timing of realization (and I think this probably falls into that case), I would not use lazy seqs

alexmiller17:08:14

and instead use loop/recur or a core.async channel, or something else

mimunzar17:08:51

Thank you Alex, will have a look into those. 👍

alexmiller17:08:46

the reason for this is that Clojure does not make guarantees about how lazy things are, and some sequence functions (map, filter, etc) amortize the cost of realization by realizing chunks at a time, usually 32 elements

alexmiller17:08:08

and others are more or less lazy about the first item, etc

mimunzar17:08:14

Understand. Thank you! 🙂