Fork me on GitHub
#clojure
<
2024-01-19
>
mpenet07:01:23

Interesting take from technomancy about [] vs () in ns imports : https://gist.github.com/technomancy/1e29d5a61ef8a61252257e8842ff5acc#-vs--for-import I couldn't agree more personally. I know it was discussed recently here and that [] was deemed more common or even prefered but I think Phil got some very good argument here.

💯 2
mpenet07:01:54

I don't agree with everything he mentions on that gist tho 🙂

1
octahedrion07:01:32

his point about when-vs-if is something I've been saying for years, everyone does it and it drives me mad

mpenet07:01:03

imho about if: it just reads better to have when and if. But it's highly subjective and depends on what you were used to in other languages I guess

octahedrion08:01:31

it's objective that when implies do when should have been called doif

p-himik09:01:35

> Clojure indentation treats lists differently from vectors Clojure doesn't have any indentation, tools do. And tools approach it differently. They are free to implement indentation differently for vectors in the :import form. E.g. Cursive does let you configure different indentation for different forms, but I think it currently only works for list forms and is based on what the first item of a list is. > I know it was discussed recently here and that [] was deemed more common or even prefered Could you please point me to that discussion? I'm a bit surprised by both of the sentiments so would be curious to read more.

3
Alex Miller (Clojure team)13:01:11

I asked Rich about the [] vs () once and he thought this was a silly argument and we should just use [] for all of these cases.

😂 3
❤️ 3
Alex Miller (Clojure team)13:01:25

My own 2 cents is that Clojure broke from Lisp in primarily using () only to mean invocation (there are a few exceptions in Clojure) and generally using [] for grouping, and require and import are both grouping not invocation

4
mpenet13:01:12

you mean import 🙂

mpenet13:01:26

I still prefer [] for require, I think also phil only meant to use () for imports. But I guess it's one of those things that will fall in the same folder as tab vs space

reefersleep14:01:14

I'm in a deep groove of using when for single-branch control flow, and I really like it. But I can't tell if it's just because of familiarity that I feel like the pure/effectful distinction wouldn't help me much. I feel like there's loads and loads of single-branch points in any code base, and every when lightens the mental load of reading the code a little bit, and that all adds up to a lot. The other distinction wouldn't occur quite as often. And I can't know if a non-core function call in an if is pure or not, anyways, so it's not like it's a clear distinction between pure if and unpure when.

4
mpenet14:01:24

ok since we're drifting, sorted requires is the one and true way 😁 Just for consistency's sake.

mpenet14:01:48

especially now that it can be automated via lsp (on save)

cjohansen15:01:58

I’ve automated that in Emacs for 10 years 😅

cjohansen15:01:08

But yes, agree, sorted requires or GTFO!

cjohansen15:01:32

I also agree with @U0AQ3HP9U’s point on single case when - it lightens the load

wevrem16:01:01

When he says “This is a lisp convention…” does “this” refer to using single-branch if’s or not using them? which one is the old convention? I’m having antecedent confusion.

daveliepmann16:01:52

I read it as "single-branch if is a lisp convention". Now, I've never been a common lisper, but this is weird because at least half the CL sources I find say that when or unless are preferred over single-branch if. I guess this is an old debate?

reefersleep12:01:15

This makes me realize just how little overlap there is in my Clojure career with Common Lisp (or other non-Clojurey lisps). I know nothing about what's going on with those languages and their communities. Keep hearing Racket's great, but haven't found reason to explore.

jdkealy16:01:19

how would i disable the "migratus" logging in my emacs REPL. I like to run tests in the REPL, and the up/down migrations are so noisy. I tried logback, but i think maybe I don't understand logback <logger name="migratus" level="off" /> https://github.com/yogthos/migratus/blob/2239659923881db5ebafa34cd4a58a192c581101/src/migratus/core.clj#L108 (log/info "Running up for" (pr-str (vec (map proto/id migrations))))

p-himik16:01:15

The logger name is probably migratus.core.

jdkealy16:01:00

thanks... trying that

p-himik16:01:51

Ah, they're probably hierarchical - both migratus.core and migratus worked for me just fine. Are you sure that logback config is used?

p-himik16:01:48

Curious - how do you use "down" migrations for your tests?

jdkealy16:01:49

how do i know

jdkealy16:01:57

i have a fixture

(defn with-db
  [f]
  (start)
  (reset-db)
  (seed-db)
  (f))

p-himik16:01:01

Not sure if there's a way to know if programmatically, but it should be used if it's named logback.xml and is somewhere at the top level on your classpath (i.e. (io/resource "logback.xml") returns something in a test).

p-himik16:01:46

I see that that fixture creates a DB, but where does it run "down" migrations? And why would it do that?

jdkealy16:01:49

this is all the logback references i have in the code base

p-himik16:01:19

Check which logback.xml is on the classpath when the tests are being run.

jdkealy16:01:52

just like (println (io/resource "logback.xml")) ?

p-himik16:01:11

Yeah, should work.

jdkealy16:01:14

i don't have a dev/resources dir

p-himik16:01:44

You do have it. Otherwise, that call to io/resource would've returned nil.

p-himik16:01:10

It's just that that change that you made with level="off" wasn't done to that file.

jdkealy16:01:12

temporariy blind sorry

jdkealy16:01:54

restarting docker... excited

p-himik16:01:56

Seems like you have multiple config files and the classpath can sometimes have more than one of them. You should try to avoid that situation.

p-himik16:01:04

But still - why the down migrations? Why not just create a DB for tests from scratch and run each test in its own transaction?

p-himik16:01:19

Personally, I never use down migrations. In fact, I have them outright disabled in Migratus. :) If I ever need to work on some different branch with incompatible DB changes, I just clone the DB. And if something ends up being broken in production after a migration, I create a new migration that fixes it in a way that's specific to that failure. Otherwise, it's waaaay to easy to lose data with a down migration.

jdkealy16:01:40

yeah... fair point

jdkealy16:01:54

i am terrified of the idea of accidentally being connected to prod and running tests from the rel

jdkealy16:01:52

i prefer only using datomic with clojure projects 🙂

jdkealy16:01:26

for which... also no down migrations, you just give it your schema and it detects changes

jdkealy16:01:40

logs are GONE!

👍 1
jdkealy16:01:50

now i can actually find my debug statements

p-himik16:01:45

On that note - consider stuff like tap> and Portal. :)

Kelvin17:01:02

So I’m running into an issue with tools.build. I’m using tools.build to build a JAR for a library that uses tools.build itself as a dep. This may have something to do with this issue I’m having:

Skipping coordinate: {:git/tag v0.9.6, :git/sha 8e78bccc35116f6b6fc0bf0c125dba8b8db8da6b, :git/url , :deps/manifest :deps, :deps/root /Users/[redacted]/.gitlibs/libs/io.github.clojure/tools.build/8e78bccc35116f6b6fc0bf0c125dba8b8db8da6b, :parents #{[]}, :paths [/Users/[redacted]/.gitlibs/libs/io.github.clojure/tools.build/8e78bccc35116f6b6fc0bf0c125dba8b8db8da6b/src/main/clojure /Users/[redacted]/.gitlibs/libs/io.github.clojure/tools.build/8e78bccc35116f6b6fc0bf0c125dba8b8db8da6b/src/main/resources]}
As a result anything that uses this lib as a dep doesn’t include tools.build as a transitive dep, and the thing falls apart.

Alex Miller (Clojure team)17:01:25

jars include a pom manifest of the deps they depend on. pom files have no mechanism for declaring a dependency on a git dep (this is a deps.edn feature), so there is no way for a Maven jar artifact to state a dependency on a git dep

Alex Miller (Clojure team)17:01:31

tools.build is also published as a Maven artifact, so in this case, you could replace that transitive dep in the dependency tree using :override-deps in an alias

Alex Miller (Clojure team)17:01:33

the equivalent artifact here would be io.github.clojure/tools.build {:mvn/version "0.9.6"}

Kelvin18:01:56

Thanks for the reply! I actually thought that using a Github instead of a Clojars/Maven dep was the reason at first, but then I thought “wouldn’t we’ve noticed it first with other libraries”?

Kelvin18:01:11

When googling I did see that this problem occurred when one uses purely local deps, but I thought “GH deps aren’t local so they should work, right?”

Alex Miller (Clojure team)18:01:30

generally, Maven artifacts should (can only) depend on other Maven artifacts

Alex Miller (Clojure team)17:01:17

A public service announcement regarding static field interop... This is something we've run into while working on 1.12. The syntax for getting the value of a static field via interop is Classname/field - this has always been the only published syntax (other than the . special form). It seems that in the wild it is not uncommon to also see this parenthesized syntax: (Classname/field) but this has never been correct. It does "work" in returning the value of the field, but this is merely an artifact of the . rewriting in the macroexpander and was never intended. For correct expression substitution, that code should take the value of the field, and then invoke it. We are still deciding what to do about this (it is in the way of other things we are doing), but regardless I'll issue a plea to Clojure developers here to always use Classname/field without parens to get a static field value!

👍 15
3
dpsutton17:01:12

This sounds like something grasp or clj-kondo could identify. A script that identified these usages in your own source or transitive libs would be so helpful

4
Noah Bogart17:01:21

If you have a working branch, I can try to find usages with core-regression

Alex Miller (Clojure team)18:01:00

I should have mentioned this, but already asked @U04V15CAJ to include this - see https://github.com/clj-kondo/clj-kondo/issues/2260

dpsutton18:01:51

outstanding. Also really nice to connect what goodies we can get when we do “the right thing”™ instead of something that just happens to work.

Alex Miller (Clojure team)18:01:23

I can see just from searching that there are many occurrences of this in the world, so no need to test anything, it's definitely a wide-spread occurrence we have to take into account

👍 1
Alex Miller (Clojure team)18:01:43

my plea is to stop making more of it :)

dpsutton18:01:00

I’ve never known whether to do clojure.lang.PersistentQueue/EMPTY or (clojure.lang.PersistentQueue/EMPTY) so nice to know there’s a right answer and why it’s the correct answer

Alex Miller (Clojure team)18:01:48

that is one I see a lot of examples of

dpsutton18:01:29

would that interest you in a var in clojure.core exposing that? (i love the persistent queue)

Alex Miller (Clojure team)18:01:04

I noticed that the Clojure Essential Reference book has a bad example of (Math/-PI) in it /cc @U054W022G - should be just Math/PI . The - there particularly highlights something - because static fields and static methods have distinct syntax C/xyz will never overlap with (C/xyz) and there is no need for the - distinguisher, so C/-field has also never been a valid syntax (although (C/-field) frustratingly accidentally works).

Alex Miller (Clojure team)18:01:25

that is far rarer in the wild, but this particular example is doubly bad in this way

Alex Miller (Clojure team)18:01:47

@U11BV7MTK we have a ticket for it somewhere

👍 1
Noah Bogart18:01:44

Is this an instance of "undefined behavior" that now has a defined behavior? or is this "defined behavior" with new changed semantics?

Alex Miller (Clojure team)18:01:48

it's "undefined behavior", tbd what it will be

👍 1
Noah Bogart18:01:33

my apologies, i meant the (Classname/field) syntax

Alex Miller (Clojure team)18:01:17

that's how I understood you

👍 1
Noah Bogart18:01:42

How were you searching to find the offending code? I could open some PRs to help ease the transition for folks

borkdude18:01:12

I grep.app-ed for (System/out) , there were quite a few of those

Alex Miller (Clojure team)19:01:22

just grepped for common static fields in the jdk - System/out, System/err, File/separatorChar, File/pathSeparatorChar, Long/MAX_VALUE, Integer/TYPE, etc

👍 1
Alex Miller (Clojure team)19:01:49

everything I tried had examples :(

😭 3
borkdude19:01:20

Why would the instance field access still be allowed using wrapping parens btw?

Alex Miller (Clojure team)19:01:37

if the static field held something invokable, you could invoke it

Alex Miller (Clojure team)19:01:26

(and note in the future, more things may be invokable then what is invokable now)

borkdude19:01:31

No I mean, why would there be a difference between static vs instance for accessing fields?

Alex Miller (Clojure team)19:01:54

instance fields always have an instance, so are always parens

Alex Miller (Clojure team)19:01:11

not sure if that answered your question

borkdude19:01:35

right, I guess I misremembered both supporting (.-foo x) and (.foo x) for fields

Alex Miller (Clojure team)19:01:15

those are both valid for instance fields

borkdude19:01:03

that's a pity ;)

borkdude19:01:38

I remember supporting that exact use case in SCI: https://github.com/babashka/sci/issues/714

borkdude19:01:27

and here is the one that should no longer work in clojure 1.12: https://github.com/babashka/sci/issues/257

🥲 2
😭 1
hifumi12322:01:49

I was totally unaware people tried getting static fields with function calls like that. Thankfully my own code is safe, it seems but all bets are off for the majority of the Clojure ecosystem. Maybe it's time for Clojure 2.0 ? 😁

👎 1
borkdude22:01:31

if the static field held something invokable, you could invoke itwhat if the instance field held something invokable, why would (.foo x) not invoke it vs (.-foo x) get the invokable? (currently both just get the field value)

borkdude22:01:58

(note that ClojureScript does make a distinction between the two)

Alex Miller (Clojure team)23:01:18

You’re comparing different things here (.field instance) or (.-field instance) is field access (as defined on the interop page)

Alex Miller (Clojure team)23:01:58

It should return you the value of the field, just as AClass/field should return you the field value

borkdude23:01:24

yeah, JS doesn't distuingish between fields and functions, they're just stuff in an object

Alex Miller (Clojure team)23:01:56

Yes, I’m sure the crossover from other langs is part of the mistaken expectation here