off-topic

https://github.com/clojurians/community-development/blob/master/Code-of-Conduct.md Clojurians Slack Community Code of Conduct. Searchable message archives are at https://clojurians-log.clojureverse.org/
p-himik 2020-09-08T08:18:22.447300Z

A very simple but long running loop-based function manages to make all 8 CPU cores busy. How come? Is it GC or something else? I don't do there anything but churning numbers and changing a single transient vector.

mauricio.szabo 2020-09-13T01:21:56.254600Z

@p-himik check for reflection warnings. Sometimes, reflection can do bizarre things...

p-himik 2020-09-13T07:37:51.256300Z

Thanks. Yeah, maybe it was reflection. I've enabled the warnings later on but only after some drastic modifications that by themselves resulted in a nicer memory usage. Initially, I was using a vector of vectors in a very tight loop that gets and sets nested double values). The first run would finish just fine, the second would crash with OOM. So another candidate is boxing, perhaps.

p-himik 2020-09-08T08:22:20.447900Z

And I'm not exactly sure, but I think the first time I ran it it used just 2 cores. And the second time it started using all 8 cores and it takes it quite a bit more time to complete. Same input, no randomness anywhere.

p-himik 2020-09-08T08:24:07.448300Z

What the hell. It failed with OutOfMemoryError, but the first time it worked just fine.

2020-09-08T08:51:16.456500Z

@ahmed1hsn Picking up your question here as it's somewhat of a thread stealer. I scanned the slide deck on zio. It seems to be about taking the type system in scala and making it (I don't understand how) more about algebraic types. Which, I infer from the slides, are about making functions which behave according to algebraic properties (association, etc..) That's a massive shift. I'm not sure it would still be clojure at the end.

đź‘Ť 1
2020-09-08T11:48:22.456800Z

that's a strong indicator that it was gc using the cores

2020-09-08T11:48:57.457Z

perhaps it is leaking resources - creating data that remains accessible via some scope outside the loop, or creating something that cannot be collected?

2020-09-08T11:52:06.459600Z

as a matter of opinion / design, I personally think the biggest problem with scala is trying to simultaneously work with the JVM (very weak type system, generics as a compile time fiction only), and use the best features of modern type safety (very strong type system, implicit and inferred types) this is exacerbated by a pattern of breaking code compatibility between compiler versions

2020-09-08T11:53:23.460600Z

the jvm type system, as much as it has one, is very compatible with lisp + interfaces, which is what clojure uses, and much of clojure's elegance and simplicity comes from embracing this

2020-09-08T11:54:22.461700Z

simultaneously trying to be compatible for interop with the jvm, and enforcing typing concepts the vm isn't capable of representing directly, is IMHO inevitably going to make things worse not better

p-himik 2020-09-08T11:54:28.461800Z

I really doubt that - the function is pure and I immediately discard its result.

2020-09-08T11:54:48.462Z

and it isn't eg. creating new lambdas via eval?

2020-09-08T11:55:01.462200Z

or otherwise creating new classes?

mpenet 2020-09-08T11:58:37.463400Z

type checking is most cases/can be a compile time feature (outside of optimisations & co coming from type annotation), you don't really need a cooperating vm

2020-09-08T11:59:09.464200Z

but that's where scala gets extremely messy

mpenet 2020-09-08T11:59:11.464300Z

but sure, it's simple to do less and stay close to the vm if/when possible

2020-09-08T11:59:23.464700Z

sure, it could be done right, I don't see real world evidence of it happening

mpenet 2020-09-08T11:59:51.465100Z

typed racket & gleam come to mind

mpenet 2020-09-08T11:59:58.465500Z

hell, even rust

2020-09-08T12:00:05.465700Z

equivalent problem: make a type safe language with inference, that allows inline machine specific assembly

2020-09-08T12:00:18.466Z

and yeah, rust might count for my example :D

mpenet 2020-09-08T12:00:46.466600Z

It's hard, sure. And difficult to do it right

2020-09-08T12:01:03.467Z

this reminds me, I do want to learn rust

2020-09-08T12:01:12.467400Z

though I might just learn zig instead

mpenet 2020-09-08T12:02:08.467800Z

zig is an odd thing. I'd prefer rust, but personally I have no use case to learn either

2020-09-08T12:02:55.468400Z

zig is what people wish (and often delusionally pretend) C would be

mpenet 2020-09-08T12:03:31.469300Z

I'd only use rust to work with embedded devices & co

2020-09-08T12:03:34.469400Z

it's simple in the way a lisp is (maximal utility from minimal features), close to "the metal"

mpenet 2020-09-08T12:03:54.470300Z

I know, I just find it odd for a new lang in 2020 🙂

2020-09-08T12:03:57.470400Z

right, I'd use rust or zig for DSP, where using an allocator could mean your RT constraints fail

2020-09-08T12:04:13.471Z

@mpenet that's everyone else's fault for not making that happen sooner IMHO

mpenet 2020-09-08T12:04:16.471100Z

I'd prefer to work in rust in these cases, but that's just me

mpenet 2020-09-08T12:04:50.472Z

but I really don't want to learn rust again

mpenet 2020-09-08T12:04:56.472300Z

and likely won't

mpenet 2020-09-08T12:06:06.473Z

(used it quite a bit in the 0.3.x days)

mpenet 2020-09-08T12:07:54.474400Z

I like simple things: I find fennel-lang for instance quite nifty, it has no bells & whistles, but is very pragmatic and fit the bill in some the use cases I encountered when clojure was not an option.

2020-09-08T12:08:38.475600Z

I attended the first fennel conf (it was four of us at a bar for a few hours), and hosted the second one (about 10 of us in a rented conference room)

3
mpenet 2020-09-08T12:08:45.475800Z

then, sure it's lua with (lisp) lipstick, so aging community & not as many options as the jvm, but it's very usable nonetheless

mpenet 2020-09-08T12:08:57.476Z

oh cool

2020-09-08T12:09:29.476600Z

I implemented the first version of quote / quasiquote / unquote also, but I don't think my grubby hand prints are on that code any more

2020-09-08T12:09:33.476800Z

it self hosts now!

mpenet 2020-09-08T12:09:43.477Z

yes

mpenet 2020-09-08T12:09:48.477200Z

since 0.5.x

mpenet 2020-09-08T12:10:05.477700Z

no more gnarly lua to deal with (almost)

2020-09-08T12:10:20.478100Z

sorry, I'm really not used to other people knowing anything about fennel and its features, I guess I'll have to get used to it :D

mpenet 2020-09-08T12:10:28.478400Z

🙂

2020-09-08T12:10:42.478900Z

I'm slowly migrating my awesome wm config to fennel

mpenet 2020-09-08T12:11:13.479900Z

you might be able to automate that, if I recall technomancy used a script to port part of lua's fennel code with it

2020-09-08T12:11:16.480Z

and it looks like fennel will get checked in as a part of the neovim repo soon (to be used in the tree-sitter impl)

2020-09-08T12:11:26.480200Z

right, antifennel

mpenet 2020-09-08T12:11:29.480500Z

yes

2020-09-08T12:11:56.481100Z

antifennel takes lua and makes equivalent fennel code, I should be able to migrate all my lua code, and just leave a fennel bootstrap stub in its place

2020-09-08T12:12:02.481300Z

seems doable

mpenet 2020-09-08T12:12:02.481500Z

yup

mpenet 2020-09-08T12:12:15.481700Z

I did the same a long time ago

mpenet 2020-09-08T12:12:20.481900Z

but I am no longer using awesome

mpenet 2020-09-08T12:12:32.482200Z

I did it manually tho

2020-09-08T12:12:58.482600Z

did you find a better WM?

mpenet 2020-09-08T12:14:09.483900Z

emacs 🙂 I basically just use a browser and emacs and I rely on boring gnome, I stay full screen with one or the other all the time. My workflow with awesome was quite simple/similar.

mpenet 2020-09-08T12:14:18.484200Z

terminals in emacs+libvterm

2020-09-08T12:15:30.484800Z

aha, yeah, awesome + tabs in neovim is my version, but on multiple screens when possible

mpenet 2020-09-08T12:18:59.485700Z

also fennel: the ability to compile with bundled lua interpreter resulting in very small files is quite cool

2020-09-08T12:21:33.486500Z

yeah, I had some wacky ideas of how to do that, but luckily Phil found a simpler and more reliable way

2020-09-08T12:22:08.487300Z

there's been talk about bundling byte code instead of source for the fennel code bundled as well, making it slightly more brittle or harder to debug(?) but smaller

2020-09-08T12:22:35.487600Z

it's basically a free feature, since it's what lua was designed for

2020-09-08T12:23:03.488500Z

I've long threatened to bundle fennel into a general purpose kafka tool, maybe I'll find time for it during my current sabbatical

mpenet 2020-09-08T12:23:06.488700Z

it's super easy to ship a single binary with everything including the ability to make it repl'able

mpenet 2020-09-08T12:23:13.488900Z

quite cool, really

2020-09-08T12:23:29.489200Z

and there's even a lib for nrepl :D

mpenet 2020-09-08T12:23:36.489500Z

yeah

2020-09-08T12:23:52.490100Z

(that is, to make it an nrepl server, usable from those few client impls that don't take clojure on the server for granted...)

mpenet 2020-09-08T12:23:54.490300Z

as I said, no need to mess with rust, I'd be busy enough with other toys

mpenet 2020-09-08T12:23:57.490500Z

🙂

2020-09-08T12:24:53.491700Z

I'd go all in on fennel and skip my recent arm64 exploration and planned zig exploration, except I strongly suspect that I want to do things in DSP that lua can't quite hack directly

mpenet 2020-09-08T12:25:29.492300Z

when you are that close to the metal there are not many options sure

2020-09-08T12:25:49.492800Z

learning 64 bit arm assembly is extremely humbling, I thought I was so much more clever than I am

2020-09-08T12:26:38.493600Z

though I think I've fully internalized 2's complement and little endian as formats, which I guess is fun trivia though it's sad I even need to care

mpenet 2020-09-08T12:27:41.494300Z

yeah that sounds more involved that what I could afford with the little free time I have these days.

2020-09-08T12:29:31.496400Z

I had a somewhat embarrassing accident with hallucinogens (never again, I swear), which left me hospitalized for a week with no internet, no hardcover books, no privacy. Working out some basic architectural stuff like 2's complement encoding on paper with a pen (no pencils allowed) was actually a nice way to pass the time

2020-09-08T12:30:34.496800Z

better would have been not to land myself there in the first place of course

2020-09-08T12:32:51.497100Z

apologies if that's TMI

mpenet 2020-09-08T12:32:53.497300Z

kids+covid here

2020-09-08T12:33:26.498200Z

yeah, that's a lot of work

mpenet 2020-09-08T12:33:29.498300Z

I mean, we didn't get covid, just small kids@home

mpenet 2020-09-08T12:33:31.498500Z

🙂

2020-09-08T12:33:59.499100Z

what we need is a "clojure-junior" that you can teach kids so they can be your offshore for tedious parts of your projects

2020-09-08T12:34:16.499600Z

if their work passes the unit tests, just drop it in

mpenet 2020-09-08T12:34:51.499900Z

a bit too early for them, stuff like logo/scratch in time

2020-09-08T12:35:27.000600Z

I showed scratch to my girlfriend and her children, but it's definitely a "lead a horse to water" type situation

2020-09-08T12:35:55.001100Z

logo is just a lisp subset that is simple enough to not need parens any more

Ahmed Hassan 2020-09-08T12:41:34.002200Z

If you want to do statically typed functional programming on JVM, then Scala is great option.

2020-09-08T12:43:40.003800Z

I cross my fingers that Eta becomes usable (with full featured interop) - the way scala works with the vm is kind of messy

mpenet 2020-09-08T12:43:44.003900Z

scala pretty much support any style of programming 🙂

2020-09-08T12:44:06.004500Z

https://eta-lang.org/

mpenet 2020-09-08T12:44:06.004600Z

which is part of the problem (kidding, kind of)

Ahmed Hassan 2020-09-08T12:47:19.008500Z

Scala is trying to move away from Haskell's abstractions e.g. Cats, ScalaZ. With ZIO and zio-prelude they are trying to do FP in more native way to Scala idioms.

2020-09-08T12:47:54.009500Z

you can use your favorite idioms in your code, but libraries will force you to use the lib authors favorite idioms

mpenet 2020-09-08T12:48:14.009700Z

^

2020-09-08T12:49:07.010800Z

eg. a friend was doing a data graph based project, they knew about the pitfalls of implicits and avoided them, but they were cornered into implicits and all the problems they bring because they needed a graph lib that used them everywhere

2020-09-08T12:49:32.011200Z

as a random example (said friend refuses to use scala any more)

Ahmed Hassan 2020-09-08T13:05:35.013800Z

Statically typed language guys have argument that it helps in refactoring large code bases. How much true this statement is and how does this help with respect to Clojure for example?

borkdude 2020-09-08T13:06:36.014800Z

@ahmed1hsn I'm obviously biased but I find clj-kondo and rg/grep helps me refactoring quite well

2020-09-08T13:07:02.015500Z

That is an advantage with static languages. The Clojure solution tends to be using good system boundaries with well defined interfaces, but it's definitely an art not a science. I do miss how easy refactoring was in OCaml for example.

borkdude 2020-09-08T13:07:14.015900Z

Automated refactorings can also yield garbage code, because the amount of thinking is reduced

2020-09-08T13:08:14.016900Z

@borkdude but a good type system can guide a dev through a manual refactor - in OCaml if I change a module interface, just running :make in nvim takes me to the needed edits, until I don't get errors, then I know I'm done

2020-09-08T13:08:34.017400Z

there's no real way to have that in Clojure (though static tools and unit tests help a lot)

borkdude 2020-09-08T13:08:42.017700Z

that's true. there was a nice tweet about this from Stuart H.: https://twitter.com/stuarthalloway/status/1234261008560115712

2020-09-08T13:08:50.018Z

:D

2020-09-08T13:09:15.018400Z

I often enjoy the glib version: "tooling is a language smell"

2020-09-08T13:10:04.019200Z

that is, the kind of tools users of $LANG consider indispensable is a peek into the things the language itself is poorly suited to handle

borkdude 2020-09-08T13:10:15.019600Z

funny no-one mentioned spec so far ;)

2020-09-08T13:10:47.020300Z

I've seen bad refactors that got further than they should have because specs were defined and naiively trusted

2020-09-08T13:11:09.020900Z

oops, nothing actually checked or enforced said specs, so they were about as useful as comments declaring return / arg types

2020-09-08T13:12:25.022800Z

in a static lang, the type is a property of the code, in clojure a spec is not a property of the code or the data alone, it's a checkable assertion about the data seen by specific code in a specific run time context

đź’Ż 3
Ahmed Hassan 2020-09-08T13:12:26.022900Z

@noisesmith refactoring workflow in Scala is similar to OCaml

đź‘Ť 1
Ahmed Hassan 2020-09-08T13:14:43.024Z

How is the situation of core.typed or TypedClojure?

borkdude 2020-09-08T13:15:08.024400Z

Btw #lsp also has some nice refactorings nowadays

borkdude 2020-09-08T13:15:28.025Z

@ahmed1hsn I think core.typed is still pretty much a research topic?

2020-09-08T13:17:01.027Z

@ahmed1hsn I don't know those tools / variants but on the topic of architecture, even with a strongly typed language the types can't extend past a single VM without making a big brittle mess. Your individual app might be strongly typed but your microservice can't be. Eventually, at some level, once you have two computers running, you have the same typing guarantees as Clojure (that is, your data can be checked at runtime for validity but nothing can be known about it statically).

✔️ 1
2020-09-08T13:17:33.027500Z

The attempts I've seen to act like data between vms / processes is typed only make the problems worse

2020-09-08T13:18:22.028300Z

(the OCaml approach is cute: you can share typed data between processes, but it's an instant failure / abort if the two processes aren't running literally the same compiled binary)

borkdude 2020-09-08T13:19:12.028600Z

is that kinda like serialized objects in Java but worse?

2020-09-08T13:20:40.029900Z

better :D no side effecting constructors, and it bails out if a trivial assertion isn't successful

2020-09-08T13:21:03.030600Z

it allows what java gets by having multiple threads in one process, but without shared memory, which is kind of cool actually

2020-09-08T13:21:16.030800Z

and it's network transparent

2020-09-08T13:22:00.031800Z

but it's still "cute" rather than "awesome" - it's dealing with a fundamental problem that nothing handles perfectly (though I suspect erlang has found a better local optimum than most)

2020-09-08T13:22:33.032300Z

point being, once you leave the realm of "everything in one process", you get all of Clojure's problems anyway

✔️ 1
mpenet 2020-09-08T13:23:40.033800Z

erlang gets aways with it via good pattern matching, records, no nil, named tuples and semi decent static analysis. All in all it's a good combo

mpenet 2020-09-08T13:24:16.034600Z

message passing is first class too, so it's optimized for that, but that's not free

2020-09-08T13:24:18.034800Z

plus a good infrastructure for IPC with retries / monitoring

2020-09-08T13:24:41.035400Z

I haven't yet used it in anger though, I do intend to fix that

mpenet 2020-09-08T13:24:43.035500Z

generally working with erlang codebases is less stressful than clojure codebases imho

mpenet 2020-09-08T13:25:45.036300Z

when it comes to refactoring I mean.

Ahmed Hassan 2020-09-08T13:30:43.041100Z

Beyond that I haven't seen core.typed in production use.

borkdude 2020-09-08T13:34:10.041900Z

@ahmed1hsn Yes. I still think Schema is convenient, but it's also still only runtime only, like spec. Btw, I think clj-kondo could pick up on Schema's defn, but since there are now at least 3 or 4 libs (schema, spec, malli) doing their own thing, I don't know if this has any priority.

borkdude 2020-09-08T13:35:36.042400Z

(some work I'm doing related to spec: https://gist.github.com/borkdude/c0987707ed0a1de0ab3a4c27c3affb03#gistcomment-3444982)

borkdude 2020-09-08T13:35:57.042900Z

It would be great if the clojure community settled on one thing eventually

borkdude 2020-09-08T13:36:14.043300Z

right now it's a bit of a scattered ecosystem

borkdude 2020-09-08T13:36:42.043600Z

Honestly, Schema was pretty great and simple (in the sense of easy :P)

ikitommi 2020-09-08T13:37:37.044400Z

#malli wip with clj-kondo

đź‘Ź 1
🚀 1
borkdude 2020-09-08T13:41:45.045400Z

Some perceived flaw of schema was that their schemas were closed by default. But it's pretty easy to make them open: {:foo s/Str s/Any s/Any}?

mauricio.szabo 2020-09-13T01:32:37.255700Z

Also, you can use closed schemas as security measures, like "don't allow a non-admin user to change the status of a user in this REST path". Rails did decide that everything was open by default, then changed the approach (breaking lots of code in the process) because of lots of bugs and security issues on production code - even github suffered from that flaw, I believe

alexmiller 2020-09-14T04:09:13.258200Z

the approach is spec 2 is that "closing" is a property of the check, not of the spec

alexmiller 2020-09-14T04:09:36.258400Z

something you can enable during validation, conform, etc if needed

đź‘Ť 1
2020-09-08T14:07:22.048200Z

yeah, in practice I added s/Any s/Any to every hash-map in schema, and 98% of my schemas were for hash-maps

2020-09-08T14:09:00.049700Z

tangent: I wonder if an entropy detecting tool would be useful for catching mismatched components. My idea being if you have a "state" or "component" map tree with the same data repeated many times at many levels of branching, that could indicate an app that's growing faster than it's being designed

mpenet 2020-09-08T14:11:44.050300Z

the open-ness part could be another namespaced key, that would get validated even if not specified in the s/keys

mpenet 2020-09-08T14:12:00.050700Z

so s/Any doesn't work the same way (lack of global registry is the real issue)

mpenet 2020-09-08T14:12:19.051100Z

different approaches

cjsauer 2020-09-08T14:13:20.052400Z

Does this hold true when using something like Avro? I’ve never used it, but it appears to be “types on the wire”.

borkdude 2020-09-08T14:14:18.053300Z

you can just programmatically merge schemas though which makes it less of a problem

mpenet 2020-09-08T14:14:45.053900Z

yes, different approaches. one assumes an attribute is always the same thing, the other not

borkdude 2020-09-08T14:16:02.054700Z

malli has much of that flexibility too and possibly more, maybe it will be schema.next in terms of community impact

mpenet 2020-09-08T14:17:21.056100Z

I am not a fan of having both approaches for something that should aim to become a standard personally. I tend to prefer Spec style, but that's just me

2020-09-08T14:18:07.056300Z

but you can't use the same types in your application code

borkdude 2020-09-08T14:18:31.056700Z

what did you mean with "both approaches"?

2020-09-08T14:18:35.056800Z

and IMHO trying to combine the avro type with your program types makes things worse not better (based on the attempts I've seen)

mpenet 2020-09-08T14:20:43.057700Z

we're circling back to Scala's discussion 🙂 imho enabling many different styles to deal with something that should be a shared by the community at large is not great

borkdude 2020-09-08T14:21:29.058100Z

yes, I intented to ask which styles you meant

mpenet 2020-09-08T14:21:44.058400Z

global registry vs first class specs

borkdude 2020-09-08T14:22:23.058800Z

I think malli also has a global registry, local is optional

mpenet 2020-09-08T14:22:34.059Z

yeah that's what I mean

borkdude 2020-09-08T14:23:14.059700Z

I don't follow. This is the same as spec? You don't have to use a local registry, it's an edge case that is supported optionally

mpenet 2020-09-08T14:23:33.060100Z

the value of a (namespaced) key in a map will always validate the same way

mpenet 2020-09-08T14:23:37.060300Z

in spec

mpenet 2020-09-08T14:23:45.060600Z

that's not true with Schema/malli

mpenet 2020-09-08T14:24:00.061Z

it can be, but not necessarly, depends on the style used

borkdude 2020-09-08T14:24:10.061200Z

ah I see

borkdude 2020-09-08T14:25:08.061500Z

So @ikitommi, malli doesn't have something like s/def ?

borkdude 2020-09-08T14:26:43.062300Z

> Example to use a registered qualified keyword in your map. If you don't provide a schema to this key, it will look in the registry. I wonder how you register a qualified keyword associated with a schema globally

mpenet 2020-09-08T14:26:54.062500Z

I think it does since it has registries

mpenet 2020-09-08T14:27:16.062900Z

I guess you can define a single registry that you'd use everywhere (if you follow that rule)

borkdude 2020-09-08T14:29:29.063600Z

in that case, just use the global registry right

mpenet 2020-09-08T14:29:52.064600Z

it works only if you control all the code you work with.

mpenet 2020-09-08T14:30:06.065200Z

lib author A can define its own, or not

ikitommi 2020-09-08T14:30:30.066Z

malli is immutable by default but supports global mutable registries. Just not by default. But, it's pre-alpha, feedback welcome.

ikitommi 2020-09-08T14:31:03.066700Z

no fdefs yet, but will be, soon.

borkdude 2020-09-08T14:31:38.067300Z

@ikitommi So the feedback / question is: if lib A defines a malli spec for keyword :foo/bar, how can you enforce that library B will validate this as intented? (did I say that right @mpenet)?

mpenet 2020-09-08T14:33:25.070200Z

afaik you cannot enforce it. You have to know where to get the info from the registry of the lib, merge it with yours potentially and then do the same for every lib that has specs registered (if any)

mpenet 2020-09-08T14:33:59.071200Z

that's where imho having too many options (or styles) hurts

mpenet 2020-09-08T14:34:20.072100Z

but maybe I missed the latest developments

ikitommi 2020-09-08T14:34:33.073100Z

currently, the lib needs to have it's own registry (map) and you can compose that it with your app registry. Could poll if people want a global mutable thing.

borkdude 2020-09-08T14:35:12.074500Z

one could ask the question if this is a common thing: validating maps from other libs

cjsauer 2020-09-08T14:35:28.075100Z

Ah yea. It appears similar to the keyword conversion problem I find at the borders of my clj systems.

ikitommi 2020-09-08T14:35:53.076300Z

you can always force a immutable (and serializable) registry inside your app, for some parts where that matters

mpenet 2020-09-08T14:36:05.076600Z

take that in the context of a haskell like type system, is it useful to have the guarantee a Thing is always assumed to be the same ?

mpenet 2020-09-08T14:36:28.077300Z

imo yes. If you make the // between an attribute (nsed key) and a Type

mpenet 2020-09-08T14:36:48.078300Z

then outside of ns'ed keys it's the wild west

borkdude 2020-09-08T14:37:10.078900Z

@mpenet it's probably the other libs responsibility to create those maps, which can from then on be assumed to be true Things?

mpenet 2020-09-08T14:38:22.080100Z

Not necessarly

mpenet 2020-09-08T14:39:16.080900Z

Unless you like to create contructors for all your data 🙂 and guarantee than any producer will use these

mpenet 2020-09-08T14:43:39.083500Z

But maybe it's quite personal, some people like it one way or the other I imagine. Right now I tend to prefer attributes to have a strong identity (like in datomic or graphql), but I guess that might not be the case of everybody, clojure enables many ways to do the same thing.

2020-09-08T23:23:54.087500Z

If I want to expose a clojure map/data oriented api as JSON, but I use qualified keywords, would the "default" approach just be to stringify the keys, skip the colon, ie :my.qualified/key to "my.qualified/key"? Just want to make sure I'm not missing some json convention or issues or something

2020-09-09T14:02:23.112100Z

I'd agree that outside my app namespaces aren't very useful, and inside my app I want them if you don't have control of how data gets into your app, and it doesn't happen in a small number of easy to intervene places, namespacing keys is only one of many problems you are going to have

2020-09-09T14:03:28.112300Z

I'd use well placed ingestion / dispersion middleware, not a special "encoding" of the namespace into the key

2020-09-09T14:04:44.112500Z

another thing to consider: {:foo/bar 1 :foo/baz 2 :quux/OK 3} -> {foo: {bar: 1, baz: 2}, quux: {OK: 3}}

seancorfield 2020-09-09T16:10:03.112900Z

For some reason, that doesn't sit well with me. I think maybe that's the only point in Val's article that I agree with: don't treat qualified keywords as something structural. I think it's because, typically, at the edges you're not going to be mapping to/from a nested (unqualified) structure.

souenzzo 2020-09-09T17:05:57.113200Z

I prefer to explicitly map qualified names<>unqualified. We usually do not control external resources I did this lib: https://github.com/souenzzo/eql-as

cjsauer 2020-09-08T23:38:22.088500Z

This is a long-discussed topic, and as far as I know there are no conventions. • https://andersmurphy.com/2019/05/04/clojure-case-conversion-and-boundaries.html • https://vvvvalvalval.github.io/posts/clojure-key-namespacing-convention-considered-harmful.html • https://juxt.pro/blog/idiomatic-integration

đź‘Ť 1
seancorfield 2020-09-08T23:48:52.089800Z

@jjttjj Both Cheshire and clojure.data.json allow you to specify how keys are turned into JSON keys (strings) so you can choose to drop the qualifier or keep it.

seancorfield 2020-09-08T23:49:13.090200Z

(their defaults are opposite, BTW)

cjsauer 2020-09-08T23:51:43.090400Z

Trying to find the forum post where this is discussed at length...

cjsauer 2020-09-08T23:53:57.091200Z

Here is one discussing the “considered harmful” post above: https://clojureverse.org/t/clojures-keyword-namespacing-convention-considered-harmful/6169/6 I don’t think that’s the one I had in mind tho :thinking_face:

seancorfield 2020-09-08T23:53:59.091500Z

user=&gt; (require '[cheshire.core :as ches] '[clojure.data.json :as dj])
nil
user=&gt; (ches/generate-string {:a/b 1 :c/d 2})
"{\"a/b\":1,\"c/d\":2}"
user=&gt; (ches/generate-string {:a/b 1 :c/d 2} {:key-fn name})
"{\"b\":1,\"d\":2}"
user=&gt; (dj/write-str {:a/b 1 :c/d 2})
"{\"b\":1,\"d\":2}"
user=&gt; (dj/write-str {:a/b 1 :c/d 2} :key-fn (comp str symbol))
"{\"a\\/b\":1,\"c\\/d\":2}"
user=&gt; 
@jjttjj /cc @cjsauer

seancorfield 2020-09-08T23:55:16.092400Z

c.d.j escapes / by default but that can be turned off.

cjsauer 2020-09-08T23:55:32.093Z

Ah here it is. I think it was the precursor to Valentin’s blog post actually: https://clojureverse.org/t/should-we-really-use-clojures-syntax-for-namespaced-keys/1516

2020-09-08T23:56:38.093400Z

good to know! wouldn't have guessed that with the escaped slashes. Haven't settled on a json lib yet

seancorfield 2020-09-08T23:56:53.093600Z

Those are both essentially the same article, both by the same author, two years apart.

seancorfield 2020-09-08T23:57:29.093800Z

(and I still think he's mostly wrong 🙂 )

cjsauer 2020-09-08T23:58:34.094800Z

The discussion itself is what I wanted to link to, because there’s quite a bit of disagreement in this area.

2020-09-08T23:59:50.095Z

I remember seeing it and not agreeing, and now a month later I need some JSON compatibility and now see it in a whole new light haha