This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-08-22
Channels
- # announcements (13)
- # babashka (22)
- # beginners (22)
- # biff (17)
- # calva (6)
- # clerk (20)
- # clj-kondo (25)
- # clj-together (5)
- # clj-yaml (20)
- # cljdoc (16)
- # cljs-dev (1)
- # clojure (42)
- # clojure-brasil (1)
- # clojure-europe (26)
- # clojure-nl (6)
- # clojure-norway (24)
- # clojure-turkiye (3)
- # clojure-uk (5)
- # clojurescript (37)
- # core-async (7)
- # core-logic (2)
- # datalevin (7)
- # datomic (43)
- # events (2)
- # fulcro (7)
- # gratitude (1)
- # hyperfiddle (7)
- # java (7)
- # jobs (3)
- # lsp (4)
- # off-topic (16)
- # pathom (18)
- # polylith (1)
- # portal (27)
- # reitit (4)
- # releases (3)
- # shadow-cljs (47)
- # tools-build (14)
- # tools-deps (16)
- # yamlscript (11)
How can I run a function property from js?
I have a lib client
with a function name start
.
Executing the following code works:
(.start client "2")
But this doesn't:
((.-start client) "2")
What am I missing about js interop?what does it mean that the latter doesn't work?
I guess, most likely it's a runtime error coming from JS and is related to this
in this case it's not an interop issue, but JS semantics in accordance to how this
works, read more on this
in JS and method binding
There are a few tools out there that may help you a bit: https://roman01la.github.io/javascript-to-clojurescript/#share-link=120,156,133,145,193,82,194,48,20,69,247,249,138,103,87,5,105,33,148,13,173,186,114,235,71,132,36,216,12,157,38,54,169,150,97,216,235,111,250,37,190,52,180,48,214,25,183,57,247,221,119,223,205,190,173,185,83,186,6,161,172,139,13,93,128,89,207,224,68,0,184,174,173,3,6,143,96,104,218,65,130,32,237,138,17,236,2,56,6,112,44,8,146,70,186,182,169,225,133,185,50,181,111,141,139,25,204,209,225,30,197,115,216,205,10,114,38,196,91,47,151,32,59,83,41,174,208,167,210,252,0,150,107,35,71,111,67,209,252,4,93,14,152,231,152,67,178,133,243,117,179,89,15,52,217,244,152,102,30,143,92,32,190,189,102,68,186,146,105,165,95,227,232,25,41,171,185,204,33,194,112,34,40,212,30,98,1,79,176,10,231,143,5,152,206,27,246,55,53,186,173,69,236,245,3,159,88,130,178,96,180,85,78,189,203,187,104,1,209,247,215,167,95,226,109,250,185,179,47,1,11,192,105,65,252,206,21,238,164,215,202,71,199,254,61,242,165,129,172,172,236,243,81,120,24,242,253,171,221,162,54,217,254,33,14,32,10,223,225,147,48,43,137,253,80,142,151,184,225,50,128,111,176,201,111,122,40,177,4,58,61,188,188,148,177,107,36,59,20,195,100,150,79,132,217,111,161,144,123,214,86,110,170,140,46,164,183,10,49,127,0,90,19,187,175 https://nextjournal.com/fndriven/cljsjsinterop It would help if you share the original js code.
I've found this post by @U0W0JDY4C to be a valuable resource: https://www.bitsbyluke.com/2018/10/20/clojurescript-interop-with-javascript.html
im receiving this error
:repl/exception!
;
; Execution error (TypeError) at (<cljs repl>:1).
; this.start is not a function
It does seems like because it loses the scope of this
.
Can I run it dynamically in cljs somehow?
I want to receive the name of a function and call it from a js class client lib
same as in JS: get the reference to the function from an object/instance, bind it, done
(let [f (aget object "function-name")
f (.bind f object)]
(f 1 2 3))
A tangential note - don't use aget
to get properties from objects.
For function names that aren't valid identifiers or are only known at run time, there's js-invoke
(which also doesn't have the this
problem since it uses .apply
).
For properties, there's goog.object/get
.
When I'm requiring a library from js (using shadow) do I need to add it to another place other than package.json?
I'm facing this problem:
Module not provided: module$node_modules$$fusionauth$typescript_client$dist$fusionauth_typescript_client_min
(:require ["@fusionauth/typescript-client" :refer [FusionAuthClient]])
You shouldn't have to do anything else. No clue where the error is coming from, perhaps there's a configuration issue or the NPM package is doing something weird.
Might be relevant: https://github.com/thheller/shadow-cljs/issues/840
But I don't see any dynamic import
or require
calls in the file here: https://unpkg.com/browse/@fusionauth/[email protected]/dist/fusionauth-typescript-client.js
I'd try changing the :require
to "@fusionauth/typescript-client/dist/fusionauth-typescript-client.js"
.
If that doesn't work, maybe "@fusionauth/typescript-client/build/index.js"
will.
I mean the loading the code part, no clue if you actually need to use it some way to trigger the error
Hey everyone, since it just came up on the #clojure channel, this is my one (and probably only) attempt to campaign for upvotes on this issue:
• https://ask.clojure.org/index.php/6574/letfn-collisions-across-namespaces
TL;DR – if you're using letfn
in ClojureScript you're liable to get burned by broken scoping and name collisions at some point, so come add your vote.
since the example calls defn outside of the top level, i dont know whether this is really a bug or simply UB
For comparison: The following works ok (does not mix up the fns "c" in the globally defined functions' respective closure):
dev:cljs.user=> (def d
(letfn [(c [] 42)]
(fn []
(c))))
#'cljs.user/d
dev:cljs.user=> (d)
42
dev:cljs.user=> (def dd
(letfn [(c [] 47)]
(fn []
(c))))
#'cljs.user/dd
dev:cljs.user=> (dd)
47
dev:cljs.user=> (d)
42
@U08JKUHA9 There is no “basically top level”. One either uses defn
at the top level or doesn’t. I am not sure if Clojure treats forms within a top-level let
form as top-level forms, but this is important to note because def
is intended to be used specifically at the top level. Any other usage working is incidental at best and not an intended use case.
I have to disagree @U0479UCF48H, there are plenty of perfectly valid use cases where defn
isn't used at the top-level:
• letfn
(or let
) is used at the top-level to define a very specific helper function one doesn't want to pollute the namespace with, for a nested defn
.
• An alternative defn
-like macro that evaluates to a do
block that does things in addition to the nested defn
(possibly also adding additional nested defn
s), as used in Guardrails and Ghostwheel for example.
• A macro that transforms a re-frame or other function registration (subscription, event, etc.) by extracting the anonymous fn
into a defn
and passing that to the registration function (both of which are nested in a top-level do
block) or alternatively replacing the nested fn
with a @(defn
. This will be used in the next version of Playback to support subscription/event replay in an identical manner to defn
replay.
This is just off the top of my head. I don't think this is remotely comparable to the https://clojure.org/guides/faq#keyword_number which was a case of "you were holding it wrong, but now that you did, we're going to keep supporting it".
Nested defn
s are legit and I think this is a very clear case of a grave ClojureScript-specific local-scope-breaking compiler bug.
Per https://clojure.org/reference/special_forms#def
> Using def
to modify the root value of a var at other than the top level is usually an indication that you are using the var as a mutable global, and is considered bad style. Consider either using binding to provide a thread-local value for the var, or putting a https://clojure.org/reference/refs or https://clojure.org/reference/agents in the var and using transactions or actions for mutation.
But isnt defn
equiavlent to a def
anyway? From the docstring of defn
,
>
clojure.core/defn
> ([name doc-string? attr-map? [params*] prepost-map? body] [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])
> Macro
> Same as (def name (fn [params* ] exprs*)) or (def
> name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
> to the var metadata. prepost-map defines a map with optional keys
> :pre and :post that contain collections of pre or post conditions.
Maybe someone from core can help clarify, but this docstring signals to me that defn
should be treated as a specific kind of def
. So in particular, not using defn
at the top-level is not an intended use case.
While defn
does in fact desugar to def
, my understanding of the http://clojure.org documentation you posted is that it refers specifically to the direct usage of def
, not "anything that desugars to def". I've seen too many perfectly legitimate usages of nested defn
s to interpret it otherwise. I can not think of any examples where that would be the case for def
.
But in a way, this is beside the point. Even from the documentation it's clear that even nested def
s are supported, it's just usually a sign that you're doing something wrong (and I agree).
I see. The reason I am bringing this up at all is because there are some instances where people report bugs, but core interprets the situation as “garbage in, garbage out”. Off the top of my head:
• providing indices to a vector past INT_MAX: https://ask.clojure.org/index.php/11080/get-find-assoc-vectors-overflows-key-when-passed-large-longs
• sorted sets throwing exceptions when looking up elements with mismatching type https://ask.clojure.org/index.php/11409/somewhat-confusing-sorted-set-behavior
• providing arbitrary strings to #uuid tagged literal (e.g. #uuid "foobar"
) — works in CLJS, not in CLJ, but this is not considered a bug
• and so on
Overall, I am trying to probe whether the reported behavior of letfn
is a legitimate bug or a case of “garbage in, garbage out”.
I see where you're coming from. I'm arguing that yes, it is very much a legitimate usage, there's a ton of widely used macro code out there that couldn't be easily written (or at all) without nested defn
s.
...and I believe the documentation also supports this by stating that basically "if you're doing it like this, it's usually a bad idea"
And like I said, I also think that the def
vs defn
distinction does matter here and I would go as far as to say that while a nested def
is usually an indication that something's off, a nested defn
, especially as described in the letfn
examples above, is usually not.
Thanks for taking the time to explain this, btw. These arguments are pretty convincing, so I’m going to upvote the askclojure issue, in hopes that core takes a closer look at it 🙂
This was a pleasantly non-confrontational disagreement, thank you as well, and also for supporting the cause. 🙂
And on a side note, this bug clearly irks a lot of people, because a couple of hours after posting it, it is now the number one open ClojureScript issue on http://ask.clojure.org – thanks everyone for upvoting.