Fork me on GitHub
#clojure
<
2024-01-24
>
Aya07:01:45

Hi guys I am getting the following error when trying to read an email field from edn using the clojure.edn/read-string function

Invalid constituent character: @
does anyone have an idea how I can fix this? my edn looks like this
{
 "env-details" {:email ""
                     :password "userpassword"}
}

Aya07:01:41

code looks like

(defn get-user-data [payload type]
  (cond (= type :edn) (edn/read-string payload)
        :else payload))

p-himik07:01:30

read-string reads a string expecting to find EDN data in that string. user in EDN would be a valid symbol. is not a valid name for anything.

Aya07:01:05

not sure I follow so I should try not use email on edn?

p-himik07:01:10

You need to turn it from a symbol into a string. A correct EDN string representation of a string with an email would be "\"\"".

Aya07:01:31

ah yeah that is correct

Aya07:01:34

thank you

p-himik07:01:50

But if you know that it's always a string and you already have the outer data deserialized, just don't use EDN at all at that level - store the value as a regular string.

avi14:01:09

I’m not sure the problem is in fact that is an invalid symbol… it looks like a string to me, in that payload example. In fact I tested out the above function and payload myself and it succeeded with no errors:

(require '[clojure.edn :as edn])
(let [payload  "{\"env-details\" {:email \"\"
                                  :password \"userpassword\"}}"
      type  :edn
      f  (fn get-user-data [payload type]
           (cond
             (= type :edn)  (edn/read-string payload)
             :else          payload))]
  (f payload type))
result: {"env-details" {:email "" :password "userpassword"}} I’m not sure what’s causing the error, but I suspect that perhaps the problem is that the value you are passing in as payload is not in fact a valid EDN string, even though the example you pasted is.

rickmoynihan09:01:08

Does anyone know of any existing parsers for ISO8601 https://en.wikipedia.org/wiki/ISO_8601#Time_intervals? Either in Java or Clojure? Or any other language for that matter? If you’re not aware of them, you can define periods of time in ISO8601 by saying <INSTANT_START>/<INSTANT_END> or <INSTANT_START>/<PERIOD_TILL_END> e.g. 2024-01-01T13:00:00Z/P1Y for the year between 1pm on 2024-01-01 and 1pm on 2025-01-01. You can also define an end instant, and specify a period before it, and there are various other short hand syntaxes. Unfortunately java.time doesn’t support the syntax; but does have partial support for some subsets of the syntax. Obviously ISO8601 instants are fully supported, but java.time.Duration and java.time.Period support only subsets i.e. time based syntax, or date based syntax, but not either or both. Whilst https://juxt.github.io/tick/#_intervals, and Allen’s interval algebra, which is cool, it doesn’t provide any parsers for this sort of thing.

p-himik10:01:29

Maybe https://github.com/MenoData/Time4J? From https://stackoverflow.com/a/44622763/564509:

// case 1 (start/end)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/2014-06-20T16:00Z"));
// output: [2012-01-01T14:15:00Z/2014-06-20T16:00:00Z)

// case 1 (with some elements missing at end component and different offset)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/08-11T16:00+00:01"));
// output: [2012-01-01T14:15:00Z/2012-08-11T15:59:00Z)

// case 1 (with missing date and offset at end component)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/16:00"));
// output: [2012-01-01T14:15:00Z/2012-01-01T16:00:00Z)

// case 2 (start/duration)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/P2DT1H45M"));
// output: [2012-01-01T14:15:00Z/2012-01-03T16:00:00Z)

// case 3 (duration/end)
System.out.println(MomentInterval.parseISO("P2DT1H45M/2012-01-01T14:15Z"));
// output: [2011-12-30T12:30:00Z/2012-01-01T14:15:00Z)

// case 4 (duration only, in standard ISO-format)
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P2DT1H45M");

// case 4 (duration only, in alternative representation)
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P0000-01-01T15:00");
System.out.println(isoDuration); // output: P1M1DT15H

rickmoynihan10:01:49

Thanks, I had stumbled on this, but for some unknown reason dismissed it — it looks like it should do the job nicely. 🙇

Stefano10:01:15

Hello everyone! Is this behaviour expected?

(with-redefs [inc #(* 2 %)] (inc 5))
;; => 6

(with-redefs [inc #(* 2 %)] (let [f inc] (f 5)))
;; => 10
Why the redef is ignored in the first case?

p-himik10:01:11

The first case probably inlines inc.

Omer ZAK11:01:07

Try

(println inc)
; #object[clojure.core$inc 0xd011f98 clojure.core$inc@d011f98]
; nil
(with-redefs [inc #(* 2 %)] (println inc))
; #object[sci.impl.fns$fun$arity_1__1168 0x2e9fd540 sci.impl.fns$fun$arity_1__1168@2e9fd540]
; nil
(with-redefs [inc #(* 2 %)] (let [f inc] (println f)))
; #object[sci.impl.fns$fun$arity_1__1168 0x676362d1 sci.impl.fns$fun$arity_1__1168@676362d1]
; nil
Different objects are referred to by inc in the three cases. Could it be due to clojure core library having been compiled with direct linking? See: https://clojure.org/reference/compilation

p-himik11:01:56

Why wouldn't those be different, regardless of the linking? You're printing different functions, so you're getting different results.

Omer ZAK11:01:47

Could depend upon different rules for dereferencing inc, depending upon whether it is used as the function in a form, or as a regular variable to be evaluated?

p-himik11:01:27

Dereferencing is the same. In the case of (inc 5) there's no dereferencing, there's inlining.

p-himik11:01:57

Because inc has inlining metadata:

(defn inc
  "Returns a number one greater than num. Does not auto-promote
  longs, will throw on overflow. See also: inc'"
  {:inline (fn [x] `(. clojure.lang.Numbers (~(if *unchecked-math* 'unchecked_inc 'inc) ~x)))
   :added "1.2"}
  [x] (. clojure.lang.Numbers (inc x)))

Stefano11:01:03

Interesting, I didn't know about inlining. That makes sense to me

Stefano11:01:10

Does it work like a macro in this case?

Stefano11:01:19

I did a quick search, it looks like it does work like a macro

Stefano11:01:06

Thanks for clarifying that

Alex Miller (Clojure team)13:01:31

Just confirming here that the difference is inlining

Derek15:01:38

When writing a custom core.cache for use with core.memoize, I'm confused as to where the RetryingDelay enters the picture and why I don't see delays and derefs within the caches provided by core.cache

Janet A. Carr16:01:45

According to the comments RetryingDelay prevents your cache from caching an exception instead opting to retry the function. So it seems the API wraps your function in the RetryingDelay, which is what this private function here does by calling d-lay. From what I understand in the core.memoize API, you should be able to reify the CacheProtocol and pass it to memoizer to create your memoized cacher.

(defn- through*
  "The basic hit/miss logic for the cache system based on `core.cache/through`.
  Clojure delays are used to hold the cache value."
  [cache f args item]
  (clojure.core.cache/through
   (fn [f _] (d-lay #(f args))) ;; RetryingDelay
   #(clojure.core/apply f %)
   cache
   item))

Janet A. Carr16:01:10

As for why it's not included with core.cache, I think the readme explains the motivation:

Caches are generally immutable and should be used in conjunction with Clojure's state management, such as atom. SoftCache is the exception here, built on top of mutable Java collections, but it can be treated as an immutable cache as well.
RetryingDelay are stateful.

Derek16:01:56

I think my issue is that RetryingDelay is not writeable to the backing store I'm using

Derek16:01:07

Thank you for looking into this for me

Janet A. Carr16:01:49

np; You shouldn't be writing RetryingDelay per se, it should be ephemeral. The private functions in core.memoize will wrap whatever function is cached in your memoizer in the RetryingDelay before dispatching on CacheProtocol type you defined when the memoizer atom is updated. So you should be able to just do something like (memoizer expensive-function MyCustomCache) and then wrap that in a function like memo from core.memoizer

👀 1
Derek16:01:17

I will try!

👍 1