This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-06-22
Channels
- # announcements (7)
- # babashka (1)
- # beginners (87)
- # boot (1)
- # cider (1)
- # clj-kondo (33)
- # cljfx (1)
- # cljs-dev (8)
- # clojars (3)
- # clojure (105)
- # clojure-austin (3)
- # clojure-europe (74)
- # clojure-finland (1)
- # clojure-korea (4)
- # clojure-nl (1)
- # clojure-uk (6)
- # clojurescript (10)
- # conjure (9)
- # cursive (29)
- # datalog (6)
- # datomic (13)
- # emacs (3)
- # events (4)
- # figwheel-main (1)
- # gratitude (1)
- # humbleui (6)
- # introduce-yourself (7)
- # jackdaw (1)
- # jobs (1)
- # lsp (29)
- # malli (3)
- # nbb (2)
- # podcasts-discuss (1)
- # portal (5)
- # re-frame (4)
- # reitit (28)
- # remote-jobs (5)
- # shadow-cljs (38)
- # tools-deps (46)
- # vim (6)
- # xtdb (24)
Is there a difference between using this
explicitly in defrecord's method body vs using the name of the field directly?
That is
(defrecord simple [s]
protocol/EventSender
(send-user-event [this u e] (prn "s: " (:s this))))
vs.
(defrecord simple [s]
protocol/EventSender
(send-user-event [this u e] (prn "s: " s)))
I first thought that maybe the second version captures the value of s
at the time when the record was created but that's not the case "
(defrecord simple [s]
protocol/EventSender
(send-user-event [this u e] (println "s: " s)))
(def ss (->simple "ahoj"))
;; this prints: s: hello
(protocol/send-user-event (assoc ss :s "hello") 1 {:a :b})
From the docstring: https://clojuredocs.org/clojure.core/defrecord > Note that method bodies are > not closures, the local environment includes only the named fields, > and those fields can be accessed directly.
It's better and faster to access the field directly
What are the cases when is using this
actually useful or necessary?
I found my defrecords' methods bodies don't need this at all.
I actually found one case in my code: (proto/get-subscription this subscription-id)
below
(defrecord FakeSubscriptionService [plans addons subscriptions]
proto/SubscriptionService
...
(get-subscription [_this subscription-id]
(find-by-id subscriptions subscription-id))
(update-subscription-custom-fields [this subscription-id custom-fields]
(when-let [subscription (proto/get-subscription this subscription-id)]
(merge subscription custom-fields))))
I asked a very similar question a few months back: https://clojurians.slack.com/archives/C03S1KBA2/p1648833619267089
Why can't I unform a map? I see that the map keys aren't really conformed but the values are conformed. Is there a workaround?
(s/def ::test-spec
(s/map-of (s/or :keyword keyword? :string string?)
(s/or :keyword keyword? :string string?)))
(s/unform ::test-spec (s/conform ::test-spec {:kw "val"}))
;; nth not supported on this type cljs.core/Keyword
(s/conform ::test-spec {:kw "val"})
;; {:kw [:string "val"]}
(s/unform ::test-spec (s/conform ::test-spec {"kw" "val"}))
;; {"kw" "val"}
Did you read the docstring of s/map-of ?
https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html#clojure.spec.alpha/map-of
Hi, this is not a request for help but a technical understanding-related question so please ignore unless interested. I /think/ that there's a close relationship between code transformations that enable >! <! to work or async/await in other languages and continuation passing, and pythonesque generators with 'yield'. I see that people have written libraries like this one https://github.com/mszajna/await-cps to add 'yield' like semantics, could that be done with the 'go' macro instead? Or if not directly then by hacking it somehow? it feels like the work that 'go' does in code transformation must enable synchronous generators by effectively creating continuations (the state machine encapsulates the continuation?) but there's an extra layer that forces us into 'async-land'. I'm not confident of this.
They definitely share the aspect of analyzing and transforming Clojure code to support “pausing”
The go code has a different goal so not sure you can make it so that (without hacking it a lot)
Both of these mimic the analysis done in the Clojure compiler and we've considered for a long time making that more amenable to external use for things like that
thanks so much for your reply, as someone non-comp-sci pondering and trying to learn it's incredible to have people like yourself around
https://gist.github.com/hiredman/5644dd40f2621b0a783a3231ea29ff1a does some code transforms like the go macro to support delimited continuations. It has more comments and links to docs on some concepts involved. It explicitly does the transformation as a kind of cps, where the go macro is more ssa/basic blocks
is there anything related I can read? if nothing else, how did you learn to write this sort of code?
@U63D7UXJB You might also want to look at #missionary which I think can provide generator-like semantics as well as controlled async operation.
The bottom of the file has some playing around defining a go macro work alike in terms of the delimited continuation operators shift and reset
The Missionary repo is https://github.com/leonoel/missionary
(it does some fascinating code transforms)
btw if people find this interesting they might find this interesting which i bumped across in trying to google this question
there will be no need for code rewriting / CPS transform after Project Loom lands in the JVM
someone trying to make a theory and people having arguments in comments, where clojure is referenced
also, async/await is considered problematic technology, despite new langs still unfortunately adopting it
a reason for async/await to be problematic was described in this blog article that I read once: https://lucumr.pocoo.org/2020/1/1/async-pressure/ which I think in clojure language translates somewhat saying "we need both >! and <!" but maybe also that channels should have a pollable atom to describe business. Again not confident of this
@U050ECB92 I use clojurescript so loom won't help me I guess
I've read that article, but tbf it could be applied to clojure's go channels equally? since they have the same contagion property, especially in clojurescript where you can't <!!
Re: Loom - https://clojurians.slack.com/archives/C8NUSGWG6/p1652487349607519?thread_ts=1652433406.842079&cid=C8NUSGWG6 (variants of go
and go-loop
that use virtual threads so you can use <!!
inside them "without blocking").
(and needs no code transformation)
Missionary does work with ClojureScript FWIW.
@U0NCTKEV8 tbf pedantry can help people like me new to the topic
the thing is, queues are everywhere, and controlling them is something every multithread system deals with either implicitly or explciitly
the reason that blog post is so "oh my god! here is this thing you might have a problem with!" is python code is famously single threaded
so, for example, on the jvm you can just spin up threads to do things, where doesn't use await/async or any kind of async library
and if you run away spinning them up you will bog your process down and eventual hit soft or hard limits
well that executor has a run queue which placing things in also takes up resources, etc etc
sure, but looking to them for advice about it is in some cases very one eyed man leading the blind
https://github.com/leonoel/cloroutine#guides may interest you
if you are just interesting in the mechanics of continuations you can also use "the continuation monad" to make it possible to play with that without doing a full compiler in a macro like core async does
@U02F0C62TC1 thanks for this, working down my reading list of reading lists
Also @U04V70XH6 thanks for the link to missionary, that and cloroutine underneath it seem close to what I was asking originally
Most idiomatic way of putting up an asynchronous blocking queue? Need to delete a bunch of files N seconds after the processing occurs
Use java.util.concurrent.BlockingQueue
assuming you don't care about cross process durability, use a java DelayQueue, launch a thread to poll it
Oh yeah, that'd be better for encoding the delay
Thanks for the suggestions! Will check both solutions:+1: are there any clojure "connectors", or do I just have to go full interop?
Generally java.util.concurrent stuff is reasonably well designed. I've not looked for clojure wrappers because they feel pretty comfortable to use, given you want mutability.
(the one notable exception to this imo is ConcurrentLinkedQueue not supporting casing the tail, which was a big enough gripe I wrote my own queue in clojure)
@U5NCUG8NR do you have a link to your queue impl?
I'm interested 😄
thanks!!
No problem, lmk if you have any questions.
It's based on the same whitepaper as the java util concurrent concurrent linked queue, but you can cas the tail
roger that
and I will, thanks
do you know the name of the paper, off-hand?
no, but it is in the javadoc for that class
ahhh ok thanks!
this is really great, btw. I have need of a queue with similar properties
it's nice to see how
Yeah, i was really surprised that not only was it not in the stdlib, I couldn't find an implementation for it in java or clojure as a library either
what do you have so far?
you might have luck using buddy for some of this https://github.com/funcool/buddy
and what issue are you seeing with your implementation?
also I think SHA256withRSA already does hashing of the input, so you're double-hashing it?
I might be wrong
The service errors out with the following on their end
System.Security.Cryptography.CryptographicException: ASN1 corrupted data
nothing jumps out to me right now except the it's hashed twice
@corasaurus-hex which lines?
lines 47-50 you SHA256 the message, then within the function called on 53 you're using SHA256WithRSA which I believe will SHA256 the message again
it's worth a try just skipping the first SHA256 to see if it works
@corasaurus-hex that got me one step further Learned c# has unsigned bytes and java has signed bytes. I’ve narrowed it down to just the following lines Getting different results. comment lines in c#
;; var rsa = new RSACryptoServiceProvider();
;; rsa.ImportRSAPrivateKey(source: Convert.FromBase64String(privateKey),
;; bytesRead: out int _ );
(defn get-private-key [s]
(.generatePrivate
(KeyFactory/getInstance "RSA")
(PKCS8EncodedKeySpec. (decode64 s))))
(def rsa (get-private-key privateKey))
;; var rsaFormatter = new RSAPKCS1SignatureFormatter (rsa);
;; rsaFormatter.SetHashAlgorithm (algorithm);
;; var result = rsaFormatter.CreateSignature (signingHash);
(def rsaFormatter (java.security.Signature/getInstance "SHA256withRSA"))
(.initSign rsaFormatter rsa)
(.update rsaFormatter signingHash)
(def result (.sign rsaFormatter))
I have been doing something similar with this code: https://github.com/tstout/conceal
@corasaurus-hex that got me one step further Learned c# has unsigned bytes and java has signed bytes. I’ve narrowed it down to just the following lines Getting different results. comment lines in c#
;; var rsa = new RSACryptoServiceProvider();
;; rsa.ImportRSAPrivateKey(source: Convert.FromBase64String(privateKey),
;; bytesRead: out int _ );
(defn get-private-key [s]
(.generatePrivate
(KeyFactory/getInstance "RSA")
(PKCS8EncodedKeySpec. (decode64 s))))
(def rsa (get-private-key privateKey))
;; var rsaFormatter = new RSAPKCS1SignatureFormatter (rsa);
;; rsaFormatter.SetHashAlgorithm (algorithm);
;; var result = rsaFormatter.CreateSignature (signingHash);
(def rsaFormatter (java.security.Signature/getInstance "SHA256withRSA"))
(.initSign rsaFormatter rsa)
(.update rsaFormatter signingHash)
(def result (.sign rsaFormatter))