This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-12
Channels
- # announcements (10)
- # babashka (26)
- # beginners (113)
- # calva (75)
- # cider (7)
- # clj-http (1)
- # cljdoc (2)
- # cljfx (3)
- # cljs-dev (13)
- # clojure (79)
- # clojure-europe (21)
- # clojure-losangeles (2)
- # clojure-nl (4)
- # clojure-sweden (1)
- # clojure-uk (23)
- # clojureladies (4)
- # clojurescript (26)
- # clojureverse-ops (2)
- # conjure (2)
- # cursive (2)
- # data-science (1)
- # datalog (6)
- # datomic (1)
- # degree9 (2)
- # depstar (4)
- # esprit (3)
- # fulcro (25)
- # introduce-yourself (2)
- # jobs (3)
- # lsp (30)
- # meander (38)
- # missionary (9)
- # nbb (7)
- # news-and-articles (2)
- # off-topic (28)
- # pathom (46)
- # polylith (19)
- # re-frame (4)
- # reitit (2)
- # sci (8)
- # shadow-cljs (23)
- # specter (17)
- # spire (1)
- # tools-deps (16)
- # unrepl (1)
- # xtdb (30)
I have a clj backend which the user uses to authenticate to an external server (via OAuth2.0). After the authentication process my backend gets an access token from the external server. How can I pass my access token to the cljs frontend so that I can use it from there?
@njerigachoka The same way as you pass any other data back to the frontend? I assume the frontend has initiated some interaction with the backend to trigger this auth in the first place?
(or maybe I'm misunderstanding what you're asking?)
Hi, I need to find a way to easily pass context between (optionally) nested functions, so probably using macros. Here is a use case using simple JS. Create a red rectangle in a canvas. The canvas-context needs to be shared to effectively color the rectangle.
const canvas = document.getElementById("canvas")
const context = document.getContext("2d")
context.fillStyle = "red"
context.fillRect(10, 10, 50, 50)
Here with a dsl
(fill "red"
(rect 10 10 50 50))
Here is my idea of fill
and rect
. Fill alone does nothing, but rect
could be used by itself, or with stroke
or something else. Same fill
could have other functions inside.
(defn get-ctx []
(.getContext (.getElementById js/document "canvas") "2d"))
(defmacro fill [style & body]
(let [ctx (get-ctx)]
(.-fillStyle ctx style)
~@body))
(defn rect [x y width height]
(if ctx
(.fillRect ctx x y width height)
(.fillRect (get-ctx) x y width height)))
(rect 10 10 50 50)
But the compiler doesn't like it Unable to resolve symbol: ctx in this context
In the rect
function, if ctx
will expect ctx
to be bound to something. There's no binding inside the scope of the function. Clearly there's no binding a the top level either.
(defn get-ctx []
(.getContext (.getElementById js/document "canvas") "2d"))
(defn rect [ctx x y width height]
(.fillRect ctx x y width height))
(let [ctx (get-ctx)]
(rect ctx 10 10 50 50))
(defn get-ctx []
(.getContext (.getElementById js/document "canvas") "2d"))
(defn fill [ctx style with-fill]
(set! (. ctx -fillStyle) style)
(with-fill))
(defn rect [ctx x y width height]
(.fillRect ctx x y width height))
(let [ctx (get-ctx)]
(fill ctx "red" #(rect ctx 10 10 50 50))
(defn get-ctx []
(.getContext (.getElementById js/document "canvas") "2d"))
(defmacro fill [ctx style & with-fill]
`(do (set! (. ctx -fillStyle) style)
~@with-fill))
(defn rect [ctx x y width height]
(.fillRect ctx x y width height))
(let [ctx (get-ctx)]
(fill ctx "red" (rect ctx 10 10 50 50))
(require '[clojure.walk :as walk])
(defn get-ctx []
(.getContext (.getElementById js/document "canvas") "2d"))
(defmacro fill [ctx style & with-fill]
`(do (set! (. ctx -fillStyle) style)
~@with-fill))
(defn rect [ctx x y width height]
(.fillRect ctx x y width height))
(defmacro threading-context [context draw-commands]
(let [context-symbol (gensym "ctx")]
`(let [~context-symbol ~context]
~(walk/postwalk
(fn [v] (if (list? v) (cons (first v) (cons context-symbol (rest v))) v))
draw-commands))
(threading-context
(fill ctx "red" (rect ctx 10 10 50 50))
or maybe set a global variable and unset it when you leave if you aren't doing any async
@emccue Thanks for the explanation. Is clear now. I kind of like a version without seeing the ctx
, so I must opt to use a global variable for it and define simple functions.
You can do versions of this with nothing but functions, as well:
(defn fill [style]
(fn [ctx]
(set! (. ctx -fillStyle) style)))
(defn rect [x y w h]
(fn [ctx]
(.fillRect ctx x y width height)))
(def sequence [& ops]
(fn [ctx]
(doseq [op ops]
(op ctx))))
(def red-rect
(sequence (fill "red")
(rect 10 10 50 50)))
;; And you can build upon it to do a nice scoped version, kind of like
;; what you're looking for:
(defn with-fill [style f]
(fn [ctx]
(let [old-fill-style (. ctx fillStyle)]
((sequence (fill style)
f
(fill old-fill-style))
ctx))))
(def red-rect
(with-fill "red"
(rect 10 10 50 50)))
(defn get-ctx []
(.getContext (.getElementById js/document "canvas") "2d"))
(red-rect (get-ctx))
but tbh, I would just thread the context.
Hi, I was solving a problem where sequence of tuples needs to be generated like [[i,j]….]
where 1 <= j < i <= n
I had written below code that works great for small values of n
(defn pp? [n [i _]]
(>= n i))
(defn bla [[i j]]
(let [b (inc j)]
(if (>= b i)
[(inc i) 1]
[i b])))
(take-while (partial pp? 6) (iterate bla [2 1]))
;; ([2 1] [3 1] [3 2] [4 1] [4 2] [4 3] [5 1] [5 2] [5 3] [5 4] [6 1] [6 2] [6 3] [6 4] [6 5])
However for large values like 1e9
, I get below error:
(take-while (partial pp? 1e9) (iterate bla [2 1]))
;; Error printing return value (OutOfMemoryError) at java.util.Arrays/copyOf (Arrays.java:3745).
;; Java heap space
Any pointers to make the code work with larger values would be greatly appreciated.An alternative way to do it,
(defn some-tuples [n]
(for [i (range 1 (inc n))
j (range 1 (inc n))
:while (> i j)]
[i j]))
@UMPJRJU9E Thanks for the alternate way, but I guess this would also suffer with same problem when n is large e.g. 1e9
Depends on how you're consuming it, if you're consuming the lazy seq one element at a time without keeping a ref to head, then previous elements will be GC'ed
@UMPJRJU9E Can you explain me this with the code ? It would be of great help
For example, the run!
function will not keep a ref to the head of the sequence,
(run! do-something! some-lazy-seq)
and hence the elements that have been consumed by do-something!
can be GC'ed.@UMPJRJU9E Thanks a ton for the run!
. Honestly hadn’t used it before.
@prashantsinha what is the purpose of printing all the values there?
That’s a good question. This wouldn’t be of much use in real life. However, I am just curious if there’s a way to optimize my solution
In my case I don’t get an error, my REPL just stops printing after a certain size and abbreviates the rest with a ...
I agree working in lazy sequence and not materializing such a huge number of elements would prevent the OutOfMemoryError.
I am just curious about any further optimizations that I can make.
PS: I was asked to handle values like 1e9
in a Clojure job interview after I was able to solve this question far too quickly 😄
Maybe you’ll find something interesting if you partition the data structure like so:
(take 5 (partition-by first (iterate bla [2 1])))
or maybe something can be gained of thinking in terms of the partitions being lazy themselves
hey, is there any good blog post/tutorial on how to work with Java classes in the REPL?
the specific problem I have: some function I use returns sun.nio.fs.UnixPath
and I'd like to figure out how to work with it without leaving the REPL and diving into Java docs - I don't know Java
In addition to Cora's advice, I also find https://clojuredocs.org/clojure.core/bean useful when doing interop exploration
should I use this fork or the clj-commons one? I've always been confused by this library and turned to babashka's fs
Actually, you probably should look at the Java docs. End users should not be interacting with any classes in sun.*
packages. You should be interacting with the interface, java.*nio*.file.Path
And specifically... https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html
I think it's good to mention that clojure.java.javadoc/javadoc
(aliased to javadoc
in any newly created clojure repl) will usually take you to the right docs for a given object or class
to avoid further confusion, I removed the fork of clj-commons/fs from my github account
Hi everyone! Is there any way to pretty format code in cursive?
For example I have inline code:
(reduce (fn [acc [key value]] (apply str acc (repeat (read-string key) value))) "" (apply assoc {} data))
Is there any way to formatting in cursive in new lines with ⌥⌘L ? Any Advice, guides articles would help. Thx!
@sarna.dev you can use babashka.fs/file
to turn such a java.nio thing into a java.io.File
the sun classes appear because those java.nio things have OS-specific implementations so you see the implementation class name rather than their abstract class or interface
If you're doing a lot of heavy lifting with files, you'll be doing a lot of Java interop, and then you'll find a world that either expects File
everywhere or a different (more modern Java) world that expects Path
everywhere 🙂
Docstrings should tell you. And often a main entry point function will be string and then path or file everywhere downstream of that
@seancorfield good to know! I was surprised by the amount of Java in my Clojure - I'm writing a CLI app, I thought that'd be an easy first project. wasn't expecting to be slapped in the face with Java objects straight away :D
clojure doesn't hide the underlying implementation much, even functions are objects that implement clojure.lang.IFn
babashka.fs
functions take strings, io Files or nio Paths so as long as you combines fns from that lib, you should not really notice what type of Java class you're dealing with
unless you're passing it to another API. I think most APIs still expect a java.io.File so in that case you can use fs/file
to coerce
@sarna.dev Are you mostly copying files and directories around or...?
@mailmeupinside keep in mind that what the REPL prints out is the class name for an object, which might represent a non-public implementation class. In your example a sun.nio.fs.UnixPath is such a private class, and the public interface intended to be used is java.nio.file.Path
sometimes it's a bit tricky to determine the public API for an opaque private object.
One trick to inspect available API is (supers (class the-object))
Sometimes I wish the REPL didn't print the private names, and instead the public capabilities of an object
@seancorfield creating new files and directories, writing and reading from them. and also some copying/swapping files
should take you to the same page
supers
is pretty useful to get some ideas though
user=> (supers (class (.toPath (jio/file "deps.edn"))))
#{java.lang.Iterable java.lang.Comparable java.nio.file.Path java.lang.Object java.nio.file.Watchable}
and for direct extension chains
user=> (parents (class (.toPath (jio/file "deps.edn"))))
#{java.nio.file.Path java.lang.Object}
(parents works with multimethod tag hierarchies too)
see https://clojure.org/reference/multimethods for more on custom hierarchies
["X == other.X" " &&" "Y == other.Y" ";"] -> ["X == other.X &&" "Y == other.Y;"]
how will you do this vector transformation?
can you say in words the rules? it appears from this snippet that you want to join the first two elements in a vector of strings?
Take a look at the partition
, str
, and into
functions
and map
(let [in ["a " "b " "c " "d "]]
(mapv (fn [strs] (apply str strs)) (partition-all 2 in)))
apply str
always looks odd to me -- I find clojure.string/join
easier to read: (clojure.string/join strs)
(although I always (:require [clojure.string :as str])
and then it would be (str/join strs)
)
i used to think that but when i looked at the source of str
i put that fear/worry to bed
Not sure I follow @dpsutton?
Oh, you mean that str/join
without a separator is apply str
?
ah, i used to think that clojure.string/str
would be "optimized" to handle a collection better but str
is basically the same. i always assumed that the one that called join would somehow be better
str/join
is still more readable than apply str
for most folk.