Forward declaration of a function in Clojurescript - clojurescript

I would like to forward-declare a function in ClojureScript. Kind of
(defn a [] (b))
...
(defn b [] ...)
I think what kind of works is to place a (def b nil) in front of the usage (b) but I wonder if there is a "better" way.

It seems that declare does the trick. I only found documentation on it for Clojure but it seems to work in ClojureScript as well.
http://clojuredocs.org/clojure_core/clojure.core/declare

Related

Using an anonymous Js function in a go block

I'm attempting to do some timed animation in clojurescript/reagent and I'm trying to use core.async to achieve series of timed steps in order. I'm using a third party js react library, so, to call its functions I'm using the form (fn [] ^js (.function (.something #ref)). However putting this anonymous function inside the go block as follows doesn't work -
(go
(js/console.log "going")
(<! (timeout 3000))
(fn [] ^js (.function (.somedata #lib))
(js/console.log "landed")
)
This returns "going" and "landed" timed correctly and works when putting another console.log function in its place. However if you wrap this console.log in an Fn it no longer gets called. It is being called in the :on-click handler of a component. What have I missed?
That ^js there is unnecessary.
When you wrap something in (fn [] ...), that something is not called unless that fn is called. I.e. ((fn [] ...)). But then, you end up creating a function and calling it immediately, which is completely unnecessary.
So, assuming I understand you correctly, you can simply replace that (fn [] ^js ...) with (-> #lib .somedata .function).
On a side note, somedata sounds like it's just a field that has some data and not a function that needs to be called. If that's the case, use .-somedata instead of .somedata.
As mentioned by Eugene Pakhomov using (fn [] ...) only creates a function, it does not call it. Thus it it basically just elimnated entirely without doing anything.
Your motiviation here seems to get rid of the inference warning. So the underlying problem is that core.async is rather forgetful when in comes to type hints. If you ask me you shouldn't do any interop in go blocks at all and rather move it all out. Either via defn or local function outside the go.
(defn do-something []
(.function (.somedata ^js #lib)))
(go
(js/console.log "going")
(<! (timeout 3000))
(do-something)
(js/console.log "landed"))
(let [do-something (fn [] (.function (.somedata ^js #lib)))]
(go
(js/console.log "going")
(<! (timeout 3000))
(do-something)
(js/console.log "landed")))
Also, just a word of caution. Using core.async for this will substantially increase the amount of code generated for code in go blocks. If you really need to do is delay something use (js/setTimeout do-something 3000). Use go with caution, it'll easily generate 10x the code for some things than would normally be required.

CLJS: Setting a JS property to the result of calling a method on it

I'm looking to modify some existing text in a web app, which I'm accessing with expressions like this:
(.-innerHTML (.getElementById js/document "myElementId"))
What I specifically want to do is mutate that text via a search/replace:
(set! (^that whole thing) (.replace (^that whole thing) "old" "new"))
And I'd ideally like to do that without having to repeat the property-access expression. Is there any existing shortcut for this? I'm envisioning something like Raku's object .= method(args) shorthand for object = object.method(args); maybe a good clj name/pattern would be (.set! (access-expression) method & args). I can always write a macro, but was wondering if I'd overlooked something already there.
I was curious too and looked in the CLJS CheatSheet and they link to the CLJS Oops library which provides similarly looking functions.
It seems to be that the most robust solution would be to just rely on the Google Closure Library (which is always at hand) and use a combination of goog.object/get and goog.object/set (no need for a macro), something like:
(require 'goog.object)
(defn update-obj! [obj field f & args]
(let [old-val (goog.object/get obj field)
new-val (apply f old-val args)]
(goog.object/set obj field new-val)))
;; Example:
(update-obj! (.getElementById js/document "my-div") "innerHTML" (partial str "it works: "))
This should work in both development and optimized output.

Block until a DOM event occurs with core.async

I've got a Clojurescript project where i need to block the whole thread execution until an DOM event occurs.
In this case, the event is DOMContentLoaded, which fire when the initial HTML document has been completely loaded and parsed. But it could be extended to any DOM (or non-DOM) event.
As i'm new to Clojurescript and async i wasn't sure how to solve this problem. My first guess was to use the core.async library. After some doc scraping, i came with that function:
(defn wait-dom-loading
[]
(let [c (async/chan)]
{1} (.addEventListener js/document "DOMContentLoaded" (fn [] (async/go (async/>! c true))))
{2} (async/go (async/<! c))))
The way i understand it is that {2} takes from chan c and is parked until the listener in {1} evaluates the function and puts a value in chan c.
As i barely understand how to do unit tests on asynchronous code (beside puting it in an (async done) expression and calling done when done) i can't verify if what i did is correct. I tried this snippet:
(do
(wait-dom-loading)
(-> (dommy/sel1 :p)
(dommy/set-text! "Loaded !")))
With a p block inside an html page, and noticed that the console complains about the js code trying to manipulate a DOM object that don't yet exists. That confirms that what i did didn't work as planned.
What does seems wrong in this example ?
Is this overkill ? Could i solve that with a smaller solution or even gasp a built-in funtion ?
Is putting my script at the bottom of my html page a not so bad practice ?
As this was my first question on stack overflow, i hope it is well-written enough.
This is how i would do it:
(ns domevent.core
(:require [cljs.core.async :as async :refer [chan]])
(:require-macros [cljs.core.async.macros :refer [go]]))
(enable-console-print!)
(def ch (chan))
(go
(pr "i am waiting")
(pr (<! ch))
(dommy/set-text! (dommy/sel1 :p) "Loaded !"))
(.addEventListener js/document "DOMContentLoaded" (fn [] (go (>! ch "hello"))))
Or more simply:
(let [ch (chan)]
(go
(pr "i am waiting")
(<! ch)
(dommy/set-text! (dommy/sel1 :p) "Loaded !"))
(.addEventListener js/document "DOMContentLoaded" #(close! ch)))
)
The point here is the ch, which is shared by reader and writer. When (<! ch) happens, there is nothing in ch yet, so this thread is parked (i.e. stops and waits for anything to appear in ch). Meanwhile, the DOMContentLoaded occurs, and the handler writes to the channel. Then the former thread continues.

Can name munging be avoided for an interop call in ClojureScript?

In advanced compilation
(js/console.log "HELLO"
js/window.navigator.msSaveBlob
(.. js/window -navigator -msSaveBlob)
(aget js/window "navigator" "msSaveBlob")
js/console.log)
=>
HELLO undefined undefined function function
I think this means that js/console has some provided externs, but navigator does not (or at least not the ms specific stuff).
AFAIK the only way to avoid this is to create some externs? But this seems unnecessarily obtuse; why would you ever want js/anything to be munged?? Wouldn't it make make more sense to never munge js/anything interop?
System functions are not munged; only your own functions are. You probably want (.log js/console ...) ?
For de-munging your own functions, place ^:export between the defn and the function name to export its name intact.
Here is more information.
All see the section called "munging" here.

Is there a function that takes a list of argument lists and applies each list to a given function?

I.e., something like:
(defn dowith [f & arglists]
(doseq [args arglists] (apply f args)))
Is there a built-in function like that in Clojure?
I write things like that moderately often; its just so short that it's not really worth wrapping:
(map #(apply myfun %) list-of-arglists)
I use map most often so i get the results and keep it lazy. of course if you don't want it lazy and don't want the results then doseq is fine also.
No, there is no built-in function that does that.