clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
p-himik 2020-10-01T06:00:55.199900Z

It's all in the documentation: https://reactjs.org/docs/lists-and-keys.html#keys

Aron 2020-10-01T10:50:46.200900Z

How does nested destructuring work with js objects? E.g. resizeobserver entries' contentRect's width and height?

2020-10-06T10:46:19.296600Z

FWIW, js-interop at least attempts to provide an api that is consistent with clojure(script). There are macros that enable destructuring (on anything js, not only POJOs), and there is j/lit which like a recursive #js. There is j/get, j/get-in, j/assoc! and so on, which all follow clojure semantics. I do agree that this stuff is nuanced and easy to run into issues. As β€œthe ship has sailed” on what ClojureScript provides out-of-the-box, libraries/user-space is the place to look now. cljs-bean is very cool and useful for situations where wrapping makes sense, I like js-interop for the rest of cases (eg. non-POJOs or perf-sensitive stuff), where you want the compiled code to be essentially what you’d write in javascript.

πŸ‘ 1
Aron 2020-10-07T01:56:12.316700Z

I think I will use js-interop instead of bean, but only when I absolutely need either

p-himik 2020-10-01T11:10:30.201Z

Destructuring doesn't work with JS objects at all.

Aron 2020-10-01T11:18:57.201200Z

I think it does

Aron 2020-10-01T11:19:02.201400Z

πŸ˜„

p-himik 2020-10-01T11:20:18.201800Z

Are you sure you have a plain JS object and not some bean or something?

cljs.user=> (let [{:keys [a]} #js {:a 1}] a)
nil
cljs.user=> (let [{a "a"} #js {:a 1}] a)
nil

p-himik 2020-10-01T11:21:54.202Z

Or maybe you have extended js/Object to support ILookup. It may work but don't do that.

Aron 2020-10-01T11:25:48.202200Z

I just realized I don't even know how to start a REPL for cljs. All the examples talk about something else when there is mention of this :-<

p-himik 2020-10-01T11:28:38.202600Z

A one-liner:

clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "RELEASE"}}}' -m cljs.repl.node

Aron 2020-10-01T11:29:58.202800Z

thank you, much appreciated. I think there should be some alias saved for this, but couldn't find yet

p-himik 2020-10-01T11:30:43.203Z

I actually just added it to ~/.clojure/deps.edn myself. :) Was using http://clojurescript.io before.

Aron 2020-10-01T11:31:10.203200Z

ClojureScript 1.10.773
cljs.user=&gt; (def obj #js [{"contentRect" {"width" 1 "height" 2}}])
#'cljs.user/obj
(defn example [[{{:strs [width height]} "contentRect"}]]
  [width height])
#'cljs.user/example
cljs.user=&gt; (example obj)
[1 2]
cljs.user=&gt; 

Aron 2020-10-01T11:31:40.203400Z

haven't tried it with the actual resizer entry yet, had to put it together step by step, very hard to understand what is going where

p-himik 2020-10-01T11:32:25.203600Z

Ah, there's your problem. #js is shallow.

p-himik 2020-10-01T11:32:41.203800Z

Huh, and apparently destructuring works with JS arrays.

Aron 2020-10-01T11:34:18.205300Z

I didn't know #js is shallow, will fix that

Aron 2020-10-01T11:35:10.207Z

so I should use a bean or something

p-himik 2020-10-01T11:35:48.208400Z

If you want to, yeah. https://github.com/mfikes/cljs-bean

p-himik 2020-10-01T11:36:20.209200Z

Or just use plain getters, like .-prop or from goog.object.

Aron 2020-10-01T11:39:16.210500Z

it's 5 lines to write them all out

Aron 2020-10-01T11:39:35.210700Z

most of it is not relevant at all.

Aron 2020-10-01T11:53:34.210900Z

I can't make it work with beans either. Must say that while js is literally the same thing everywhere, and I can run a webserver in a browser if I really want it without changing the source, clojurescript is nothing like clojure, the two seem to be two entirely separate languages and I keep tripping over this, even after years of first realizing it.

p-himik 2020-10-01T11:59:51.211100Z

Just in case - you can chain the usages of .-prop:

cljs.user=&gt; (def x #js {:a #js {:b 1}})
#'cljs.user/x
cljs.user=&gt; (.. x -a -b)
1

p-himik 2020-10-01T12:00:29.211300Z

> I can run a webserver in a browser Really? How would it listen for new connections?

p-himik 2020-10-01T12:01:08.211500Z

CLJS is very similar in this regard to CLJ - you access properties of the native objects with the dot syntax. I'm not sure what the difference is that you're tripping over.

p-himik 2020-10-01T12:06:36.211700Z

CLJ and CLJS are indeed almost the same language if you stay within the language itself and don't try to venture into the interop world. The only exception that I can think of right now is how macros work. And I think a few :require might be different.

Aron 2020-10-01T12:10:04.211900Z

I didn't say I can listen to new connections, I said I can run the code πŸ™‚ Doesn't have to make sense

Aron 2020-10-01T12:10:33.212100Z

the difference is that I've been trying to write this thing for hours and I still don't know how it works

p-himik 2020-10-01T12:11:15.212300Z

OK, let's agree to disagree re web servers then. :) What exactly are you having troubles with?

cljs.user=&gt; (require '[cljs-bean.core :refer [bean]])
nil
cljs.user=&gt; (def x #js {:a #js {:b 1}})
#'cljs.user/x
cljs.user=&gt; (let [{{:keys [b]} :a} (bean x :recursive true)] b)
1

Aron 2020-10-01T12:11:23.212500Z

basically, while the language has gazillion tools to make your life easy, if you are working with javascript, it's kind of a gambling experience to find the right combination that actually does what I expect

p-himik 2020-10-01T12:12:33.212700Z

It has a very well defined behavior and a very limited set of very composable things. I fail to see how this could possibly be a gamble.

Aron 2020-10-01T12:13:31.212900Z

I don't like the agree to disagree phrase, it doesn't mean what people think it means. But let's not delve into that. πŸ™‚ I am registering a resizer observer event on an element and I would like to get the width and height properties from under the contentRect property. The only way I could do it to write .-propertyaccess way, none of the other syntax approaches or even using cljs-bean seem to have access to those values

Aron 2020-10-01T12:13:44.213300Z

I do not question that it's well defined! πŸ™‚

Aron 2020-10-01T12:14:56.214700Z

https://drafts.csswg.org/resize-observer/#content-rect-h these

lepistane 2020-10-01T12:15:00.214900Z

low resolution questions here 😞 is it possible to run CLJS SPA app within someones website? kinda like widget? does it have to be in iframe? could compiled CLJS code be called from site's JS code and work properly?

p-himik 2020-10-01T12:15:26.215100Z

Can you be more specific - maybe you have a link to the JS code that you would like to convert to CLJS?

Aron 2020-10-01T12:15:43.215300Z

just a min

p-himik 2020-10-01T12:24:21.215500Z

Since your last question seems to be able to answer every other one, I'm gonna answer just it. Yes, it can be called from a third-party JS code and work properly.

p-himik 2020-10-01T12:24:49.215700Z

Export all the needed symbols, create a JS bundle, and use it as a regular JS script.

2020-10-01T12:25:04.216100Z

I like this library's approch for destructuring js obj, lookup, an more. Very useful: https://github.com/applied-science/js-interop

Aron 2020-10-01T12:25:39.216500Z

but this is the thing, why do i need additional dependencies to do something that's so basic?

Aron 2020-10-01T12:26:18.216700Z

it increases the incidental complexity of the project so much so early.. it's really disheartening

2020-10-01T12:30:47.216900Z

For eg., i used it on one CLJS React native project because I wanted to manipulate some JS obj idiomatically.

p-himik 2020-10-01T12:32:45.217100Z

@ashnur map-like destructuring is for things that support get, that's it. You can have some object that both supports get, has some value associated with :x, and has an .-x property. If get would work on JS properties, this situation would be ambiguous.

p-himik 2020-10-01T12:33:51.217300Z

Interop is different than "vanilla" CLJ[S] code, that's it. But the amount of specifics is so negligible that any cheatsheet gives you an extensive information with all the nuances.

Aron 2020-10-01T12:34:08.217500Z

you definitely like to say "that's it" πŸ™‚

Aron 2020-10-01T12:35:16.217700Z

The question is, how to get from javascript objects something that can be destructured? You asked for the example, have you checked it out?

lepistane 2020-10-01T12:56:05.218Z

are there any examples online that i can refer to?

lepistane 2020-10-01T12:57:18.218200Z

or tutorials?

p-himik 2020-10-01T12:58:00.218400Z

I can confirm that cljs-bean does not work in this case because the entries that the callback receives are not POJOs. But it's how this particular library works and it's not a fault of CLJS. > how to get from javascript objects something that can be destructured? If you really need that functionality, some library or custom code has to be used as CLJS does not have that built-in (neither does CLJ). And it seems that cljs-bean does not satisfy the criteria.

p-himik 2020-10-01T13:00:41.218600Z

Any CLJS tutorials would do since I don't think there's anything special about using some code in a compiled CLJS bundle from some JS.

p-himik 2020-10-01T13:01:46.218800Z

Imagine you have two separate JS files that both augment js/window. How would you go about using some function from the second file in the code from the first file? Same exact thing here because compiling CLJS will give you a single JS file.

Aron 2020-10-01T13:03:32.219Z

I didn't say that cljs is at fault, I hope that's not what transpired... I am particularly careful to not associate blame with anything...

lepistane 2020-10-01T13:09:01.219200Z

makes sense thank u!

p-himik 2020-10-01T13:11:52.219400Z

Well, you did say "clojurescript is nothing like clojure" although in this particular context they're exactly the same. And that "[the lack of JS destructuring in CLJS] increases the incidental complexity of the project so much so early". And while it may be somewhat true compared to starting a pure JS project, it's for a very good reason and I don't think there could be any other way without making CLJS a mess.

Aron 2020-10-01T13:16:59.219600Z

> in this particular context they're exactly the same. does this mean that clojure is unable to destructure POJOs the same way clojurescript apparently is? I didn't say the lack of destructuring causes the increase incidental complexity, why do you accuse me of such nonsensical things so I have to explain myself for things I never said? The increase in incidental complexity is if and only if I have to include additional dependencies to achieve something. It was a specific answer to a specific suggestion, not a general comment about clojurescript. Do you have so many people making such bad claims that you misunderstand me so much, or is it just me who you treat like this?

p-himik 2020-10-01T13:23:53.219900Z

> does this mean that clojure is unable to destructure POJOs the same way clojurescript apparently is? Yes. > The increase in incidental complexity is if and only if I have to include additional dependencies to achieve something You have to include additional dependencies (or write some code) to support JS objects destructuring. Without doing anything, you cannot destructure #js {...}. The lack of destructuring of POJOs makes you having to include something to support that destructuring, exactly as you say. Given that, I don't know what you're disagreeing with. I'm not trying to point fingers here, I'm pointing at what I see as inconsistencies in reasoning.

Aron 2020-10-01T13:30:27.220100Z

> > does this mean that clojure is unable to destructure POJOs the same way clojurescript apparently is? > Yes. Thanks, that's good to know.

2020-10-01T15:14:42.222100Z

it looks like clojurescript doesn't throw arity exceptions, just compile warnings. (i suppose that's because js doesn't care.) do folks try to be disciplined in terms of arity anyway, or should we treat this like a feature and embrace it? what's more idiomatic?

2020-10-01T15:20:38.222800Z

i guess the fact that it's a compile warning, and not an error, indicates something about community preferences

ghadi 2020-10-01T15:25:55.223800Z

@michael740

node
Welcome to Node.js v14.12.0.
&gt; function foo(a){return 42;}
undefined
&gt; foo("one")
42
&gt; foo("one", "two")
42

ghadi 2020-10-01T15:28:12.224800Z

it's inline with the JS platform

2020-10-01T15:35:59.229Z

@ghadi - given that, i take it that it's idiomatic to ignore arities when convenient? the re-frame subs come to mind. reg-sub expects a fn of type [db query-v] -&gt; ? but maybe it's convenient to pass in (fn [db] ...) instead

p-himik 2020-10-01T15:47:50.230800Z

I try to not do that. I think shadow-cljs gives warnings when you use incorrect arities. Well, at least when it can deduce the issue.

2020-10-01T15:47:56.230900Z

i'm curious about this because it feels like a type error. does the clojurescript community not mind in much the same way that the larger clojure community doesn't get that worked up over types?

p-himik 2020-10-01T15:49:11.232100Z

I can't speak for the whole community, but I don't remember seeing any CLJS code that would deliberately use incorrect arities. IMO abusing "fluid arities" is just asking for trouble.

2020-10-01T15:58:22.232300Z

right on

isak 2020-10-01T15:59:37.233100Z

I don't think that will cause any problems, because I don't see how you could enforce arities in ClojureScript without a big performance penalty

p-himik 2020-10-01T16:02:30.234400Z

It will cause problems as soon as some library decides to introduce an arity that you've been using mistakenly, like the (fn [db] ...) example above. Re: check - not sure. It's a single check of arguments.length &gt; N.

isak 2020-10-01T16:05:12.235700Z

I thought he was talking about just passing callbacks that accept less arguments than they will receive. I can't see how that would cause any problems regardless of what the library that invokes the callback does. Can you?

isak 2020-10-01T16:06:32.236900Z

> It's a single check ofΒ `arguments.length > N`. It would still mean wrapping a lot of function calls though (all the function calls you can't verify statically). That means bigger bundle size too.

p-himik 2020-10-01T16:14:32.239300Z

> I thought he was talking about just passing callbacks that accept less arguments than they will receive. I can't see how that would cause any problems regardless of what the library that invokes the callback does. Can you? Absolutely. A third-party lib expects a 2-arg fn, but you pass a 1-arg fn because you don't care about the second arg. After a while, the lib adds support for 1-args fns that are called in different circumstances than their 2-arg buddies. Usually such a change would be considered a non-breaking one. But your code could easily be broken by it, regardless of whether it's a callback or not.

isak 2020-10-01T16:21:53.240Z

How would they check the arity of your function in order to call it in different circumstances?

p-himik 2020-10-01T16:23:36.240900Z

The lib doesn't check arity, it checks something else:

(case my-condition
  7 (callback-fn 1)
  42 (callback-fn 1 2))

isak 2020-10-01T16:26:26.242200Z

Hmm, I don't see why that would be a problem in your function there. They'd have to pass something else in as the first argument, right? And that seems like it would be a breaking change.

p-himik 2020-10-01T16:27:54.243700Z

Right, my example is just to show that it doesn't check the arity. But the first argument should be different, you're right. It wouldn't be a breaking change because before the lib fn was explicitly expecting a 2-arg fn. A lib user, by using a 1-arg fn, would break the contract and reap the consequences some time later.

p-himik 2020-10-01T16:29:38.244900Z

If something expects something specific, it's better to not do something else just because it may be easy. JS makes many things excruciatingly easy. So much so there's a feet deficit.

isak 2020-10-01T16:32:09.246600Z

I think I see your point. But adding more arities, then changing the order of arguments for those new arities (or similar) seems like it should be considered a breaking change for a ClojureScript library (since it would be easy to make this mistake)

p-himik 2020-10-01T16:34:01.248300Z

Ah, right - the order may be the same. My example is still a good one because there's one more possibility. That third-party lib might expect different results from the callback fns with different artities. Like map - the 1-arg one returns a transducer but the 2-arg one returns a collection.

p-himik 2020-10-01T16:34:41.249100Z

That way it wouldn't really be a "callback fn", but whatever - still some function that does something, only this time it also should return something.

isak 2020-10-01T16:35:37.249400Z

Ok yea that is a good point

wilkerlucio 2020-10-01T19:59:12.250700Z

hello, while implementing a custom map type in CLJS, I noticed that the contains? fn doesn't use the -contains-key? from IAssociative. I'm making the impl on both CLJ and CLJS, on CLJ it uses the -contains-key?, is this a bug on CLJS or is there are reason for it?

wilkerlucio 2020-10-01T20:00:07.250800Z

by looking at sources, the impl of contains? in CLJ is very different, the CLJS one just relies on get, while the CLJ has a bunch of type checks

p-himik 2020-10-01T20:55:16.251Z

Just in case - there's also #cljs-dev that might be better at getting attention of those who know.

wilkerlucio 2020-10-01T22:59:28.251700Z

thanks, I'll post there as well πŸ™