Fork me on GitHub
#clojurescript
<
2024-01-22
>
itaied09:01:29

;; No stacktrace for e:

(go (try (let [result (<p! (some-fn-results-rejected-promise))])
           (catch js/Error e
             (throw e))))
;; There is a javascript stacktrace
(go (try (let [result (<p! (some-fn-results-rejected-promise))])
           (catch js/Error e
             (throw (js/Error e)))))
;; is it possible to access to cljs stacktrace? (which means i'll see that the error came from "some-fn-results-rejected-promise")?

thheller09:01:32

Short answer is: Do not use core.async for promise interop

🎯 1
👍 1
thheller09:01:03

JS doesn't have the concept of rethrowing exceptions like Java, so doing that is lossy

itaied09:01:39

what about propagations? core async makes the stacktrace disappear?

thheller10:01:13

like I said .. do not use core.async for this. Browsers have special support for Promises and async stacktraces, which is built-in and not extensible. Since Browsers do not know core.async they cannot do this stichting together of traces

thheller10:01:45

not core.asyncs fault, just a limitation of the platform

Chris McCormick10:01:02

Hello, I've again run into an API that wants me to use an AsyncIterator:

for await (const [key, value] of this.keyv.iterator()) {
      console.log(key, value); // Return: key and value 
};
I did a search here and came up with the following links: https://ask.clojure.org/index.php/10896/how-to-work-with-asynciterable-interface-in-cljs https://clojure.atlassian.net/browse/ASYNC-239 Which looks like there's no nice clean way to handle these. What's the current best practice for handling this situation in CLJS?

Roman Liutikov10:01:28

macros suggested in the linked post make sense

👍 1
nivekuil11:01:12

well, this was an unpleasant surprise.. this physics engine, rapier, uses super small floats as IDs and (= (hash -0.32553251) (hash -0.0000032553251)) is there a fast alternative?

p-himik12:01:12

Alternative to what? hash? Or the engine? Why do you need to compare hashes in the first place?

nivekuil12:01:19

a different way to hash floats to use as keys in a map

nivekuil12:01:56

comparing hashes is how hash maps work no?

p-himik12:01:33

To an extent.

p-himik12:01:12

You can store keys in a map that all have the same hash. But since those IDs are small, they will all have the same hash, which will result in O(n) access/insertion times. You can't override the built-in hash, but you can create an alternative map data structure implementation that uses a different hashing. E.g. you can first (* id 1000000) and hash it after or something like that. Alternatively, you can use a tree map. Both approaches introduce an issue where you have to painstakingly make sure that the map type is the one you expect.

p-himik12:01:49

Also, maybe the multiplication route is not feasible if the numbers can get quite big. In that case, it would make sense to come up with a proper hashing approach.

nivekuil12:01:16

yeah, I'm aware of the degenerate behavior 🙂 it's not the behavior in clojure or any other language i've used, so it's surprising. custom map type doesn't sound bad, just have to be careful about using these handles anywhere else I guess

p-himik12:01:10

Heh, but the underlying implementation uses u32 for IDs.

p-himik12:01:09

There's at least one instance where the bindings split some ID-looking f64 into two u32. Perhaps you can do the same and have a map not like id->something but [u32, u32]->something.

nivekuil12:01:14

I just converted the ID handle back to the js object it represents to use that as the key instead, I hash it elsewhere already so goog/getUid should already be cached, guessing it's pretty fast anyway

p-himik12:01:59

Just in case - getUid mutates the object. If that object cannot be mutated or is recreated, the value will be wrong.

p-himik12:01:56

cljs.user=> (def x (js/BigInt 7))
#'cljs.user/x
cljs.user=> (hash x)
1
cljs.user=> (hash x)
2
cljs.user=> (hash x)
3

nivekuil12:01:07

what a language. 2 number types, neither safe to hash

p-himik12:01:26

To be fair, the issue with BigInt comes from CLJS. :)

p-himik12:01:59

Or from the fact that JS doesn't care about hashes. Somehow.

dnolen15:01:48

the issue is we use JavaScript numerics for performance and interop reasons

dnolen15:01:26

the hashing thing doesn't really have anything to do w/ JavaScript - JavaScript doesn't have hashing

dnolen15:01:46

I added a bunch of comments on how I think it can be done - happy to see someone try it - will take look soon if no one else does

p-himik18:01:02

Curious - is that if-not a personal preference? Also, are there any notable performance considerations?

dnolen18:01:59

no, it's just a macro for (if (not ...) ...)

p-himik18:01:39

Oh sorry, by "performance considerations" I meant the hashing approach, not if-not.

dnolen18:01:04

... but it did remind to add a missing ^boolean

dnolen18:01:33

when it comes to hashing I just defer to whatever Clojure does - and if it bottoms out in JDK whatever JDK does

p-himik18:01:25

> ... but it did remind to add a missing ^boolean Oh... huh. Is there no way to do that automatically for all the known methods that always return a boolean? I feel like there's been a discussion or maybe even an issue about but can't recall exactly.

dnolen18:01:19

hrm, you're right that we can figure this out from externs, but I don't know if this case works

Jakub HolĂ˝ (HolyJak)17:01:08

Hello folks! Any tips how to troubleshoot “Max. call size stack exceeded” when the stack trace only contains core fns and none of my code? > Uncaught RangeError: Maximum call stack size exceeded > at Object.eval [as cljs$core$ILookup$_lookup$arity$2] (core.cljs:6871:1) > at Function.eval [as cljs$core$IFn$_invoke$arity$2] (core.cljs:1960:18) > at Object.eval [as cljs$core$IFn$_invoke$arity$1] (core.cljs:3354:6) > at Object.cljs$core$pr_sequential_writer [as pr_sequential_writer] (core.cljs:10289:20) > at Object.cljs$core$print_prefix_map [as print_prefix_map] (core.cljs:10560:4) > at Object.cljs$core$print_map [as print_map] (core.cljs:10574:8) > at Object.eval [as cljs$core$IPrintWithWriter$prwriter$arity$3] (core.cljs:10649:6) > at Object.cljs$core$prwriter [as prwriter] (core.cljs:778:16) > at Object.cljs$core$pr_writer_impl [as pr_writer_impl] (core.cljs:10360:10) > at cljs$core$pr_writer (core.cljs:10442:6) 🙏

✅ 1
p-himik17:01:20

What user action results in this exception? Seems like printing some object. So I'd inspect that object.

thheller17:01:21

what is the full trace?

thheller17:01:40

my first guess would be printing an atom containing itself, but that would have a deref in the trace

Jakub HolĂ˝ (HolyJak)17:01:22

That is the full stack trace that is printed. No user action, just loading my app. Printed by React ErroubBoundary, I know this happens in one particular component. But cannot find out what is trying to print what.

Jakub HolĂ˝ (HolyJak)17:01:49

Yes, I too suspect it is some infinite data problem, just need to find out where.

thheller17:01:09

you can usually set a breakpoint in the browser devtools and just step out

thheller17:01:19

that should usually take you to the problem code

Jakub HolĂ˝ (HolyJak)17:01:38

The question is where to set it 😅

thheller17:01:58

any of the above lines works

👀 1
thheller18:01:01

> But cannot find out what is trying to print what.

Jakub HolĂ˝ (HolyJak)18:01:17

Thank you, that helped!

thheller18:01:21

this could just be a side effect of something else calling theObject.toString() which invokes the printer

Jakub HolĂ˝ (HolyJak)18:01:42

When fulcro inspect installs itself, it tries to print something that blows up it seems.

Jakub HolĂ˝ (HolyJak)18:01:23

Though the paticular line is (log/info "Installing Fulcro 3.x Inspect" {}) so it is perhaps soemthing in Timber’s context or something…

Jakub HolĂ˝ (HolyJak)18:01:26

my bad, it might not be that pr-write that triggers the exc. but an earlier one 😅

Jakub HolĂ˝ (HolyJak)19:01:40

FYI I found it, it was my own pr-str one place in the code

Jakub HolĂ˝ (HolyJak)19:01:55

I guess the thing I tried to print was simply too large

Jakub HolĂ˝ (HolyJak)22:01:53

Thank you all for your help!

kennytilton23:01:52

"too large"? In a sense, but a stack overflow makes me think the "size" had to do with depth, and possibly a cyclic structure. That is why I asked about *print-level*. Binding that to some modest integer will let you see much of the data, but only so many levels deep.

💯 1
Jakub HolĂ˝ (HolyJak)21:01:25

You are most likely right that there was a cycle.

kennytilton21:01:58

If so, (binding [*print-level* 3] (prn <cyclic data>)) (untested) should work.

Jakub HolĂ˝ (HolyJak)08:01:55

indeed, it did, thanks!

🎉 1