Can I require functions globally so I don't need to require every time in ClojureScript?


#1

Or a macro, say I want to use << everywhere in my program. I want to require it globally. Can I add configure somewhere and make it happen?


#2

No, this is not possible.

Also don’t use <<. :wink:

(<< "Hello $(world)!")
(str "Hello " world "!")

#3

Why it’s suggested not using? I have other cases where I need inserting several variables in a string and I think string interpolation would be a lot easier.


#4

You are free to use it if you like it.

I just prefer str over << as it “fits” much better and you don’t need special support from an editor to detect “code” inside strings. FWIW I was looking for a string interpolation in CLJ as well when I started since I was so used to it from other languages before. Turned out that str is enough (for me).

Just compare the example from the << docstring yourself.

(<< "Just split a long interpolated string up into ~(-> m :a (get 0)), "
    "~(-> m :a (get 1)), or even ~(-> m :a (get 2)) separate strings "
    "if you don't want a << expression to end up being e.g. ~(* 4 (int v)) "
    "columns wide.")

(str "Just split a long interpolated string up into " (-> m :a (get 0)) ", "
     (-> m :a (get 1)) ", or even " (-> m :a (get 2)) " separate strings "
     "if you don't want a << expression to end up being e.g. " (* 4 (int v))
     "columns wide.")

;; or formatted differently
(str "Just split a long interpolated string up into "
     (-> m :a (get 0))
     ", "
     (-> m :a (get 1))
     ", or even "
     (-> m :a (get 2))
     " separate strings if you don't want a << expression to end up being e.g. "
     (* 4 (int v))
     " columns wide.")

#5

In my case

(str "1px solid " (hsl 0 0 80))

turned into

(<< "1px solid ~(hsl 0 0 80)")

and it became easier to control the spaces in the string. I have been using string interpolations for years in CoffeeScrpt and JavaScript/TypeScript and it feels much more natural.

Yeah it’s a problem the editor has no way highlighting the expression inside. At least compiler can see my typos and throw warnings.


#6

Your second snippet has a typo :slight_smile:


#7

Is this one correct?

(<< "1px solid ~(hsl 0 0 80)")

#8

Well, perhaps it’s the first one - it has an extra closing paren at the end as a string.


#9

str is declared globally. There’s always that. :grin:


#10

If you use lein or boot, I know you can do something in your dev profile to :require the namespace and :refer the macros. I think it will be available only the repl though (not sure, you should test).


#11

I’m using shadow-cljs. And the author of shadow-cljs just said no. :slightly_frowning_face:


#12

Boy I hope so. I expect a lot of Clojure(Script) devs would be frustrated at a new function used without a require in their namespace, forcing them to dig around looking for its source & docs. Configuration wizardry adding a require from “somewhere else” (which I would be aware of…how?) would be un-idiomatic to the extreme in my book.

Please just require a function or macro if you want to use it.


#13

Of course, it’s a bad practice, 100% agree. I was just trying to find a solution.

An even dirtier hack that could work (untested), is to use the preloads feature of the Cljs compiler to auto require a custom namespace. In it, you may be able to intern the macro into clojure.core. it would then available every where I think?

So dirty. If it works it would be the equivalent of adding a function the global window object with almost no way of knowing where it came from. Untraceable. Bad idea. I’m almost ashamed of having the idea :sweat_smile:


#14

Yes it’s bad habit in business code. However, I found it still it necessary to have such features at the compiler level for specific use cases. It’s like macros can do to too much magic it’s not encouraged using everywhere, while we all know macros has great powers shaping Lisp into a great language.


#15

Did you look at the tagged literals https://clojure.org/reference/reader#tagged_literals ?


#16

sounds interesting but does it mean I have to implement that reader literal by myself?

do you have any guide how to create a reader literal?


#17

Hi yep, you have to implement your own. Played with this a while back, don’t remember the details to well, but it seems like a good match for what you want.

Would not abuse it to much, remember something about them not composing that well with macros I think (different phase in compilation process) also not sure how ide’s handle these.

Take a look at:


#18

FWIW shadow-cljs does not support custom reader literals in CLJS code. Supporting possibly side effecting functions called at read time would be a nightmare for caching. I also do not see the benefit over plain old function calls.


#19

Ohh I see.
It’s been a while since I played with them, since then switched to shadow-cljs so good to know. :smiley:

One made-up use-case would be logging like #log :debug my-var (without importing the log function everywhere).

Also found an interesting idea is in this article http://tonsky.me/blog/hiccup/

#rum/tag [:div#timer "Time is " #rum/tag [:span.time time] " sec"]