This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-05-19
Channels
- # announcements (1)
- # asami (75)
- # beginners (16)
- # calva (14)
- # cider (4)
- # clj-kondo (11)
- # cljs-dev (3)
- # clojure (110)
- # clojure-australia (1)
- # clojure-china (1)
- # clojure-europe (38)
- # clojure-hk (1)
- # clojure-indonesia (1)
- # clojure-japan (1)
- # clojure-korea (1)
- # clojure-my (1)
- # clojure-nl (1)
- # clojure-sg (1)
- # clojure-spec (1)
- # clojure-taiwan (1)
- # clojure-uk (2)
- # clojurescript (34)
- # conjure (1)
- # data-science (9)
- # datahike (7)
- # datalevin (1)
- # datascript (1)
- # datomic (5)
- # etaoin (1)
- # fulcro (23)
- # graalvm (50)
- # helix (4)
- # hyperfiddle (8)
- # introduce-yourself (1)
- # jobs (3)
- # kaocha (10)
- # malli (8)
- # mid-cities-meetup (1)
- # minecraft (1)
- # off-topic (13)
- # pathom (14)
- # polylith (38)
- # reitit (1)
- # releases (1)
- # sci (65)
- # shadow-cljs (28)
- # specter (12)
- # tools-deps (8)
- # vim (1)
- # vscode (11)
- # xtdb (31)
When using the or
part in map destructuring, one issue I am also facing is,
{:keys [a] :or {a 3}} {:a nil}
When a
is nil
, it won’t get the default value 3.
How do you bypass this issue?
Basically what I want to achieve is a guarantee that all vars have a default value. Users might accidentally pass in {:a nil}
. This mostly happens when the user also receive a
from upstream invocations.(merge-with (fn [a b] (if (some? b) b a)) {:a 1} {:a nil})
;; => {:a 1}
it doesn't work with destructuring, though 😞
typically I just punt on this and say the caller shouldn't send the value if it's nil
while the or
part has its value; but a or-some
has its place too. (but unluckily there isn’t)
for sure! it's worth a feature request on http://ask.clojure.org
What about just using an or
in a let
binding instead?
(fn [m] (let [a (or (:a m) 3)]...))
I've done that as well, but if you have more than a few keys to do this with it pays to use something more general
or-some could be a nice addition to destructuring, but I just want to point out I'm pretty sure the current behavior is on purpose. Take for example:
(get {:a nil} :a 10)
;> nil
(get {} :a 10)
;> 10
I believe it's because conceptually this allows you to model two different things, which normally with static structs or classes you can't do.
Basically you can distinguish between isn't defined and is defined as nil.
It can be the difference between say, we never collected this piece of info from the customer, to we asked the customer and they didn't fill in this optional field.Generally the way I use it is that if you don't put the key, I default, but if you put the key as nil I throw a validation error, because that's most likely a bug that you specified the option but it was nil
Is there a way to have :as-alias
not cause a circular reference?
like I only want to require a namespace for its alias, definitely not for access to its vars.
(I haven't really confirmed this is an issue with compilation so there is a chance it works just not in cursive)
/tmp/circular on :cloud: (us-east-1) on :cloud:
❯ echo '{:paths ["."]}' > deps.edn
/tmp/circular via :coffee: v11.0.11 on :cloud: (us-east-1) on :cloud:
❯ echo '(ns bar (:require [foo :as-alias f]))' > bar.clj
/tmp/circular via :coffee: v11.0.11 on :cloud: (us-east-1) on :cloud:
❯ echo '(ns foo (:require [bar :as-alias b]))' > foo.clj
/tmp/circular via :coffee: v11.0.11 on :cloud: (us-east-1) on :cloud:
❯ clj
Clojure 1.11.1
user=> (require 'foo)
nil
user=> (in-ns 'foo)
#object[clojure.lang.Namespace 0x4ed38226 "foo"]
foo=> ::b/b
:bar/b
Shouldn't be a load cycle. What is the issue?
@U3JH98J4R Is Cursive using tools.namespace
? That was recently updated to treat :as-alias
as non-loading wasn't it?
This is https://github.com/cursive-ide/cursive/issues/2690 which I’m planning to fix in the next build.
According to the docs, print-dup, when true, means that objects will be printed in a way that preserves their type when read in later
Is the following not strange then?
(binding [*print-dup* true]
(prn (java.sql.Timestamp. 1)))
=> #inst "1970-01-01T00:00:00.001000000-00:00"
Why does the default behaviour for date types subvert print-dup?
When at the REPL, seeing things like dates printed with their type info is very useful: whilst conceptually I have a 'point in time' here, my code will be expecting a particular API (there is no common inst api, as there is for e.g. numbers). This contrasts with printing data to convey out of process ofc, where a more abstract representation will generally be preferable.
btw if anyone reading this has no idea what I'm talking about, see:
(binding [*print-dup* true]
(prn {:a 1 :b 2}))
=> #=(clojure.lang.PersistentArrayMap/create {:a 1, :b 2})
🤷 well, it seems like a mistake to me. Added a comment to https://clojure.atlassian.net/browse/CLJ-2224 so hopefully we avoid this with java.time.Instant
asked a question: https://ask.clojure.org/index.php/11898/printing-and-reading-date-types
hello, I'm using the cognitect aws api (https://github.com/cognitect-labs/aws-api), but when I use commands to list data (like :ListBuckets
or :ListObjects
on s3
) I always get an empty map as the response, I notice by looking at the meta that the responses are correct (I can see a XML string with all the correct data) but the response clojure map comes blank, how can I get the response as Clojure data?
this is what I'm running
(def s3 (aws/client {:api :s3
:region "sa-east-1"}))
(aws/invoke s3
{:op :ListBuckets})
not sure about the data.xml
, is this something that I need to have on my cp?using the latest from https://github.com/cognitect-labs/aws-api/blob/master/latest-releases.edn
in specific:
com.cognitect.aws/api {:mvn/version "0.8.539"}
com.cognitect.aws/endpoints {:mvn/version "1.1.12.206"}
com.cognitect.aws/s3 {:mvn/version "822.2.1109.0"}
org.clojure/data.xml 0.2.0-alpha6
coming from com.cognitect.aws/api 0.8.539
com.cognitect.aws/api 0.8.539
. org.clojure/data.json 2.4.0
X org.clojure/tools.logging 1.2.1 :superseded
. com.cognitect/http-client 1.0.110
. org.clojure/core.async 1.5.644
. org.eclipse.jetty/jetty-client 9.4.44.v20210927
. org.eclipse.jetty/jetty-http 9.4.44.v20210927
. org.eclipse.jetty/jetty-io 9.4.44.v20210927
. org.eclipse.jetty/jetty-util 9.4.44.v20210927
. org.eclipse.jetty/jetty-http 9.4.44.v20210927
. org.eclipse.jetty/jetty-util 9.4.44.v20210927
. org.eclipse.jetty/jetty-io 9.4.44.v20210927
. org.eclipse.jetty/jetty-util 9.4.44.v20210927
. org.clojure/data.xml 0.2.0-alpha6
X org.clojure/data.codec 0.1.0 :superseded
. org.clojure/core.async 1.5.644
. org.clojure/tools.analyzer.jvm 1.2.1
. org.clojure/tools.analyzer 1.1.0
. org.clojure/core.memoize 1.0.253
. org.clojure/core.cache 1.0.225
. org.clojure/data.priority-map 1.1.0
X org.ow2.asm/asm 5.2 :superseded
. org.clojure/tools.reader 1.3.6
hi @U066U8JQJ, sorry for the delay. can you share the meta on the response?
no worries, sure, the response looks like this:
{:headers
{"server" "AmazonS3",
"content-type" "application/xml",
"x-amz-bucket-region" "sa-east-1",
"transfer-encoding" "chunked",
"x-amz-request-id" "C5DWX2XACRK2803D",
"date" "Thu, 19 May 2022 13:01:53 GMT",
"x-amz-id-2"
"k/PwQWs+8VP4WcPbh6CB1B5599HokfnADoosgBam2b0hbgmA+o9vQT+PYF8C3vK0XUa8avvx6Q0="},
:status 200,
:body
#object[java.io.BufferedInputStream 0x5a8a8e5f "java.io.BufferedInputStream@5a8a8e5f"]}
I did slurp
the body, which contains valid XML:
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<ListBucketResult xmlns=\" \"><Name>pdf-extract-results</Name><Prefix></Prefix><KeyCount>10</KeyCount><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>2020-12/375603_OLGARIALIM...
also, when I use the command :PutObject
, it works as expected, and get data in the result (an :ETag
)
:GetBucketLocation
works fine, :HeadObject
is another one I also have correct results for
seems something with the listing ops that get me empty results
ListBuckets
, ListObjects
and ListObjectsV2
are the ones I had problems so far
Why lists created using quotation contains meta data?
Clojure 1.11.1
user=> (meta '(1 2 3))
{:line 1, :column 8}
user=> (meta '())
nil
The reader attaches location metadata to lists
isn't it a little bit inconsistent? no meta for empty list. I know it is a special class but still strange to see
the location metadata is used to do line number recording for compiled code and it needs to track function forms most importantly (and empty lists aren't)
so, not trying to be consistent
thanks for explanation!
Most fun bug of the week (artist's recreation) The code works perfectly except it wasn't filtering out the results we expected it to
(defn get-stuff [{:keys [limit offset filter]}]
(let [filter-pred (if filter
(fn [thing] (check thing))
(constantly true))
stuff (fetch-stuff)]
(->> stuff
(filter filter-pred)
(drop offset)
(take limit))))
:-) https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#shadowed-var
key
val
and type
specifically have all bitten me multiple times. It’s a little annoying, but I’ve found it easier to just consistently single-letter those.
Core routinely shadows things, including key
and val
. E.g. (source assoc)
.
Other names occasionally being shadowed, after a very superficial glance: name
, test
, cat
, next
. And I'm at just 10% of the core.clj
file.
There’s no reason to treat core as canon. I just happened to know offhand that key
and val
are very often abbreviated in there.
scoping is a thing, shadow away
I know that’s the official line, but then you have the above “fun bug of the week” which I assume consumed more than an hour of time.
there are only so many good words, what are you going to do?
shadowing key
had bitten me many times. I have a new personal rule to never use it as a local name or as a keyword.
FWIW, I'm pretty sure that for me thinking about alternative names has consumed significantly more time than dealing with errors induced by shadowing. :) And after all, nothing prevents you from accidentally shadowing your own name.
Sometimes it's appropriate, but not always. E.g the name can be a part of some API. Renaming that in code also requires effort, a constant one. Whereas I have to deal with shadowing issues once a year at most, and spend not more than half an hour on them.
It's not about the number of characters at all. We might simply have different preferences. I love short names, but the preferred length is usually a function of the size of the scope.
I'm talking about names in general.
If you receive {:filter ...}
from somewhere, you might use {f :filter ...}
but it has its own cost. And for me, more often than not that cost is not worth it - so I tend to prefer {:keys [filter ...]}
.
seems like a place where editors could provide context
function params in a slightly different color might have made that obvious
I'm with you on using short forms and avoiding shadowing. I find that it causes more trouble by tripping someone up than it solves by giving you some better names. I tend to use it only very rarely where a namespace is defining some similar function for operating on specific types of data (e.g., a map
function that operates just like core/map
but on some specific datastructure. malli.util
is a good example of this providing some functions for working with malli schemas).
the best reason to shadow vars is that you get to call them shadow vars which just sounds cool 😎
> i shadow certain names routinely To clarify, I do too. I initially enabled the shadowed-var linter for myself, but could not get used to it. It's configurable though for the vars you want.
The most fun variant of this bug is the one where you're in the repl, observe the behavior, turn on CIDER's breakpoint debugger, and the problem vanishes. Turns out when cider compiles your code for debugging it will make symbols in function position ignore shadowing bindings.
made quite a few heisenbugs for me.
I guess you could shadow and append a character like *
to represent the shadow (other characters may fit better)
I guess pound characters are allowed outside of syntax quote as well:
(let [inc# 10])
They are, but are reserved
and where is that documented? https://clojure.org/reference/reader
Actually I'm thinking of :
But # is not listed as a valid symbol char
I've been messing with a development workflow where I'm developing a Clojure program on a remote machine, through a local repl, using a java ssh library to connect to the remote machine and manage the (long running) clojure process there and also set up an ssh tunnel. I'm happy with this workflow when things work but I haven't figured out a great way to deal with unreliability, mainly my local networking going down and sometimes the remote clojure repl not running, and a lot of other little failure modes. Is there anything like a component library that tries to be smart about restarting unreliable components automatically? is the go to approach just have each component keep attempting to reconnect when necessary, and then use backoff/retry everywhere in the dependent components?