clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
Crispin 2021-04-29T02:37:46.202200Z

I'm having trouble finding the source of disparate run times in subsequent group-by calls. First call is slow. But then if you evaluate the exact same thing it's fast. Is there some kind of caching in group-by? group-by uses transient collections. Is there internal caching in transient/persistent! ?

Crispin 2021-04-29T02:38:00.202500Z

example code here: https://pastebin.com/PszjtJcB

raspasov 2021-04-29T02:40:34.202600Z

(time …) is not a good benchmark; Use criterium (library), or if you really care/need performance, something like YourKit is essential (it’s a paid product, it’s worth it IMO, I’ve used it)

phronmophobic 2021-04-29T02:41:54.203300Z

It's due to laziness. If you add (doall tuples) before the first time measurement, then the times should be similar

👍 1
😂 1
1
👆 1
raspasov 2021-04-29T02:41:57.203400Z

Try switching tuples to: (def tuples (mapv vector kmers (next kmers))) … to see if it makes a difference.

phronmophobic 2021-04-29T02:45:03.203700Z

fwiw, your example seems like a reasonable usage of time (to me).

Crispin 2021-04-29T02:48:51.204200Z

thankyou. thats it

👍 1
raspasov 2021-04-29T03:27:58.204500Z

I agree, I didn’t notice the big discrepancy at first (which is very obviously caused by the laziness of map as you pointed out)

👍 1
2021-04-29T06:25:29.211800Z

Has there been any attempts to do MSA with clojure? I’d like to know if there’s any good sample projects out there in github or else. So far I’ve found one book ‘microservices-with-clojure’ but couldn’t find more, definitely yet to be a mainstream way of developing with clojure. But I think the event driven nature of the architecture suits with immutability and pure function concepts in clojure (or with other fp languages). I’d like to know more the community’s perspectives on this and current situation.

2021-04-29T07:00:32.215600Z

I see your point on not re-inventing the wheel. But having to get acquainted with those tech-stacks in Java will be a little bit of hurdle to jump through.

2021-04-29T07:00:48.215800Z

Yap, I’ve been using aws-api as well; it was a nice implementation.

2021-04-29T07:01:28.216Z

all in all, microservice seems to be very capable with current clojure environment. It is reassuring to know!

2021-04-29T07:09:42.216200Z

Ya, Clojure support for some of those would be good, but the language is too niche, those projects tend to only support the top 10 most used languages like Java, C#, JS, Go, C++, etc.

2021-04-29T07:10:59.216400Z

And even then, they often don't support them first class, normally they use code-gen, but that means they always design their clients in an OO way, and then generate the client code for Java, C#, JS, etc. all from it. So even if they generated a Clojure one, it would probably feel very OO and similar to using the Java one through interop

2021-04-29T07:12:15.216700Z

That said, for the most popular ones, I'm sure you'll find a relatively well maintained Clojure wrapper made by someone else, such as Kafka and ActiveMQ, and all the AWS one are covered by aws-api

👍 1
2021-04-29T07:38:21.217100Z

I'd also have a look at Polylith if I was you: https://polylith.gitbook.io/polylith/ It's not exactly MSA, and it can be used to make micro-services, but it's also different. Kind of let you do a micro-services lite architecture and then decide if you want to deploy things as a monolith or a set of micro-services.

👍 1
2021-04-29T08:04:18.218600Z

Awesome! thanks for the recommendation, will look into it.

the2bears 2021-04-29T19:54:58.287100Z

> A system where services (typically having its own db) communicate with events on pub-sub basis As an aside, I think this is far too narrow a description of micro-services. More important to mention is decoupling and autonomy of services. Communication may be events, it may be a request/response mechanism. Services tend to be small, encompassing a business context. Finally, they lend themselves to independent deployment due to many of the above qualities.

🙏 1
2021-04-29T06:25:37.211900Z

Ya, this would have made more sense, but I think the two are just called arg-list and the context tells you which one is being refered too.

2021-04-29T06:40:16.212200Z

What's MSA?

2021-04-29T06:42:38.212400Z

I meant for MircoService Architecture

2021-04-29T06:44:08.212800Z

A system where services (typically having its own db) communicate with events on pub-sub basis

2021-04-29T06:44:55.213Z

Lots of people do Micro-services with Clojure, you can have a look at Compojure-API, Yada, Liberator, Pedestal or Reitit, in no particular order, those are the most popular options for writing RESTfull HTTP API micro-services.

2021-04-29T06:46:15.213300Z

Then for Pub/Sub people use Kafka, RabbitMQ, AWS SNS/SQS, AWS Kinesis, etc. All those have great client support from Clojure through their Java library and a lot of them have plenty of Clojure wrappers for as well if you prefer.

2021-04-29T06:48:36.213600Z

Seems like I was quick to judge from just finding one book. I stumbled upon this clip and it seems great. https://www.youtube.com/watch?v=PWuuh48r2tc

2021-04-29T06:48:52.213900Z

There's more too, I think Redis Pub/Sub and ActiveMQ are popular as well

2021-04-29T06:50:27.214100Z

Ya, in fact there's probably too many options all with equal popularity, so it can be difficult choosing which one to go with since there's no clear winner.

2021-04-29T06:51:56.214300Z

There's also some good support for GraphQL, which for some use case is nicer to use over REST

2021-04-29T06:52:22.214500Z

So those libraries support clojure environment, yes? I mean it will be pretty sad if one has to call java apis in clojure code. I hope the environment revolving msa-clojure is at least actively being discussed.

2021-04-29T06:52:52.214700Z

Sure, I’ve used Lacinia once with clojure, and it was also great.

2021-04-29T06:55:43.214900Z

All the rest ones I mentioned are Clojure first. The Pub/Sub ones are Java based. But you shouldn't find it sad, Clojure is designed to leverage Java where there is no need to improve over it, it explicitly doesn't re-implement what Java does well already, and things like stateful clients to remote services is done very well by Java, the Clojure interop syntax makes the usage a breeze and even more convenient and natural than it be in Java itself.

2021-04-29T06:57:32.215100Z

I'm sure you'll find plenty of Clojure wrappers over them by many people, but personally I'd just use them directly with Clojure interop, they all generally just revolve around:

(doto (SomeClient. config)
  (.sendMessage message))

2021-04-29T06:59:45.215300Z

Hum... Actually the AWS ones have native Clojure clients maintained by the company that employs the Clojure core team itself: https://github.com/cognitect-labs/aws-api

Jim Newton 2021-04-29T08:52:06.220200Z

is there a tutorial about how a macro (defined by defmacro) can extract meta data from its list of arguments?

Jim Newton 2021-04-29T08:55:06.222800Z

I’d like to invoke a macro as follows: `(my-macro a b ^{some-meta-data-1-as-hash} c d e ^{some-meta-data-2-as-hash} e f)` and within the macro definition figure out that two hashes were given, the first associated with c (which might be any syntactical form, and the second hash was associated with e which again might be any syntactical form.

Jim Newton 2021-04-29T08:58:06.224700Z

hmm actually its worse than that. The syntax is

(my-macro ([a b c] ….)
          (^{some-data-as-hash} [a b [c d]] …)
          ...)

borkdude 2021-04-29T08:59:52.225Z

@jimka.issy

user=> (defmacro foo [a] (list 'do (meta a)))
#'user/foo
user=> (foo ^:foo [])
{:foo true}
user=> (foo ^{:foo :bar} [])
{:foo :bar}

Jim Newton 2021-04-29T09:07:46.225600Z

couple of things are fuzzy.. meta gets the meta data associated with its given value right? When if I pass the same value twice to the macro, how does meta know which is which?

Jim Newton 2021-04-29T09:07:46.225700Z

e.g. (mymacro ^meta-data-1 42 ^meta-data-2 42)

borkdude 2021-04-29T09:09:11.226200Z

you can't do (foo ^:foo 1) since metadata cannot be applied to a number

Jim Newton 2021-04-29T09:10:40.227200Z

interesting. that means I really don’t understand. I thought meta data was applied to the list (foo 1) with some magic indication that it applies to the 2nd element.

borkdude 2021-04-29T09:11:58.228400Z

There is hardly any magic in Clojure. meta just looks up metadata on objects that support it (notably collections and symbols, all implementing clojure.lang.IObj)

borkdude 2021-04-29T09:13:01.229600Z

When you write (defn foo [^String x]) what you are doing is you are writing a list with symbols. The symbol x has metadata {:tag String}. And this data is processed by the defn macro (or rather the thing below it, the fn* special form)

Jim Newton 2021-04-29T09:13:24.230100Z

so if I make a macro call with the same symbol twice, can I have different meta data on each occurance of the symbol? (mymacro ^meta-data-1 a ^meta-data-2 a)

borkdude 2021-04-29T09:13:51.230500Z

yes

Jim Newton 2021-04-29T09:14:18.231Z

ok, that means the meta data is not assoicated with the symbol, because a is eq to a

Jim Newton 2021-04-29T09:14:29.231400Z

or am I even more confused that I imagined?

borkdude 2021-04-29T09:14:59.232Z

the metadata is associated with a specific symbol. symbols are not interned in Clojure, because they do not have context-free meaning, like keywords or strings

raspasov 2021-04-29T09:16:39.233Z

@jimka.issy so if I’m understanding correctly, you’re trying to associate meta data to a binding form, and have the macro behave more or less like (defn …)

raspasov 2021-04-29T09:16:41.233200Z

Is that about right?

borkdude 2021-04-29T09:16:43.233400Z

See this example:

user=> (defmacro foo [a] (list 'quote (map (juxt identity meta) &form)))
#'user/foo
user=> (foo ^String x)
([foo nil] [x {:tag String}])

Jim Newton 2021-04-29T09:18:54.233600Z

are you asking what i’d like to do after I extract the meta data?

Jim Newton 2021-04-29T09:19:08.233800Z

sorry, I don’t understand your question

raspasov 2021-04-29T09:20:08.234Z

Nevermind 🙂

Jim Newton 2021-04-29T09:20:36.234200Z

I’m writing a macro which is very similar to fn. fn allows the user to specify several sequences, the first element of each is a lambda-list (an arglist in clojure-speak). I want to optionally associate meta data with some of these lambda-lists

borkdude 2021-04-29T09:21:49.234400Z

See example: https://clojurians.slack.com/archives/C03S1KBA2/p1619687803233400

raspasov 2021-04-29T09:23:18.234700Z

For writing a macro that’s similar to defn/fn see this: https://github.com/lilactown/helix/blob/master/src/helix/core.clj#L116 (it has been useful to me to look at when writing something similar)

raspasov 2021-04-29T09:38:05.235300Z

@borkdude that’s a neat example 🙂 The short version (if I’m correct):

(defmacro foo-short [a]
 `'~(map (juxt identity meta) &form))

raspasov 2021-04-29T09:38:45.235500Z

Took me 5 min to figure out, a small mind bender 🤯 😄

raspasov 2021-04-29T09:39:55.235700Z

That triple combo ``'~`

Jim Newton 2021-04-29T09:46:05.237900Z

I have to admit that I really don’t understand. but my code works. I have written a macro named dsfn which expands to destructuring-fn as follows:

(dsfn ([x]  'aaa)
      (^{x Boolean}
         [x y] 'bbb)
      ([x y] 'ccc))
expanding to
(destructuring-fn
  ([[x] {}] 'aaa)
  ([[x y] {x Boolean}] 'bbb)
  ([[x y] {}] 'ccc))
here’s the macro
(defmacro dsfn [& forms]
  (letfn [(process [form]
            (let [meta-data (meta (first form))]
              (cons [(first form) (if (nil? meta-data) {} meta-data) ] (rest form))))]
    `(destructuring-fn
      ~@(map process forms))))

raspasov 2021-04-29T09:53:23.238100Z

What does destructuring-fn look like?

raspasov 2021-04-29T09:54:14.238300Z

Is that another macro?

Jim Newton 2021-04-29T09:55:11.238500Z

yes it is another macro.

Jim Newton 2021-04-29T09:56:30.239Z

I hope that link is public. tell me if it is not

raspasov 2021-04-29T09:56:57.239200Z

Yes, public.

raspasov 2021-04-29T09:58:26.239400Z

That is neat to try to match on the structure/shape of the data.

raspasov 2021-04-29T09:59:09.239600Z

What part of dsfn is unclear? It seems to do what it says.

Jim Newton 2021-04-29T10:00:38.239800Z

hmm. perhaps it is clear, and I’m just self deprecating.

raspasov 2021-04-29T10:02:28.240Z

That looks like a neat project; Is it part of research or just for fun?

Jim Newton 2021-04-29T10:21:32.242900Z

How am I suppose to distinguish beween vector-ish and list-ish ? For example, fn distinguishes its semantics based on whether an argument looks like [a b c] or ([a b c] …) ? I had been using the function list? but apparently given (cons 1 (list 2 3 4)) the list? predicate returns false.

Jim Newton 2021-04-29T10:22:02.243500Z

my dsfn macro above calls (cons ….) which produces a non-list 😞

Jim Newton 2021-04-29T10:23:23.244Z

looks like in the code of fn that it calls vector? rather than calling list? to distinguish the two cases.

yuhan 2021-04-29T10:31:36.244100Z

You probably want seq? instead of list? , which is specifically for IPersistentLists

Jim Newton 2021-04-29T10:38:32.244300Z

thanks. yes it is both fun and research.

Jim Newton 2021-04-29T10:39:01.244500Z

I’m happy to have feedback.

Jim Newton 2021-04-29T10:39:18.244700Z

it’s part of a presentation at the European Lisp Symposium in two weeks.

Jim Newton 2021-04-29T10:41:21.244900Z

take a look: https://gitlab.lrde.epita.fr/jnewton/clojure-rte/-/blob/master/doc/dsc.md

borkdude 2021-04-29T11:00:33.245200Z

always use seq? is probably a good rule of thumb

raspasov 2021-04-29T11:47:24.245400Z

Nice, any hope this can work in Clojure and ClojureScript?

Jim Newton 2021-04-29T12:46:27.245600Z

I have no experience with clojure script.

Jim Newton 2021-04-29T12:46:47.246100Z

the theory behind it is that it should work in a large range of dynamic reflective languages

Jim Newton 2021-04-29T12:46:56.246300Z

a student of mine wants to investigate javascript

Jim Newton 2021-04-29T14:52:37.246700Z

what do functions like int? and integer? and number? double? do in clojurescript?

raspasov 2021-04-29T15:09:40.246900Z

@jimka.issy perhaps you want to create a clojure-rte channel here in Slack to discuss this?

raspasov 2021-04-29T15:12:47.247100Z

All of the above functions exist in CLJS; there are some gotchas around numbers, but those are all caused by the differences between JS and the JVM;

raspasov 2021-04-29T15:13:23.247300Z

Things like this actually run ok in CLJS:

(+ nil 1)
=> 1 
… but would throw an Exception on the JVM

raspasov 2021-04-29T15:17:32.247600Z

From here: https://clojurescript.org/about/differences • Numbers • ClojureScript currently only supports integer and floating point literals that map to JavaScript primitives ▪︎ Ratio, BigDecimal, and BigInteger literals are currently not supported ◦ Equality on numbers works like JavaScript, not Clojure: `(= 0.0 0) ⇒ true`

borkdude 2021-04-29T15:20:38.248100Z

Related to something in #beginners : Has there been any discussion around allowing (Class/staticMethod foo bar baz) if staticMethod is a Java method receiving a variable number of things at the end, instead of forcing Clojure users to create an array?

borkdude 2021-04-29T15:21:34.248700Z

I guess this is more difficult to support in Clojure because of the dynamic typing? (currently you can look at the type of array to choose the right method)

alexmiller 2021-04-29T15:30:43.249600Z

yes, fogus has been working on this

alexmiller 2021-04-29T15:31:12.250Z

it's complicated of course, but going to take a run at it for 1.11 probably

borkdude 2021-04-29T15:35:49.250200Z

ooh really, wow

borkdude 2021-04-29T15:36:09.250400Z

go @fogus!

👏 5
1
borkdude 2021-04-29T15:36:51.251200Z

I guess there is an ambiguity when you have varargs of arrays, but this is pretty rare... it's a difficult thing to get right I can imagine

borkdude 2021-04-29T15:44:09.251900Z

I didn't know the last one would work as well, but it does (clojure 1.11.0, babashka current).

user=> (defn foo [& {:keys [a b]}] [a b])
#'user/foo
user=> (foo {:a 1 :b 2})
[1 2]
user=> (foo :a 1 :b 2)
[1 2]
user=> ((partial foo :a 1) :b 2)
[1 2]
user=> ((partial foo :a 1) {:b 2})
[1 2]
🤯

alexmiller 2021-04-29T15:48:46.252800Z

https://ask.clojure.org/index.php/4224/java-method-calls-cannot-omit-varargs for anyone who wants to vote on it (such an old request, jira goes back to 2010!)

borkdude 2021-04-29T15:49:05.253600Z

are you adding up votes from ask + the old jira or how does this work?

alexmiller 2021-04-29T15:49:07.253700Z

it wasn't even jira - that was filed back when we were using Assembla

alexmiller 2021-04-29T15:49:27.254100Z

primarily using ask, but we look at both

alexmiller 2021-04-29T15:50:00.254600Z

jira votes did not fully survive the transition into cloud jira (lost any votes from users that weren't migrated)

😞 1
borkdude 2021-04-29T15:50:23.254900Z

voted, thank you

alexmiller 2021-04-29T15:50:59.255200Z

did not really have a big impact - the highest rated things were still the highest rated things more or less

alexmiller 2021-04-29T15:51:38.256200Z

it has enough votes that it is already on the radar of course, but doesn't hurt

borkdude 2021-04-29T15:51:42.256300Z

I am using a similar thing to your ask for some of the issues in my projects, but using github discussions. It makes elaborating on ideas easier while keeping the issue itself more crisp.

2021-04-29T15:52:20.256400Z

Why does defmulti go out of its way to prevent itself from being re-evaluated more than once?

alexmiller 2021-04-29T15:52:44.256700Z

because you would lose all the methods I think

borkdude 2021-04-29T15:53:04.256900Z

can't it update itself if it already exists?

alexmiller 2021-04-29T15:53:38.257300Z

what problem are we trying to solve?

1
1
borkdude 2021-04-29T15:53:45.257500Z

(similar to how vars are updated when you call def twice)

2021-04-29T15:54:16.258300Z

Hum... I can see how someone might have thought that, but I think it would have been less annoying to manage that problem than try to force re-evaluate a defmulti.

borkdude 2021-04-29T15:54:20.258500Z

@alexmiller It might be related to a discussion in #clj-kondo where someone suggests that clj-kondo should advice using a var as the dispatch function (to which I didn't agree, but this would solve their REPL problem)

2021-04-29T15:55:16.259300Z

I've just seen a lot of people get burned by that and use tricks to avoid it, like passing it a var to the dispatch-fn, or adding a (def multi nil) above it.

alexmiller 2021-04-29T15:55:16.259400Z

this is one of those things where repl use has tradeoffs with non-repl use

ghadi 2021-04-29T15:55:59.260700Z

someone should say what they're trying to do out loud. It's buried in between the lines

👍 1
borkdude 2021-04-29T15:56:43.261500Z

I thought @didibus was referring to what @ddouglass said in #clj-kondo but that might not be the case and maybe it was purely co-incidental

2021-04-29T15:57:41.262800Z

I was wondering if there was any downside to use those trick, since defmulti goes out of its way to not be re-evaluable.

ghadi 2021-04-29T15:57:53.263400Z

as someone who has watched rich and alex work for a little while now:

alexmiller 2021-04-29T15:57:56.263600Z

well, it's slower

ghadi 2021-04-29T15:58:21.264100Z

didibus is asking about "why does defmulti go out of its way not to be re-evaluable"

ghadi 2021-04-29T15:58:54.264700Z

I think what they mean is "I want to alter or iterate on the dispatch function at the REPL"

ghadi 2021-04-29T15:59:16.265400Z

the stuff about "preventing re-eval" is removed from this, and a presumption ^

2021-04-29T15:59:27.265700Z

Ya, for the Var. I guess adding (def multi nil) above it shouldn't be slower though right?

alexmiller 2021-04-29T16:00:18.266800Z

no, not sure if that impacts ability of tools to analyze

ghadi 2021-04-29T16:01:33.267500Z

changing the dispatch function could change its arity, which would also break expectations on all the extensions

2021-04-29T16:01:46.267700Z

In this case I wanted to know why it prevents itself from being re-evaled, I already know the workarounds at the REPL. Was trying to reason what are the pros/cons of this:

(def multi nil)
(defmulti multi (fn[..] ...))

ghadi 2021-04-29T16:02:34.268200Z

keep in mind the extensions could be in any file

2021-04-29T16:03:02.268400Z

I feel it must have been written very early. Because require doesn't force reload by default, and most people at the REPL control what they reload. So I don't see why it would cause issues nowadays, but also I can see how someone thought that it shouldn't.

ghadi 2021-04-29T16:04:28.269600Z

what is the "it" in "I don't see why it would cause issues"?

2021-04-29T16:04:54.270200Z

Ya, it's a bit of a tradeoff I guess. What is more annoying, reloading the defmulti by accident and having to reload all the other defmethod for it or the other way around.

2021-04-29T16:05:15.270700Z

it = defmulti

borkdude 2021-04-29T16:05:37.271600Z

I think you mean, it = making defmulti reloadable

alexmiller 2021-04-29T16:05:43.272100Z

you may not even know what the defmethods are to reload them

matheusashton 2021-04-29T16:06:49.273400Z

Hello! I'm trying to run a compojure project with ring-jetty-adapter , and tried to add wrap-reload of ring.middleware.reload so I could run lein run only once while developing, but I'm receiving an exception trying to run:

Caused by: java.io.FileNotFoundException: Could not locate ring/middleware/reload__init.class, ring/middleware/reload.clj or ring/middleware/reload.cljc on classpath.
	at clojure.lang.RT.load(RT.java:466)
	at clojure.lang.RT.load(RT.java:428)
	at clojure.core$load$fn__6824.invoke(core.clj:6126)
	at clojure.core$load.invokeStatic(core.clj:6125)
	at clojure.core$load.doInvoke(core.clj:6109)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5908)
	at clojure.core$load_one.invoke(core.clj:5903)
	at clojure.core$load_lib$fn__6765.invoke(core.clj:5948)
	at clojure.core$load_lib.invokeStatic(core.clj:5947)
	at clojure.core$load_lib.doInvoke(core.clj:5928)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$load_libs.invokeStatic(core.clj:5985)
	at clojure.core$load_libs.doInvoke(core.clj:5969)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$require.invokeStatic(core.clj:6007)
	at clojure.core$require.doInvoke(core.clj:6007)
	at clojure.lang.RestFn.invoke(RestFn.java:482)
	at fiis_api.service$eval2080$loading__6706__auto____2081.invoke(service.clj:1)
	at fiis_api.service$eval2080.invokeStatic(service.clj:1)
	at fiis_api.service$eval2080.invoke(service.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7176)
	at clojure.lang.Compiler.eval(Compiler.java:7165)
	at clojure.lang.Compiler.load(Compiler.java:7635)
	... 96 more
any ideas of what am I missing?

borkdude 2021-04-29T16:10:02.274200Z

The dependency?

2021-04-29T16:13:22.274400Z

It's an ergonomics issue, if you've defined te wrong dispatch function and want to fix it at the REPL. And it seems maybe the behavior of defmulti is only for the REPL ergonomics as well. In trying to prevent the attached methods from being lost by accidentally re-evaluating the defmulti. So I was wondering if that was all there is to it, or there was like performance, or memory or some other reasons that's not just a REPL ergonomic thing.

matheusashton 2021-04-29T16:13:32.274600Z

I added [ring "1.9.3"] to project.clj .-.

2021-04-29T16:14:08.274700Z

And if you bypass it because you personally prefer the other way of working at the REPL, would you risk something doing so

ghadi 2021-04-29T16:17:02.274900Z

if you are changing the dispatch function, it is not automatically clear whether the previously extended things are compatible with the new dispatch function

2021-04-29T16:20:48.275100Z

Well, most of the time when you change the dispatch function it's because it was wrong to begin with. So generally either the defmethod already didn't work and you're trying to fix them, or you know you plan to just change your defmulti to work differently and will go update the defmethods too.

2021-04-29T16:27:02.275500Z

Ya, I see the tradeoff, maybe I feel in practice if you're changing a dispatch-fn, you're probably the owner of the defmulti and your dispatch-fn wasn't working or doing what you want. And if you've got a defmulti from a library, it won't get re-evaluated anyways because require itself doesn't reload lib-spec.

2021-04-29T16:28:32.275700Z

But.. I need to think about that second one more. Like if I vended a library where I expect users can extend the defmulti and my code did:

(def multi nil)
(defmulti multi (fn...))
Would I cause them pain-points at the REPL

2021-04-29T16:29:36.275900Z

high voter turnout requires high impact issues that fire people's imaginations, not just for Clojure issues 🙂

benwen 2021-04-29T16:44:03.277900Z

Hi all: The San Francisco-based Bay Area Clojure meetup is looking for speakers for a May 11 (usu. 8pm PT) zoom event. #clojure-bay-area if you are interested in sharing something or know someone who might fit that description. Past zoom events here: https://www.youtube.com/channel/UCmtrRPVjcEMZrzTfAY3fd0Q Folks from remote locations works as well. Thank you!

2021-04-29T16:53:08.278300Z

Currently hammock-timing this one. 🙂

Jim Newton 2021-04-29T17:02:48.278700Z

it will be interesting to see how much work will be needed to make it work in clojurescript

Jim Newton 2021-04-29T17:03:34.278900Z

There are quite a few places where I depend on the way symbols work and also on the JVM.

2021-04-29T17:16:09.280Z

:/ - (javadoc (.getBytes "hello")) opens a google search for "allinurl:[B.html"

2021-04-29T17:16:24.280300Z

maybe arrays should be special cased?

denik 2021-04-29T17:39:14.281100Z

what’s the best/fastest way to compare two byte-arrays?

2021-04-29T17:40:16.281500Z

for equality?

denik 2021-04-29T17:47:12.282700Z

this works but allocates two vectors 😕 (compare (vec (.getBytes "bar")) (vec (.getBytes "bar")))

alexmiller 2021-04-29T17:49:27.283200Z

java.util.Arrays has some methods for sorting and equality of byte arrays

2021-04-29T17:51:08.283300Z

how do you compare opaque byte arrays?

2021-04-29T17:51:30.283600Z

just the raw byte values (i.e. ignoring any semantic meaning)?

denik 2021-04-29T17:52:10.284500Z

yes

denik 2021-04-29T17:52:22.285200Z

they just need to be compared for a db index

alexmiller 2021-04-29T17:52:32.285500Z

depending on your exact goals, you could certainly write a tight loop over the array for this purpose (in Java for best performance) or there are probably some numerical methods if you convert the byte arrays as numbers

2021-04-29T17:53:11.285600Z

Yeah I don’t think that’s built in anywhere

2021-04-29T17:53:19.285900Z

that I know of

denik 2021-04-29T17:54:03.286100Z

thank you!

denik 2021-04-29T17:55:49.286500Z

thanks alex!

Ronny Li 2021-04-29T21:07:47.288700Z

Does anyone know about the general approach behind Roam's multiplayer feature? Wondering if there's any libraries out there that can help me implement something similar 🙂

phronmophobic 2021-04-29T21:13:11.291200Z

Not sure what roam is using, but many multiplayer features are implemented on top of CRDTs or Operational Transforms(OTs). Here’s a good video that covers many of the concepts, https://youtu.be/x7drE24geUw

phronmophobic 2021-04-29T21:15:22.293Z

The guy from the video has a crdt library called automerge, https://github.com/automerge/automerge

Ronny Li 2021-04-29T21:15:40.293300Z

Thank you! 🙏