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.

alexmiller16: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?)

alexmiller16:12:57

It would be 3 in this case

alexmiller16:12:48

In the first question that is

alexmiller16:12:47

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

alexmiller16:12:02

Because of the quote

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.

alexmiller16:12:11

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

👍 1
alexmiller16: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)

alexmiller16:12:52

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

alexmiller16: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 ?

alexmiller16:12:04

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

alexmiller16:12:16

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

Steiner16:12:58

oh, shit. I got it.

alexmiller16:12:00

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

alexmiller16:12:13

Or I guess you do in the latter arity

alexmiller16:12:49

Although range is lazy so it's not realized