Fork me on GitHub
#beginners
<
2021-12-31
>
metehan00:12:25

what does *Cannot infer target type in expression* means

metehan00:12:14

(.then (.symbol (:contract @state-data)) #(js/console.log %)) ;this works fine
(.then (.balanceOf (:contract @state-data) addr1) #(js/console.log %)) ;this gives the error

metehan00:12:17

I couldn't find any help on stackoverflow or github or documentation

ghadi00:12:12

Please paste what you typed in

ghadi00:12:20

And the full output

ghadi00:12:38

Ah, thanks. Slack glitch

metehan00:12:45

WARNING in app/cards/ethers.cljs
  52 |      [:button {:on-click #(log (:contract @state-data))} "Log: contract from state data"] [:br]
  53 |      [:button {:on-click (fn [] (.then (.decimals (:contract @state-data)) #(js/console.log %)))} "Log: Erc20 decimals"] [:br]
  54 |      [:button {:on-click (fn [] (.then (.symbol (:contract @state-data)) #(js/console.log %)))} "Log: Erc20 symbol"] [:br]
  55 |      [:button {:on-click (fn [] (.then (.balanceOf (:contract @state-data) addr1) #(js/console.log %)))} "Log: Erc20 Balance"] [:br]
----------------------------------------------^---------------------------------
Cannot infer target type in expression (. (:contract (clojure.core/deref state-data)) balanceOf addr1)

metehan00:12:17

and here is the whole code: https://codeshare.io/eVmLg7

metehan01:12:54

instead of this dot notation (.balanceOf (:contract @state-data) ...) I started to use (aget (:contract @state-data) "balanceOf") now it's working. but still I would like to know what does *Cannot infer target type in expression* means

seancorfield02:12:39

@UJ35GLZU7 The fact that aget works but trying to "call" balanceOf does not, suggests that it's a field, not a method. Maybe try (.-balanceOf (:contract @state-data)) and see if that works?

seancorfield02:12:01

(which is a bit odd, based on my reading of that code you shared, but I don't do much cljs and I know nothing about cryptocurrency -- and generally avoid it and the people who work with it 🙂 )

seancorfield02:12:38

The error message says that the ClojureScript cannot determine the type of the expression well enough to be able to compile the dot-expression -- which, as I say, seems odd since those other invocations all seem to work on (:contract @state-data) -- and, based on the source of the cljs compiler, seem most likely to be triggered when you try to access fields of Object or of non-JS data where the field is not resolvable against an existing extern(? whatever that means in cljs/js).

dpsutton04:12:12

if you are using shadow-cljs this section has information for you: https://shadow-cljs.github.io/docs/UsersGuide.html#infer-externs

metehan10:12:47

(.-balanceOf (:contract @state-data)) caused exact same error. after I read infer-externs I understood whats going on finally 🙂 so first code I had works as expected but when shadow-cljs compiles it didn't recognize it as a method. thank you for your time seancornfield, dpsutton 🙏

seancorfield16:12:13

@UJ35GLZU7 Good to know! We've both learned things from this thread!

Steiner08:12:27

here is a scheme macro for thread-last

(define-syntax ~>>
  (syntax-rules ()
    ((_ value)
     value)
    ((_ value (subr args ...) other-clauses ...)
     (~>> (subr args ...  value) other-clauses ...))
    ((_ value subr other-clauses ...)
     (~>> (subr value) other-clauses ...))))
and I want to write a thread-last macro myself, reference this scheme macro, how should I write it ??

Benjamin11:12:53

(defmacro ->>
  "Threads the expr through the forms. Inserts x as the
  last item in the first form, making a list of it if it is not a
  list already. If there are more forms, inserts the first form as the
  last item in second form, etc."
  {:added "1.1"}
  [x & forms]
  (loop [x x, forms forms]
    (if forms
      (let [form (first forms)
            threaded (if (seq? form)
              (with-meta `(~(first form) [email protected](next form)  ~x) (meta form))
              (list form x))]
        (recur threaded (next forms)))
      x)))
this is the definition in core.clj

Ben Sless15:12:53

I experimented with implementing scheme like macros with meander https://gist.github.com/bsless/ef07a7ab21a614720a36c698b5121d6e

Steiner15:12:11

eh, is this ok ?

(defmacro thread-last
  ([value] value)
  ([value next-expr & other]
   (if (symbol? next-expr)
     `(thread-last (~next-expr ~value) [email protected])
     (let [[subr & args] next-expr]
       `(thread-last (~subr [email protected] ~value) [email protected])))))
I have test it with
(assert (=
         (->> (range)
            (map #(* % %))
            (filter even?)
            (take 10)
            (reduce +))
         (thread-last (range)
                      (map #(* % %))
                      (filter even?)
                      (take 10)
                      (reduce +)))

        "Fuck You"
        )


(assert (=
         (->> (range)
            (filter even?)
            (take 5))
         (thread-last (range)
                      (filter even?)
                      (take 5)))
        "Fuck You")
it works fine

dpsutton08:12:35

interesting that that does some pattern matching. that's quite nice

Steiner15:12:26

I have a problem while writing macro, in expr

(defmacro thread-last
  ([value] value)
  ([value next-expr & other]
   (if (symbol? next-expr)
     `(thread-last (~next-expr ~value) [email protected])
     (let [[subr & args] next-expr]
       `(thread-last (~subr [email protected] ~value) [email protected])))))
does the ~next-expr mean replace the ~next-expr with the s-expression of next-expr, or evaluate the next-expr ?

Swapneil16:12:27

The former, I believe.

Alex Miller (Clojure team)16:12:06

syntax quote is quoting (so read but not evaluate). - is unquote so will evaluate the unquoted form

Swapneil16:12:25

Hm. I may actually need clarification on this as well. If next-expr was (+ 1 2), would 3 be inserted, or would we insert (+ 1 2) and then evaluate the output expression after macroexpansion was complete? (e.g. would (defmacro tester [x] `(quote ~x)) give out (+ 1 2) or 3?)

Alex Miller (Clojure team)16:12:57

It would be 3 in this case

Alex Miller (Clojure team)16:12:48

In the first question that is

Alex Miller (Clojure team)16:12:47

In the second, it would be (+ 1 2)

Swapneil16:12:13

Ah, ok, so internally it's first inserting the S-exp, and then it evals the resulting expression like any other code, but we only actually see the end result after the eval. Same as Common Lisp, then.

Alex Miller (Clojure team)16:12:11

There is no “inserting”, unquote just turns on normal eval

👍 1
Alex Miller (Clojure team)16:12:12

Inside a syntax quoted form

👍 1
Swapneil16:12:07

Yes, I was referring to the whole situation of unquoting an input to a macro in a syntax quoted form inside the macro. In non-macro code I assume `(quote ~(+ 1 2)) would give us (quote 3) as a result (and my REPL agrees)

Alex Miller (Clojure team)16:12:52

Macros are not special - they're just functions that get uneavluated forms

Alex Miller (Clojure team)16:12:13

You can use syntax quote at your repl or anywhere else

Steiner16:12:34

@U064X3EF3 but how do you explain this code

(assert (=
         (->> (range)
            (map #(* % %))
            (filter even?)
            (take 10)
            (reduce +))
         (thread-last (range)
                      (map #(* % %))
                      (filter even?)
                      (take 10)
                      (reduce +)))

        "Fuck You"
        )
if is evaluate, the (range) should be a infinite sequence, and clojure will calculate forever, right ?

Alex Miller (Clojure team)16:12:04

If you haven't found it yet, macroexpand-1 is useful for checking what a macro expands to

Alex Miller (Clojure team)16:12:16

->> is not evaluating that first form, just emitting it unevaluated

Steiner16:12:58

oh, shit. I got it.

Alex Miller (Clojure team)16:12:00

In yours, this is value, and you also don't evaluate it

Alex Miller (Clojure team)16:12:13

Or I guess you do in the latter arity

Alex Miller (Clojure team)16:12:49

Although range is lazy so it's not realized