This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-08
Channels
- # adventofcode (9)
- # announcements (5)
- # babashka (3)
- # beginners (46)
- # calva (21)
- # cider (15)
- # clj-kondo (20)
- # cljs-dev (57)
- # cljsrn (10)
- # clojure (147)
- # clojure-dev (6)
- # clojure-europe (3)
- # clojure-france (2)
- # clojure-italy (8)
- # clojure-nl (18)
- # clojure-norway (5)
- # clojure-spec (16)
- # clojure-uk (63)
- # clojuredesign-podcast (7)
- # clojurescript (65)
- # clojurex (42)
- # cursive (12)
- # datomic (10)
- # fulcro (47)
- # graalvm (102)
- # graphql (2)
- # jobs (5)
- # joker (12)
- # off-topic (33)
- # pedestal (6)
- # re-frame (6)
- # reagent (8)
- # reitit (6)
- # remote-jobs (4)
- # rewrite-clj (10)
- # shadow-cljs (86)
- # sql (45)
- # testing (4)
- # tools-deps (43)
- # vim (8)
- # xtdb (3)
Is there a way to somehow iterate over lexical bindings inside body of a function or a let
form (that should happen in the context of macro expansion of course)?
I'm pretty sure I have seen some Clojure debugger-type library thingy that might be implemented by doing that, or something similar. Let's see if I can remember which one it is...
I haven't tried this, but the code that includes a definition of 'local-bindings' in this StackOverflow Q&A might be relevant? https://stackoverflow.com/questions/2352020/debugging-in-clojure
That code looks to me to be specific to Clojure/JVM, and wouldn't work for ClojureScript, because it is reaching into internals of Clojure/JVM compiler specific to it.
@andy.fingerhut Thanks, this is exactly what I was looking for.
Google search for clojure.lang.compiler/LOCAL_ENV turns up other places it has been used for similar purposes, too, in case you want other examples.
i was playing with alex and george's debug repl recently - fwiw, the latest version doesn't use compiler internals. still i didn't find it to work as-is for cljs -- though it seems likely it would work for clojure clr. i believe it uses &env now: https://github.com/GeorgeJahad/debug-repl/blob/master/src/alex_and_georges/debug_repl.clj#L29_L46
fwiw. the speculation bit there seems fairly in line with what i saw combing through past clojure irc logs 🙂
What makes you think that? It isn't mentioned on https://clojure.org/reference/macros
I should have been more clear: :locals
is never populated in &env
when using macroexpand
, so if your macro depends on it, you wont’ be able to test it that way
more just complaining on my end that I can’t use macroexpand
to test my macro I’m working on <_<
Hello folks! When I run my function in the REPL I get > Execution error (StackOverflowError) at (REPL:1). but the stack trace contains nothing of my code, only many clojure.core$concat, $seq and clojure.lang.LazySeq. How do I troubleshoot this? How do I find out where in my code am I creating this??? The stack trace:
[[clojure.lang.LazySeq sval "LazySeq.java" 42]
[clojure.lang.LazySeq seq "LazySeq.java" 51]
[clojure.lang.RT seq "RT.java" 535]
[clojure.core$seq__5402 invokeStatic "core.clj" 137]
[clojure.core$concat$fn__5493 invoke "core.clj" 725]
[clojure.lang.LazySeq sval "LazySeq.java" 42]
... (these few repeated many times over)
[clojure.lang.LazySeq seq "LazySeq.java" 51]
[clojure.lang.RT seq "RT.java" 535]
[clojure.core$seq__5402 invokeStatic "core.clj" 137]])
can you show the code or the error message at least ? 😄
only having the stack trace is very little to go on
ah, now i get it, the stackoverflow is your error message ... any chance you built endless recursion there ?
https://stuartsierra.com/2015/04/26/clojure-donts-concat this might give you some insight. if you built up a sequence using concats, you end up with too many lazy thunks to realize the sequence later and run out of stack
Thank. I am pretty sure I do not build a sequence manually anywhere but I do operate on data using lazy sequence operations.
I cannot really share the code as there is few hundred lines of code involved. I just call my (fetch-and-process-all-invoices)
.
The error message is there ☝️ and it is useless: Execution error (StackOverflowError) at (REPL:1).
The only hypothesis is that the error actually happens after my function run, when REPL tries to display its output, that could explain why there is only clojure.* in the stacktrace.
if that was true, you would see a different error message (not Execution error)
You are right. But why doesn't the stack trace have anything of my code? How do I find where is this happening?
do you use concat anywhere?
Yes, at a few places, I will look into that / alternatives. (And reread the article!) Ah, I guess I am hitting this > and the accumulated stack frames of seq prevent us from seeing where the error originated
Hm, looking through the code I do not see any suspicious use of concat
with multiple arguments, mostly just (merge-with concat ...)
etc. I have to re-check...
are you doing that in a loop / recursion?
Thank you, no, I am not. I now deployed some (I am close to 100% sure unrelated) changes and the problem went away it seems. :hand_with_index_and_middle_fingers_crossed: it was just a fluke...
that seems unlikely
I know . I have no idea what's happening. So everything is as normally:) Thank you for your help! I'll see if it comes back..
why clojure doesn’t have a list literal or a symbol literal? > Clojure has no literal representation for Lists. If you write a List out in your program, it is interpreted as code. At first glance, it appears that quoting the List is a good solution. However, if you quote a List, the elements of the List won’t be evaluated. That means that a quoted List is only useful for Lists of literals. https://purelyfunctional.tv/guide/clojure-collections/ Clojure is data oriented, I was wondering why there is no literal for a symbol or a list of data. One supposition would be homoiconicity could not be achieved, but I could not explain why.
#inst "1985-04-12"
=> #inst"1985-04-12T00:00:00.000-00:00"
#{:a}
=> #{:a}
[1 2 3]
=> [1 2 3]
{:a 1}
=> {:a 1}
'(1 2 3)
=> (1 2 3)
(1 2 3)
=> error
I don't understand the question. '(a b c)
is a list literal containing 3 symbol literals
It needs quoting to avoid being evaluated in a REPL, unlike a map or set literal, that is true, because code is inside of lists, too.
Are you asking why it needs quoting at the REPL to avoid evaluation, and maps and sets do not?
Maybe a little more -- all of those expressions are being read, then evaluated, and the result of evaluation printed, at the REPL.
maps and sets are read, and during evaluation, they evaluate to themselves, as do keywords, numbers, and #inst values. All subexpressions of the map and set literals are also evaluated, recursively, too, so if a map or set literal contained a parenthesized expression, it would be evaluated, and present the same difference in behavior as if the parenthesized expression were typed as the whole expression.
If lists also always evaluated to themselves, like maps and sets did, then they could not be used to contains code for evaluation -- you would need some other syntax for that? (not sure if that makes sense)
Maybe this is obvious but I didn't see it mentioned: you can use (list ...)
(list 1 2 (+ 1 2))
=> (1 2 3)
With (list ...)
the values inside the list are not quoted, like they are when you quote the list itself:
'(1 2 (+ 1 2))
=> (1 2 (+ 1 2))
If you're familiar with other Lisps, you can also use the more traditional cons
to build lists in Clojure:
(cons 1 (cons 2 (cons (+ 1 2) nil)))
=> (1 2 3)
I should be a little more precise, even without the quote in front (a b c)
is a list literal containing 3 symbol literals. If you only do read
on that, no eval
, you get a list.
It is the eval
that causes an error if any of a
b
or c
are not defined with values, or if the value of a
is not something that can be called as a function or macro.
user=> (read-string "(a b c)")
(a b c)
user=> (eval (read-string "(a b c)"))
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: a in this context
As opposed to this, where the set evaluates to itself, and so do 1, 2, and 3:
user=> (read-string "#{1 2 3}")
#{1 3 2}
user=> (eval (read-string "#{1 2 3}"))
#{1 3 2}
In the next example, reading returns a set containing 3 symbols. Without eval
, no problem, you get back such a set. Eval of the set returns a set, but also recursively calls eval on all elements, which is when it finds that a
is undefined:
user=> (read-string "#{a b c}")
#{a c b}
user=> (eval (read-string "#{a b c}"))
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: a in this context
Reading a list or set or map are all pretty consistent behavior, and the syntax for each are all literal syntax for those data structures. The rules for eval
behavior on a list are different than the rules for eval
behavior on a set or map -- the first element of the list is special.
![thanks2](https://emoji.slack-edge.com/T03RZGPFR/thanks2/50a7eae6ac7040b9.gif)
I am stuck trying to proxy an java.io.OutputStream. It has two different write methods, one overloaded with a byte array and one overloaded with an integer. I seem to type hint things correctly to tell the compiler how to implement the write methods.
My solution right now is to write a java class that derives from output stream and names those methods differently as abstract methods.
That would lead to an abstract method error as you will have only overridden one of the two methods.
(def x
(proxy [java.io.OutputStream] []
(write
([o] (println (class o)))
([o s len]))))
#'user/x
user=> (.write ^java.io.OutputStream x 2)
java.lang.Integer
nil
user=> (.write ^java.io.OutputStream x ^bytes (byte-array 0))
[B
I've proxy'ed outputstreams a few times, and it is always the same, type check in the write method
huh. Well, you are overriding the object method (byte[]) one I think. I wonder how that is working or if just no one calls the int method.
like, ghadi literal posted a transcript of a repl session showing you it working for both the int write method and the byte[] write method
So then when you proxied did it override all methods with one signature and call your code for both?
e.g. you give it a function body (which may have multiple arities) and all methods with that name will call that function
@lukaszkorecki Any chance you have some sample code? This stuff is confusing
@josh_tackett sure, let me find a version I can share
@josh_tackett here you go: https://gist.github.com/lukaszkorecki/f978452d1b3e88c3d88832d3defd5e74 - usual disclaimer, code is as-is etc etc etc
also, this works only with java 8 - because it relies on javax.xml.bind DatatypeConverter
I'm going to try to extend buddy-core to handle :aes256-cbc-hmac-sha256
got it, i will circle back to this if I can't extend buddy-core
I don't think I ever used it - usually BouncyCastle does everything I needed, including PGP and the API is pretty straightforward, what's confusing is the overall cryptography stuff 😉
beware -- neither BouncyCastle nor buddy are "misuse resistant" libraries like libsodium
or google's tink
pgp tends to be less straight forward once you get to multiple objects, subkeys etc. 🙂 at least if you do it with bouncy castle, there are lots of pitfalls
well it's also the fact that it's not just crypto
it's about containers and objects inside of them
way more than "this is just encrypted data" 🙂
and a big part of that in my mind is just overengineering at it's finest
then again ... it does the job ... so i don't complain 🙂
Luckily the PGP stuff I was working on was pretty light weight and in a controlled environment, implementing production-grade, customer facing features is indeed a task that needs a lot of attention and verification.
@lukaszkorecki I'm getting this error: java.lang.ClassNotFoundException: javax.crypto
@lukaszkorecki actually it can't find any of the libs I'm trying to import haha
because you aren't using the his ns verbatim, you are trying to turn it into an (import ...) call in the repl, but failed to quote the imported classes
(:import java.security.SecureRandom (javax.crypto Cipher SecretKeyFactory) (javax.crypto.spec SecretKeySpec IvParameterSpec PBEKeySpec) (javax.xml.bind DatatypeConverter) (org.bouncycastle.jce.provider BouncyCastleProvider) (java.security Security)))
so he does it with an import
(ns skyscraper.scrape.encryption
(:import javax.crypto Cipher KeyGenerator SecretKey
javax.crypto.spec SecretKeySpec
java.security SecureRandom
org.apache.commons.codec.binary Base64))
(defn bytes [s]
(.getBytes s "UTF-8"))
(defn base64 [b]
(Base64/encodeBase64String b))
(defn debase64 [s]
(Base64/decodeBase64 (bytes s)))
(defn get-raw-key [seed]
(let [keygen (KeyGenerator/getInstance "AES")
sr (SecureRandom/getInstance "SHA1PRNG")]
(.setSeed sr (bytes seed))
(.init keygen 128 sr)
(.. keygen generateKey getEncoded)))
(defn get-cipher [mode seed]
(let [key-spec (SecretKeySpec. (get-raw-key seed) "AES")
cipher (Cipher/getInstance "AES")]
(.init cipher mode key-spec)
cipher))
(defn encrypt [text key]
(let [bytes (bytes text)
cipher (get-cipher Cipher/ENCRYPT_MODE key)]
(base64 (.doFinal cipher bytes))))
(defn decrypt [text key]
(let [cipher (get-cipher Cipher/DECRYPT_MODE key)]
(String. (.doFinal cipher (debase64 text)))))
ya I'm using :import
ok, got it. how do I fix it?
(ns skyscraper.scrape.encryption
(:import (javax.crypto Cipher KeyGenerator SecretKey)
(javax.crypto.spec SecretKeySpec)
(java.security SecureRandom)
(org.apache.commons.codec.binary Base64)))
👍 thank you
is it a bad idea to be using vectors like so?
(ns skyscraper.scrape.encryption
(:import [javax.crypto Cipher KeyGenerator SecretKey]
[javax.crypto.spec SecretKeySpec]
[java.security SecureRandom]
[org.apache.commons.codec.binary Base64]))
i see vectors used in clojure.instant, but lists elsewhereI think both are common in practice
https://stuartsierra.com/2016/08/27/how-to-ns is pretty common and good advice
I disagree only with using () for imports :)
oops, https://stuartsierra.com/2016/clojure-how-to-ns.html is better link
and fyi, Rich thought Stuart's reasoning for lists in that article was bogus :)
https://github.com/gfredericks/how-to-ns implements that article its low star count doesn't do justice to how well it works
I’ve taken to categorising requires where they grow very large (which I bet will make some people frown). I.e., you’ll see stuff like:
;; Mutations
[poc.mutations.search :as search-mut]
;; Components
[ :refer [app]]
[poc.components.token :refer [Token]]
;; Fulcro
[com.fulcrologic.fulcro.mutations :as mutations :refer [defmutation]]
[com.fulcrologic.fulcro.algorithms.merge :as merge]
oh, i hadn't seen that sort of arrangement before -- thanks for sharing. by coincidence i happen to be doing things alphabetically like the stuart sierra article says, iiuc.
I’ve mostly gone alphabetically, but started getting some namespaces with quite a lot of dependencies due to breaking things up in fairly small pieces, and then it became more useful to organize them primarily by purpose.
Though I still tend to stick standard lib stuff at the top prior to everything else. But when I’m pulling in a bunch of UI components, it seems to make more sense to group them than to sprinkle them around routing, clojure.string
, third party libs, and so on.
I do the same when it's particularly thorny tracking to deps - like in https://github.com/clojure/tools.deps.alpha/blob/master/src/main/clojure/clojure/tools/deps/alpha/util/maven.clj#L14-L49
My preference is whatever my editor uses when formatting my code. 🙂 I think clj-refactor.el uses vectors.
i also group my requireds by their "level", clojure language stuff at the top and tiny-scope app namespaces at the bottom
either is fine
I prefer vectors
@jumar a compatible alternative to jasypt in clojure: https://github.com/pyr/jcipher