Fork me on GitHub
#clojurescript
<
2020-06-08
>
flyboarder00:06:34

If anyone would like to help me hack the cljs compiler, im adding native class support

lilactown01:06:53

are you intending to submit a patch?

flyboarder01:06:30

not currently, I think this needs some real world testing first

lilactown01:06:02

there's an open JIRA I submitted recently about this exactly

flyboarder01:06:50

yeah I have read it, my personal use case is on node.js with a project that requires I extend existing classes

lilactown01:06:56

nice. if it's any inspiration, here's the syntax I chose for helix (a react wrapper) for creating a React class:

(defcomponent MyClass
  (foo [this]
    ,,,)

  ^:static (bar [this] ,,,))

lilactown01:06:03

Yep v similar!

lilactown01:06:00

I could imagine like:

(defclass MyClass :extends SomeOtherClass
  ,,,)

flyboarder03:06:55

@lilactown this is the exact syntax I was also thinking!

flyboarder03:06:14

or MyClass :implements SomeInterface

Spaceman04:06:11

For this line:

(.val (js/jQuery (str "delivery" (:num-delivery-addresses db))) (:description suggestion))

Spaceman04:06:35

I'm getting the following error:

Uncaught Error: [object Object] is not ISeqable
    at Object.cljs$core$seq [as seq] (core.cljs:1226)
    at re_frame$fx$do_fx_after (fx.cljc:74)
    at Object.re_frame$interceptor$invoke_interceptor_fn [as invoke_interceptor_fn] (interceptor.cljc:71)
    at Object.re_frame$interceptor$invoke_interceptors [as invoke_interceptors] (interceptor.cljc:109)
    at Object.re_frame$interceptor$execute [as execute] (interceptor.cljc:204)
    at Object.re_frame$events$handle [as handle] (events.cljc:65)
    at Object.eval [as re_frame$router$IEventQueue$_process_1st_event_in_queue$arity$1] (router.cljc:179)
    at Object.eval [as re_frame$router$IEventQueue$_run_queue$arity$1] (router.cljc:198)
    at eval (router.cljc:146)
    at Object.eval [as re_frame$router$IEventQueue$_fsm_trigger$arity$3] (router.cljc:169)
Why would that be?

Spaceman04:06:03

hello, anyone here?

Spaceman04:06:35

This is in an event handler btw

flyboarder04:06:40

@pshar10 can you verify your brackets? looks like (:description suggestion) is the context object jquery is expecting

Spaceman04:06:07

Yeah that expression is a string

Spaceman04:06:18

pretty sure

flyboarder04:06:10

@pshar10 is your db an atom?

Spaceman04:06:31

I don't know what that means

Spaceman04:06:51

like not a data-structure you mean?

flyboarder04:06:54

you might need to add @db if the db object is an atom containing your map

flyboarder04:06:15

i dont know much about your app so I am guessing at what the vars could be

Spaceman04:06:46

it's a map you get in as a parameter in re-frame, if you're familiar with it

flyboarder04:06:23

the simple thing to do would be to replace it bit by bit

Spaceman04:06:30

for all intents and purposes it's a parameter of a function, and within the function db is used

flyboarder04:06:36

and figure out exactly which function is throwing

Spaceman04:06:24

what does not ISequable mean anyway?

flyboarder04:06:27

either :num-delivery-addresses or :description is operating on an object

flyboarder04:06:37

not on a collection

flyboarder04:06:54

so it’s attempting to access a js object as if it was a map

Spaceman04:06:39

Yeah but both expressions actually give strings so they are valid

flyboarder04:06:15

are you able to print each of these in-place of what is currently broken?

Spaceman04:06:44

yeah that's why I'm pretty sure that they're valid

flyboarder04:06:05

are you able to print the element you are selecting also?

Spaceman04:06:08

there might be a difference between cljs and js strings though and the expression expects js ones, I don't know

flyboarder04:06:07

well right now we dont know if (js/jQuery (str "delivery" (:num-delivery-addresses db)) <- this is broken

flyboarder04:06:27

or if this is broken -> (.val elem (:description suggestion))

Spaceman04:06:12

(js/jQuery (str "delivery" (:num-delivery-addresses db)))
gives that error too

flyboarder04:06:44

ok so it’s probably (:num-delivery-addresses db) try deref’ing the db (:num-delivery-addresses @db)

flyboarder04:06:13

if this db map is in an atom it will need to come out first

Spaceman04:06:30

no it's not dereference-able

flyboarder04:06:11

hm, im at a loss then, what happens when you print the db is it a straight clojure map?

Spaceman04:06:35

The expression is valid but I think it's in the wrong place or something. That reframe expects some other ending to that function, I don't know.

Spaceman04:06:46

yes it's a regular map

flyboarder04:06:51

what is it contained within?

Spaceman04:06:06

I'll check out #re-frae

dazld05:06:03

The default implementation of weakmap doesn't make a lot of sense in CLJS, right? As in, it works on identity, and not value. Is it true to say that underneath the hood, cljs doesn't try to "reuse" objects that have already been created with a particular value...? Hence, there's no way for a weakmap to know if a particular instance of a value can be discarded or not.

lilactown05:06:53

It makes sense if identity is important to you, which it might in some

lilactown05:06:28

CLJS will generally allocate a new object anytime you use a data literal

lilactown05:06:30

So a value added to a weak map, might be garbage collected and removed from the weak map if you lose reference to that object

dazld05:06:27

(def ws (js/WeakSet.))
=> #'cljs.user/ws
(.add ws :hi)
=> #object[WeakSet [object WeakSet]]
(.has ws :hi)
=> false

dazld05:06:38

yup 😞 it gets funky.

dazld05:06:58

(def k :hi)
=> #'cljs.user/k
(.add ws k)
=> #object[WeakSet [object WeakSet]]
(.has ws k)
=> true

thheller08:06:13

@dazld all the JS collections only operate on object identity and in development keywords are recreated on time. in a release build you'd get the "expected" result since keywords are only created once.

dazld08:06:53

that's super interesting, thank you

thheller08:06:25

but it would still run into issues if you get your keyword via dynamic constructed code (eg. edn, transit)

thheller08:06:34

so its safer to assume this never works : P

dazld08:06:41

was just thinking about that, would be a pain to develop with too..

thheller08:06:17

CLJS also has the same issue which is why identical? doesn't work for keywords/symbols and they have their own keyword-identical? variants

👍 4
thheller08:06:45

funny enough this would be fixed by using a weakmap in keyword construction 😛

dazld08:06:36

as in... keep references to all created kw in a weakmap / weakset?

thheller08:06:52

"interning" them just like clojure does yes

dazld08:06:12

doesn't sound like it would be too hard to pull off..

thheller08:06:24

but this is unlikely to happen given that weakmap isn't universally available

dazld08:06:42

no, but it can be shammed

dazld08:06:04

I know you don't like polyfills though 😉

thheller08:06:10

also very little gain to be had here

p-himik09:06:35

@U05224H0W Do you know of a reason why keyword literals are recreated in dev? Seems counter-intuitive at best.

thheller09:06:08

no clue. might be the lack of weakmap in JS when CLJS first came out?

p-himik09:06:40

Wouldn't then the keywords be recreated in prod as well?

p-himik09:06:02

My main concern is not the behavior itself, but the difference between prod and dev.

thheller09:06:29

the difference really is just a performance/code-size optimization. you should always treat keywords as-if you were in development

thheller09:06:11

and this optimization you'd still do even if keywords were interned ... doesn't really change anything on that front

p-himik09:06:11

We're back at base 1 one then. Why not enable this optimization in dev as well? Would it somehow hinder the development?

thheller09:06:47

now that I think about it the reason this is done is probably :advanced. if you were to register a keyword in some global "registry" (eg. weakmap or just js object) then closure can never DCE any keyword

thheller09:06:54

yeah thats proably it

thheller09:06:35

you cannot enable it in dev. in shadow-cljs its a closure compiler pass that optimizes the whole program at once

thheller09:06:10

in regular CLJS it emits "forward" references in the code that are then created in a special namespace with special handling in the compiler as part of the build

thheller09:06:40

in dev with REPL and stuff you cannot possibly know all the keywords that are going to be constructed

p-himik10:06:39

> then closure can never DCE any keyword But we don't have DCE in dev either way. But I'm assuming that such a registry is populated after DCE. Which is probably not the case in :advanced. > you cannot enable it in dev. in shadow-cljs its a closure compiler pass that optimizes the whole program at once Ah. Well, one can dream. :)

thheller11:06:59

there is not much to dream about. you either have DCE for keywords or you gain the "convenience" of interned keywords. I'd rather have DCE.

isak00:06:36

I can't think of a good reason to not hoist constants in dev mode too. You could just hoist them to the referencing file, instead of one big file like you do for prod. (Assuming reload experience is the problem) @U05224H0W For DCE, couldn't you just switch all static references to keywords to new functions that find-or-create them (specificially)? E.g., :foo/bar => (find-or-create-foo-SLASH-bar)

schaueho12:06:24

Is there any good library support to traverse the DOM? The particular use-case I have is react-testing-library and accessing node collections, childrens, attributes and so on. The JS interop works, of course, but feels somewhat cumbersome.

Roman Liutikov19:06:00

@schaueho (tree-seq #(some? (.-children %)) #(array-seq (.-children %)) js/document)

🎉 4
lilactown19:06:24

tree-seq is like, 33% of the reason I love ClojureScript 😛