This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-04-03
Channels
- # announcements (5)
- # babashka (8)
- # beginners (98)
- # biff (2)
- # calva (20)
- # cider (16)
- # clerk (2)
- # clj-kondo (20)
- # cljdoc (19)
- # clojure (90)
- # clojure-art (3)
- # clojure-boston (1)
- # clojure-europe (7)
- # clojure-nl (2)
- # clojure-norway (47)
- # clojure-uk (3)
- # clojurescript (10)
- # cursive (10)
- # data-science (1)
- # datalevin (1)
- # defnpodcast (1)
- # events (2)
- # fulcro (11)
- # gratitude (2)
- # honeysql (18)
- # hyperfiddle (11)
- # introduce-yourself (1)
- # jobs (2)
- # lambdaisland (4)
- # lsp (6)
- # malli (4)
- # membrane (3)
- # off-topic (58)
- # polylith (14)
- # portal (2)
- # releases (2)
- # ring-swagger (4)
- # tools-deps (8)
- # xtdb (8)
hi, I am porting some go code to clojure and woud like to know how/if I can implement the go pattern of checking things as I go and stopping processing once a condition fails. Go seems to use multiple returns to solve this issue and they just return error. But with clojure not having a "return" statement, how would I go about this ? I guess my main interest is: how do I stop doing work once I know it's no use going forward, in a processing flow that is procedural ?! For people interested in sharing solutions: I prefer easy to read and reason than one liners / macros . https://github.com/slackhq/nebula/blob/bbb15f8cb1ecdc7e423ffd1a85a3fc8c0898bf95/cert/cert.go#L694
There have been plenty, plenty of discussions on error handling and early returns. Feels like the most recent was just a week ago.
Ah, two weeks ago: https://clojurians.slack.com/archives/C03S1KBA2/p1711033948990839
seems to be a common issue I guess - maybe docs can be improved / patterns documented ?!
Also, since that Go function seems to return either an error or a nil, the conversion to Clojure is trivial and doesn't require any gimmicks or particular approaches. Just use (if-let [error (do-stuff)] error (... do more stuff ...))
.
> maybe docs can be improved / patterns documented ?! Docs PRs are always welcome. :) But note that there's no "the" approach.
not sure if it's that simple with the error or nil . Will have to think about it. Thanks for the suggestion though
> Docs PRs are always welcome. :) But note that there's no "the" approach. I'm currently trying to formulate the thing in my head, not ready for a PR 🙂 But I do have a feeling that it's something recurring => opportunity .
FWIW, here's how I'd write something like that there.
Used or
instead of if-let
and used a vector to return two values in one case. IMO it's even easier to reason about then the original.
(defn verify-private-key [curve ^bytes key]
(if (not= curve ns-details/curve)
"curve in cert and private key supplied don't match"
(if nc-details/ca?
(case curve
:Curve_CURVE25519
(when (not= (alength key) ed25519/private-key-size)
;; Why do they use a constant to check for the length
;; but a hard-coded value to report a mismatch?
"key was not 64 bytes, is invalid ed25519 private key")
:Curve_P256
(let [[priv-key err] (.NewPrivateKey (ecdh/P256) key)]
(if err
"cannot parse private key as P256"
(let [pub (-> priv-key (.PublicKey) (.Bytes))]
(when-not (bytes-equal? pub nc-details/PublicKey)
"public key in cert and private key supplied don't match"))))
(str "invalid curve: " curve))
(let [[pub err]
(case curve
:Curve_CURVE25519
(curve25519/X25519 key curve25519/Basepoint)
:Curve_P256
(let [[priv-key err] (.NewPrivateKey (ecdh/P256) key)]
[(when-not err (-> priv-key (.PublicKey) (.Bytes))) err])
[nil (str "invalid curve: " curve)])]
(or err
(when-not (bytes-equal? pub nc-details/PublicKey)
"public key in cert and private key supplied don't match"))))))
Could also remove some unnecessary duplication, but didn't want to deviate from the original too much.
And I find such things more often than one would expect, where using the simplest, dumbest solution on top of immutable data and absence of arbitrarily placed returns makes things easier to reason about. Not too long ago, I had to rewrite MusicXML parser and validator from Python to Clojure. Took me a bit because the original code was ported from C++ and used a lot of variable overrides, mutation, early returns. In the end, the code became simpler and I found a few bugs that were caused by a mismatch of the initial authors' expectations and what the MusicXML format allows.
Of course, I'm not saying that it's always the case. Some algorithms' implementations do benefit from less functional approaches.
I kind of feel that too. my brain is wired less functional, and like you said: some situations are easier to implement less functional and maybe then improve
When i am doing things that have multiple IO ops and can fail at somepoint during execution of a series of functions. i try to leverage this idea https://medium.com/appsflyerengineering/railway-oriented-programming-clojure-and-exception-handling-why-and-how-89d75cc94c58 basically make a macro which returns result and error, if error is true, just propagate it. you wrap in a try catch and you can handle the scenario in a readable way
yep. (with-pirate-voice "I've been serchin' all my life for this ARRRgh" ). IMO this shold be part of clojure.core Thank you @U069RSXM1CP . Seems like there are a few libraries implementing the concept: one is https://github.com/druids/rop
Oh nice 😄 ive not even considered using a library for this haha ill take a look
i think ive seen https://github.com/adambard/failjure in a project before 😄 another ROP impl
makes me wish we were on clojureverse forums just so we could point everyone to the same thread lol
bumping/pinning threads in forums is more obvious than searching for specific threads in slack.
I'm focusing on failjure now. seems to be good for what I am trying to achieve . Will know more once I've written more code with it
There was a discussion over in #clojuredesign-podcast as well https://clojurians.slack.com/archives/CKKPVDX53/p1712678059534529
Hi all, I just ran into a situation where this issue affected me and wanted to mention it here. (https://clojure.atlassian.net/browse/CLJ-2794)
This relates to gen-class
not implementing the default implementations on interfaces correctly. What happened for me was that the kafka client library has an interface which in a recent update got a new overload, with a default implementation calling the old overload. Because of this issue in gen-class
, the default implementation did not fire and caused a break on my side. What was a backwards-compatible change for other JVM languages, was a breaking change for me. ☮️
feel free to add any info here: https://ask.clojure.org/index.php/13178/why-gen-class-does-not-generate-default-interface-methods
don't think we are going to address in 1.12, but it's in my list for 1.13
thank you for the update
btw - in gen-class you can do this kind of thing for overloads with same arity but different parameter types:
prefix-methodName-ParamType1-ParamType2
and so on. What is the correct ParamType
for byte[]
? I used prefix-methodName-String-bytes
. Will this work like I expect?
I doubt it :) off the top of my head, don’t know, that is implementation detail, not part of public api of gen-class
It might not be part of the public API but it's for sure part of the implied API, if StackOverflow is anything to go by. It solves a problem people have with interop.
For future me's benefit: It would be prefix-methodName-String-byte<>
to match an overload of methodName
that takes a String in first position and a byte-array in second position.
Anyway - thanks for input 👍:skin-tone-4:
it's quite likely for that expectation of internals to be broken in 1.12 with the new class array syntax
that is a little bit frightening.
well, these are internals
I have not seen the changes so far affecting anyone in this way, but we are redo-ing a lot of it right now, not sure if that will affect things. it's possible that syntax there is coming from clojure.java.reflect, which is not changing, in which case nothing would change
I looked at the code, it's not based on either of these so shouldn't change
I remember at a conj one of the Clojure luminaries commented "there is no dishonor" in stepping back to the host language to meet interop constraints. Perhaps instead of relying on gen-class internals, this occasion calls for a solution that doesn't use gen-class!
I'm having a hard time getting rid of a reflection warning around a JavaFX ListCell and proxy-super
, not sure if it is possible. Already asked this in the past but the solutions didn't work. Details on the 🧵 ...
I'm implementing something like this :
public class MyCell extends ListCell {
public MyCell() { }
@Override protected void updateItem(Number item, boolean empty) {
// calling super here is very important - don't skip this!
super.updateItem(item, empty);
...
}
}
and this are the two things I've tried :
clj -Sdeps '{:deps {org.openjfx/javafx-controls {:mvn/version "21.0.3-ea+1"}}}'
user=> (import 'javafx.scene.control.ListCell)
user=> (set! *warn-on-reflection* true)
user=> (defn list-cell-factory []
(proxy [ListCell] []
(updateItem [item empty?]
(proxy-super updateItem item empty?))))
Reflection warning - call to method updateItem can't be resolved (target class is unknown).
and also :
clj -Sdeps '{:deps {org.openjfx/javafx-controls {:mvn/version "21.0.3-ea+1"}}}'
user=> (import 'javafx.scene.control.ListCell)
user=> (set! *warn-on-reflection* true)
user=> (defn list-cell-factory []
(proxy [ListCell] []
(updateItem [item empty?]
(let [^ListCell this this]
(proxy-super updateItem item empty?)))))
Reflection warning - call to method updateItem on javafx.scene.control.ListCell can't be resolved (no such method).
I'm starting the repl from scratch before trying since there is some stateful stuff going on this ListCell static initializers and it complains about toolkit not initialized in this contrived example if you eval the proxy twice
Can you just write this in java?
well, I mean it works in Clojure, my question is about this kinds of reflections, trying to see if there is a way
note the answer is in the https://clojurians.slack.com/archives/C03S1KBA2/p1627918259119400 two comments below
https://ask.clojure.org/index.php/10890/reflection-warning-about-field-when-calling-method seems similar
oh I see, so the reflection can't be avoided
I guess we should have a reflection skip meta system then for this cases, (ala :clj-kondo/ignore), so we can keep or reflections log clean
Hi I am trying to use malli to validate the input LocalDate string in params I did try to use malli.experimental.time but seems like it cannot handle the localDate string Ideally i used regex ealier but this breaks the Swagger doc as json is not able to convert regex. So if someone has some experiance with this that will be helpful
(def some-obj
[:map
[:rate [:maybe number?]]
[:myDate [:maybe [:re #"^\d{4}-\d{2}-\d{2}"]]]
[:myDate2 [:maybe [:re #"^\d{4}-\d{2}-\d{2}"]]]])
Want to validate localDate string like "2020-12-02"
#malli/maybe #ring-swagger is probably going to have a more knowledgeable base for this 😄
I just tried with :query [:map [:a [:re #"a"]]]
being in :parameters
of an endpoint.
The picture is what I get in the generated Swagger UI for the field.
Since you mention swagger I assume it is, you need a time transformer https://github.com/metosin/malli/blob/master/src/malli/experimental/time/transform.cljc
To add to my first comment - I use the latest alpha versions of all the relevant packages.
@UK0810AQ2 can u please help me with a small eg !
When creating the coercion, update the default opts https://github.com/metosin/reitit/blob/master/modules/reitit-malli/src/reitit/coercion/malli.cljc#L84 Stick in your own provider
Swagger Error
Caused by: com.fasterxml.jackson.core.JsonGenerationException: Cannot JSON encode object of class: class java.util.regex.Pattern: ^\d{4}-\d{2}-\d{2}
Best to move this to #CLDK6MFMK but... You need to register a custom encoder for Regex class in Cheshire: https://github.com/dakrone/cheshire?tab=readme-ov-file#custom-encoders
we are using charred for json implementations we still need to make changes in Cheshire ?
because you're getting an error from Jackson, it would suggest that the swagger generator uses Cheshire internally, what Json library your own code is using has no influence
Also @U06C2P5N21L Please don't post multiple top-level messages in a channel about the same issue. Post details in a thread to keep the communication here easier for everyone to follow and respond to.
@U04V70XH6 noted, thanks !
Hello any help with date parsing? At the moment this
(java.time.LocalDate/parse "01-Jul-99" (java.time.format.DateTimeFormatter/ofPattern "dd-MMM-yy"))
Why obviously? There's nothing in the input string that would help the date parser to determine if the year is 1099, 1999 or 2099
Docs for https://docs.oracle.com/javase/10/docs/api/java/time/format/DateTimeFormatter.html says yy
is a year type, which is defined thus:
> Year: The count of letters determines the minimum field width below which padding is used. If the count of letters is two, then a reduced
two digit form is used. For printing, this outputs the rightmost two digits. For parsing, this will parse using the base value of 2000, resulting in a year within the range 2000 to 2099 inclusive.
looks like there's a way to override that setting but it's a little gnarly https://stackoverflow.com/a/32783553/706499
Also @U0KGSPTGB Please don't post multiple top-level messages in a channel about the same issue. Post details in a thread to keep the communication here easier for everyone to follow and respond to.