sci

Sam Ritchie 2023-06-08T18:28:06.557329Z

@borkdude or anyone — I am working on a portal viewer that’s cljs evaluated via sci. this require fails with “could not find namespace: goog.object” https://github.com/mentat-collective/Leva.cljs/blob/main/src/leva/schema.cljs#L6 is there a replacement I can use, for goog.object/set with a string key (not known at compile time) and value?

Sam Ritchie 2023-06-08T18:28:21.968629Z

I would use assoc if I were in cljs, but I’m mutating a JS object here

borkdude 2023-06-08T18:29:11.376949Z

yes, (aset obj "foo" "bar")

Sam Ritchie 2023-06-08T18:30:07.567089Z

okay nice, whenever I do that someone pops up and says “only use aset with arrays!!”

borkdude 2023-06-08T18:30:21.806199Z

yeah, I know ;P

1
Sam Ritchie 2023-06-08T18:32:12.271149Z

borkdude approved, done! and yes this is clearly the right way, thanks!

borkdude 2023-06-08T18:32:59.974129Z

cljs.user=> (doto #js {} (js/Reflect.set "foo" "bar"))
#js {:foo "bar"}

borkdude 2023-06-08T18:33:14.639079Z

but this is way more expensive in SCI, so I'd just use aset

Sam Ritchie 2023-06-08T21:05:19.329169Z

@borkdude any preferred substitute for this-as in sci?

borkdude 2023-06-08T21:06:03.696569Z

depends on the exact example

borkdude 2023-06-08T21:09:42.619549Z

https://github.com/babashka/sci#this-as

Sam Ritchie 2023-06-08T21:17:28.621099Z

Sam Ritchie 2023-06-08T21:17:39.565259Z

this is from portal, when I try to require a cljs file that uses this-as inside of it cc @djblue

Sam Ritchie 2023-06-08T21:19:00.590559Z

@borkdude oh whoops I assumed your link was a docstring for this-as, instead it’s a workaround -

borkdude 2023-06-08T21:22:06.614279Z

yes, this-as is only possible in a compiled language, in an interpreter I haven't found a way

Sam Ritchie 2023-06-08T21:25:06.009459Z

there must be some other way to get the “context” for the event, I’ll read up

Sam Ritchie 2023-06-08T21:25:51.482529Z

so it’s calling the handler with https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

Sam Ritchie 2023-06-08T21:33:40.484419Z

I think I can get around this

djblue 2023-06-08T21:33:45.314119Z

thisAs = new Function('return this'); var obj = { fn: thisAs }; obj.fn()
=> {fn: ƒ}

borkdude 2023-06-08T21:35:34.482379Z

nice :)

user=> (def thisAs (new js/Function "return this"))
#'user/thisAs
user=> (def obj #js {:fn thisAs})
#'user/obj
user=> (.fn obj)
#js {:fn #object[anonymous]}

borkdude 2023-06-08T21:35:38.920939Z

(this is SCI)

borkdude 2023-06-08T21:41:37.590799Z

I guess I could use that in SCI and track where the this-as local is used and insert a call to this special thisAs function instead

borkdude 2023-06-08T21:42:43.611499Z

another alternative would be to wrap every function body in SCI with this-as in the host, but not sure if there would be a performance impact

djblue 2023-06-08T21:43:03.399139Z

Although, I guess this-as is a macros

(defmacro this-as
  "Defines a scope where JavaScript's implit this is bound to the name provided."
  [name & body]
  `(let [~name (~'js* "this")]
     ~@body))

borkdude 2023-06-08T21:43:28.860649Z

in CLJS it's a macro, but in SCI I could treat it as a special thing

👍 1
borkdude 2023-06-08T21:46:44.988859Z

I updated the issue here, I think the js/Function thing is interesting, I'll try it when I have some time after the bb conf. Or perhaps @mkvlr feels like hacking on this with me tomorrow ;) https://github.com/babashka/sci/issues/564

Sam Ritchie 2023-06-08T21:47:46.828409Z

I’ve got it worked out for now, turns out I could close over the object that was eventually passed to my callback as this, since I had just created it when I registered the callback

borkdude 2023-06-08T21:48:11.241379Z

yeah, that's how I usually work around it too

borkdude 2023-06-09T09:52:07.892299Z

I tried a couple of things, but I'm still getting the global object in SCI for "this":

cljs.user=> (def obj (sci/eval-form (sci/init {:bindings {'thisAs (js/Function. "return this") }}) (do (def obj (clj->js {:f (fn [] (thisAs))})) (.f obj))))
#'cljs.user/obj
cljs.user=> (identical? obj js/globalThis)
true

borkdude 2023-06-09T09:53:58.420989Z

ah wait:

cljs.user=> (sci/eval-form (sci/init {:bindings {'thisAs (js/Function. "return this") }}) (do (def obj (clj->js {:fn thisAs})) (.fn obj)))
#js {:fn #object[anonymous]}

borkdude 2023-06-09T09:54:30.838959Z

so it doesn't work when you add the thisAs in a wrapped function

borkdude 2023-06-09T09:59:45.323119Z

I wish I could make this work:

(sci/eval-form (sci/init {:bindings {'thisAs (js/Function. "return this") }}) (do (def obj (clj->js {:fn (fn [] (thisAs))})) (.fn obj)))
since then I could probably also make this-as work, but it seems thisAs needs to be directly on the object

borkdude 2023-06-13T14:53:28.511269Z

@sritchie09 unchecked-set/get may be more "idiomatic" than aget/set, even though the docs say it's internal ;)

borkdude 2023-06-13T14:54:51.353549Z

oh not exposed in SCI it seems

borkdude 2023-06-13T14:55:00.156839Z

but could do that (issue/PR welcome)

borkdude 2023-06-13T14:55:09.491189Z

ah well, aget/set works