Fork me on GitHub
#beginners
<
2020-08-25
>
stopa01: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) ])

❤️ 3
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.

seancorfield03:08:19

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

stopa15: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);
:thinking_face:

seancorfield16:08:04

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

stopa17: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 :thinking_face: --- To sanity check, here's what the repl tells me when i check for every type var:

stopa17:08:42

storage
#object[com.google.cloud.storage.StorageImpl 0x2d9299b6 "com.google.cloud.storage.StorageImpl@2d9299b6"]
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.

👍 3
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).

❤️ 3
Joel04: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.

Joel05:08:30

ok, i'm not aware of core.logic

Joel05:08:03

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

Joel05:08:16

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

Joel05: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.

Joel05: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.

phronmophobic05: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"))

Joel06: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")))

Joel05:08:52

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

phronmophobic05:08:03

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

Joel05: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=>

phronmophobic05:08:41

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

phronmophobic05:08:43

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

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

Joel05: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.

yuhan05:08:54

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

Joel06:08:55

is the macro handling the underscore (match anything)?

yuhan06:08:40

yup, you can try macroexpanding to see what it does

yuhan06: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")

Joel06: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 @qythium 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 🙂 ).

Joel06:08:13

ah interesting.

yuhan06:08:23

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

Joel06:08:08

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

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 @qythium 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 🙂 ).

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)

Casey06: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

Alex Miller (Clojure team)12:08:16

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

Endre Bakken Stovner10: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?

Endre Bakken Stovner10:08:49

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

mloughlin10:08:30

is that the cljs-ajax library?

Endre Bakken Stovner12:08:17

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

Endre Bakken Stovner14: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.

mloughlin14:08:33

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

👍 3
Jelle Licht15: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)

Jelle Licht15: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 😕

Alex Miller (Clojure team)15:08:48

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

Alex Miller (Clojure team)15:08:56

you want to get the vary-meta in the expansion

Jelle Licht15: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)

Jelle Licht15: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

Alex Miller (Clojure team)15:08:06

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

Alex Miller (Clojure team)15:08:09

you want that to instead expand to:

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

Alex Miller (Clojure team)15:08:27

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

Jelle Licht16: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 😕

Jelle Licht16: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 @U064X3EF3

lefteris16: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

practicalli-johnny18: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.

Milan Munzar17: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. :)

Alex Miller (Clojure team)17: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

Alex Miller (Clojure team)17:08:14

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

Milan Munzar17:08:51

Thank you Alex, will have a look into those. :thumbsup:

Alex Miller (Clojure team)17: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

Alex Miller (Clojure team)17:08:08

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

Milan Munzar17:08:14

Understand. Thank you! 🙂