Fork me on GitHub
#clojure
<
2020-06-16
>
noisesmith00:06:46

I don't see any problem with using an env var and/or system property as a flag that causes a non-top-level require to be run for loading alternate behaviors

noisesmith00:06:24

also, -e is sensitive to position in the command line - I forget the required order but I know it can be clobbered by some flags

lsenjov00:06:16

(when (:env/mock env) (require 'mock.namespace))?

lsenjov00:06:30

Alright, I’ll give that a try then. Thanks 🙂

noisesmith00:06:03

I wouldn't expect to be able to get a namespaced keyword out of the environment, but yeah that's the idea I had in mind

noisesmith00:06:40

since you mention that it's a convenience for the less clojure-adept, a standard thing like system property or env to turn it on seems to make sense

👍 3
lsenjov00:06:15

I could also do a (try (require …)) in, and load it if it exists, but I don’t know what that does when it AOTs

noisesmith00:06:46

I think io/resource looking for a resource name (eg. "/my/lib/optional.clj") followed by load if it's not nil would be more elegant than a try/catch require

👍 3
noisesmith00:06:05

if you want the api to simply be "load this if found"

lsenjov00:06:14

That’s probably the nicest, since the namespace will only get loaded in if a deps alias is added

noisesmith00:06:40

or manual addition to classpath, or copying the file onto classpath...

alexmiller01:06:46

-i is better suited to this

alexmiller01:06:48

if you made an alias with :extra-paths and :main-opts of -i that combo would I think be useful to conditionally add paths and load

alexmiller01:06:09

assuming you put these namespaces in a different source root

alexmiller01:06:55

actually I guess you don't even need the :extra-paths

lsenjov03:06:52

-i was exactly what I needed, I just didn’t realise it was needed in :main-opts, so I was passing in -i env/mock/… as an argument instead. Thanks heaps Alex

Romit Gandhi07:06:49

Is it possible & good to develop chat app in clojure using http://socket.io or firebase ?

emccue17:06:10

Just as possible and good as it would be in java

emccue17:06:39

or i suppose in the case of http://socket.io Javascript?

emccue17:06:13

you'll need to use clojurescript to use that library

Harry Glover08:06:36

Hi, Hope everyone is well. I am on the lookout for a Clojure Developer for a client based in The Hague. If interested, please contact me for further information. #clojure #job #remote-jobs #clojurescript #freelance

Ben Sless08:06:57

Is there any way to create non dynamic bindings besides function calls and builtins? (such as let*) I want to create local bindings without generating code (just generate the let) or faking an environment (with a map) Is there a way to do that or is code generation my only option?

noisesmith13:06:14

AFAIK none of the binding creation code that's lower level than let* is part of the public API. So it's possible to generate bytecode that plays nicely with a given clojure version, but it can break on the next version.

noisesmith13:06:19

And you would be making byte code, because that's what let* does

Ben Sless14:06:47

My choice here is between worse performance and generating code from templates which would make security team pull their hair out

noisesmith14:06:36

what's the difference between "generating code from templates" and a macro?

noisesmith14:06:50

the fact that it's constructed after prod startup?

noisesmith14:06:56

also, I don't know anything about your domain logic, but ending up with runtime generated code as a perf bottleneck would usually be an architecture problem

noisesmith14:06:50

I think a refactor that looks for values in a map is the least bad option, if I understand your original question correctly

noisesmith14:06:55

it's definitely safer than dynamic eval or runtime bytecode generation if security is a concern

Ben Sless14:06:30

Yes, it's code which can be generated after prod startup, a sort of optimized templating mechanism. If you manage to translate template to clojure code, which should be easy ("just data"), you can gain incredible performance, and even beat "state of the art" java templating engines. The question is how much of a concern is it to verify that all the symbols in an expression are part of a known set before evaling it?

noisesmith14:06:49

you could use clojure.walk/postwalk and throw an exception if any symbol is not a member of a whitelisted set, or otherwise fails some predicate

Ben Sless14:06:29

I can sleep tight with that solution

noisesmith15:06:27

(defn accept
  [form accepted]
  (walk/postwalk
   (fn [x]
     (if (and (symbol? x)
              (not (accepted x)))
       (throw (ex-info "Invalid access" {:sym x
                                         :accepted accepted}))
       x))
   form))
(ins)user=> (accept '(let [x 1 y 2] (+ x y)) '#{let + x y})
(let [x 1 y 2] (+ x y))
(ins)user=> (accept '(let [x 1 y 2] (System/exit 0) (+ x y)) '#{let + x y})
Execution error (ExceptionInfo) at user/accept$fn (validate-form.clj:7).
Invalid access
(ins)user=> *e
#error {
 :cause "Invalid access"
 :data {:sym System/exit, :accepted #{x y let +}}
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "Invalid access"
   :data {:sym System/exit, :accepted #{x y let +}}
   :at [user$accept$fn__520 invoke "validate-form.clj" 7]}]
 :trace
 [[user$accept$fn__520 invoke "validate-form.clj" 7]
  [clojure.walk$walk invokeStatic "walk.clj" 51]
  [clojure.walk$postwalk invokeStatic "walk.clj" 53]
  [clojure.walk$postwalk invoke "walk.clj" 53]
...

👍 3
Ben Sless15:06:40

Yep, it's pretty straightforward, just imagining the talk with security

noisesmith15:06:00

there's also some prior art with clojure sandboxes used in eg. public IRC server bots - by providing that service in a place where many clojure experts are present they found a lot of weird corner cases - here's clojail https://github.com/flatland/clojail and @U0NCTKEV8 has a currently active bot that uses some other security layer iirc

Ben Sless15:06:33

That's awesome! thanks!

sveri09:06:11

Since jdk 14 you can turn on better NPE output. This will show you which variable exactly caused the NPE. Did someone try that with clojure already? Does it work here too?

alexmiller11:06:25

Yes, but the “variable” is the null in either Clojure internals or generated bytecode so it may not be as helpful as you’d like

borkdude12:06:05

@harryg Feel free to post in #clojure-nl and #jobs as well

jjttjj13:06:59

I have a library that creates a nested data structure and provides operations on it. User’s of the library will probably want to hook into these changes. For example, if an item inside a sequence in the data structure, is split in to two items via a function in the library (so the sequence will now have one additional item), the user of the library will probably want to do things to the old or new item resulting from the split. My goal is to not actually have the library provide a reference type but still expose something that let’s a user watch for changes without doing diffs. Here’s a sort of contrived example https://gist.github.com/jjttjj/6cef4c2c8e1ed7e5907ced6074199ae3 Is this a legitimate pattern? Are there other examples of libraries like this? Is there an obvious better way to do this? It reminds me a little bit of zippers but it’s not quite the same thing. Should the :last-changes key be metadata?

jjttjj13:06:28

This is sort of like "hooks as data". Instead of "transactions as data"

bartuka13:06:15

This reminds me of Specter (https://github.com/redplanetlabs/specter), but I think they do not keep track of what changed after some operation. (I'm not a heavy user of the lib)

phronmophobic17:06:15

I’ve seen similar patterns, but it kind of depends on the purpose of :last-changes

phronmophobic17:06:55

is :last-changes meant to be a log of operations? is it meant for some sort of undo?

jjttjj17:06:50

I have two usages in mind 1. To put the state in an atom, call swap! on it with my api functions, then be able to access :last-changes from an add-watch 2. to enable separate operations to occur sequentially that need to know some information about what a previous operation did. I've been working on a window manager. My windows (maps with x/y/h/w) are stored in a sorted set, and I have functions that can do things like split a window and move the location of the current window (with pure data functions). I'm wondering if it's possible to keep this nice pure data implementation separate from what goes in the windows. So I would like to be able to horizontally split a window, return the resulting data structure, but I need to then put something in the new window. Or my app might need to do some triggers whenever any new window is created, etc. Currently my api looks like (splith windows location-to-split map-to-merge-with-resulting-split) but I'm wondering if I can rid of that last arg and have that be a separate step

phronmophobic17:06:35

this sounds very similar to the VDOM approach

phronmophobic17:06:42

which seems like it would work well here

jjttjj18:06:12

cool, thanks 🙂

phronmophobic18:06:08

assuming windows in your splith example is a pure immutable data structure, then in the VDOM approach, splith wouldn’t take a map-to-merge-with-resulting-split arg

phronmophobic18:06:20

you would simply have a sync operation that takes the last synced windows value and a new windows value that represents the desired state. sync would then reconcile the differences with either fewest operations or the least disruptive operations

jjttjj18:06:46

So windows is an immutable sorted-set, location-to-split identifies which window in that set to split, and the last map-to-merge... arg is a map to merge into the newly created window resulting from the spit (ie the newly created window will have :x/:y/:h/:w but I might want to give it new things like a :view and a :titleat the application level to actually allow it to be rendered

jjttjj18:06:16

so I think you're saying to use (sync old-windows new-windows) and that will make it happen efficiently, but my main problem is how to create new-windows itself? I could be missing something

phronmophobic18:06:39

oh, I didn’t realize what map-to-merge was. anyways. new-windows would be returned from splith

phronmophobic18:06:30

I was thinking something like:

(let [start-windows (current-windows!)
      windows (splith start-windows split-location new-window-info)
      windows (splitv windows split-location2 new-window-info2)]
  (sync! start-windows windows))

phronmophobic18:06:45

the VDOM approach assumes nothing mucks with the actual dom besides the reconciler which is probably different from a window manager. I don’t know enough about window managers to know what the best way to handle the windows changing outside of the reconciler

phronmophobic18:06:48

the other api that comes to mind if you’re trying to separate what from how is from transducers:

(apply-ops! window-handle
            (comp (splith split-location new-window-info)
                  (splitv split-location2 new-window-info2)))

phronmophobic18:06:43

where splith and splitv would be similar to transducers and each would receive the current window state when they are run

phronmophobic18:06:02

not sure this is helpful ¯\(ツ)

jjttjj18:06:28

oh that's really interesting. I think I'm getting the sync thing, will have to think about that.

jjttjj18:06:56

Yeah it's def helpful, thanks! It's always useful bouncing ideas around 🙂

👍 3
sveri14:06:21

@alexmiller I assumed something like this. So this would need some mapping like javascript -> clojurescript source maps? Do you plan on adding such a feature in the future or is that out of the woods?

alexmiller15:06:45

no idea, haven't thought about it

sveri15:06:37

Okay, thank you.

surferHalo14:06:04

Hi, anybody knows what’s “dup” and “ctor” stands for in print-dup and print-ctor?

alexmiller15:06:22

afaik dup = duplicate, as in "print so that it can be read as data"

surferHalo05:06:23

Thanks, Alex, your answer is a confirmation.

bartuka14:06:38

I read as dump and constructor

👍 3
surferHalo14:06:34

thanks, that make sense,

ghadi14:06:03

i think dup is duplicate

surferHalo14:06:21

duplicate a print method/representation form?

Daniel Stephens14:06:54

I found this in core:

(add-doc-and-meta *print-dup*
  "When set to logical true, objects will be printed in a way that preserves
  their type when read in later.

  Defaults to false."
  {:added "1.0"})
hasn't helped me work out what it stands for though

surferHalo14:06:34

Make sense too,

Daniel Stephens14:06:41

might be definition-use pair

ghadi14:06:07

duplicate being a stronger guarantee than copy -- duplicate meaning copy exactly

bartuka14:06:47

If I record well, I used the dup to save some data to file. Like in the example: https://clojuredocs.org/clojure.core/print-dup#example-542692cac026201cdc326b8c

bartuka14:06:49

so I associated with "dump"

noisesmith14:06:23

duplicate as in, if you read the thing emitted by print-dup, it will be a duplicate, = to the original

👍 6
surferHalo15:06:24

I think duplicate makes more sense, “print” to out/file is already sense of dump. As @dstephens refer, preserve the type and printed, is just a duplication of data in another location.

👍 3
erwinrooijakkers15:06:42

Is there a way to create a generator that generates an increasing value without using fmap?

(def index
  (atom 0))

(gen/sample (gen/fmap (fn [_] (swap! index inc)) (gen/int)))
;; => (1 2 3 4 5 6 7 8 9 10)
Here the gen/int is ignored

dpsutton15:06:27

what's your use case? Seems not really in the spirit of test gen to restrict values like this

hiredman15:06:29

Using state like that will not work correctly when shrinking failures

dpsutton15:06:49

and you specifically don't want a monotonically increasing collection but your generators to follow a pattern of generation?

hiredman15:06:03

And won't let you repeat test runs using the same random seed

dominicm15:06:35

My first thought is to instead generate a sequence of ints, and use the (gen/int) to set a seed to pass to (iterate inc (gen/int))

erwinrooijakkers16:06:22

It comes from code that generates examples that are inserted in to a database

erwinrooijakkers16:06:46

Every example needs a unique int

noisesmith16:06:37

in that case, why not spec the collection of examples, and fmap to associate unique ids?

noisesmith16:06:34

using shuffle or random-sample to get ids out of a large set of numbers for example, or even running distinct across a gen/sample of gen/int

hiredman16:06:08

it looks like you are generating collections of things incorrectly, e.g. you are generating a single thing multiple times, and taking that as a collection, instead of generating a collection of things

☝️ 3
hiredman16:06:32

(guessing based off of the call to sample above)

hiredman16:06:09

if you generate a vector of things, then everything has a natural unique id (its position in the vector)

noisesmith17:06:08

We've discovered that transit gives an NPE in writer on encode if the top level argument to be encoded doesn't have a write handler (for nested data inside a collection, there's an error that actually indicates that the writer for the data it was trying to encode wasn't found). Is this a bug or an unfortunate consequence of a desired optimization?

noisesmith17:06:08

sanitized.ns-test=> (mw/encode-body {:headers {"content-type" "application/transit+json"} :body string?})
Execution error (NullPointerException) at com.cognitect.transit.impl.AbstractEmitter/marshalTop (AbstractEmitter.java:203).
null

sanitized.ns-test=> (mw/encode-body {:headers {"content-type" "application/transit+json"} :body {:s string?}})
Execution error at com.cognitect.transit.impl.AbstractEmitter/marshal (AbstractEmitter.java:194).
Not supported: class clojure.core$string_QMARK___5410
(defmethod encode-body "application/transit+json"
  [request]
  (update request :body
          #(.toString (doto (ByteArrayOutputStream.)
                        (-> (transit/writer :json)
                            (transit/write %))))))

noisesmith17:06:30

(while I'm at it that toString should be str)

isak18:06:46

Is it fair to say that component libraries don't change how you model stateful things like connection managers or load balancers in Clojure, but only how they are passed around?

noisesmith18:06:47

to say those things are even "modeled" seems like an overstatement - you have an object and it's stored somewhere

noisesmith18:06:25

but yes, the difference is that with a component library, that thing is passed to the thing using it, rather than being accessed via globally visible location (usually)

noisesmith18:06:30

some people argue that mount isn't a component library for this reason - as it still puts the stateful object in a var that's accessed via location

isak18:06:06

ah, yea makes sense

isak18:06:11

right, ok

noisesmith18:06:05

though, depending on what you mean by "model", they also provide centralized control of how the resources are initialized and disposed of

isak18:06:43

I guess I mean to say implement - assuming you couldn't use something off the shelf and wanted to make your own in clojure

noisesmith18:06:12

maybe it's more clear to say, the reason one would use a component library (stuartsierra/component, integrant, mount, etc.) is to have a uniform way of initializing and disposing of resources, and automatic resolution and scaffolding of dependencies between those resources

3
noisesmith18:06:22

it's like DI without the "magic" bit - you create something that talks to the component system and the system ensures that it gets inserted in with the rest properly

bhaim12318:06:15

Hi I'm not sure I get the difference between or and :or for example:

(or 1 2)
=> 1
(:or 1 2)
=> 2
I also can't find where the :or is defined (tried to look in the complier but did not see it) and the logic behind it

lukasz18:06:22

:or is just a keyword. Your second example is more or less this: (get 1 :or 2)` meaning you're treating 1 as a map

bhaim12318:06:22

Thanks! Any good reason to write in this style?

lukasz18:06:38

It depends on the code - I tend to use (:some-key a-map) if I'm ok with it returning nil if the key doesn't exist. Otherwise I'd use (get a-map :some-key :some-fallback-value) Lastly, there's also destructuring which is sometimes preferable. Usually readability is the guiding principle. That said - if you do a lot (or (:some-key a-map) :some-other-val)) in 99% of cases you want to use get

bhaim12318:06:41

Thanks a lot, I'll a look at it

plins18:06:31

is there a better way of writing this?

(try
  (Long. my-long)
  (catch Exception _ nil))

plins18:06:31

fixed the snippet

hiredman18:06:48

I think that is fine.

hiredman18:06:00

I might prefer Long/parseLong to calling the long constructor because it is less ambiguous and returns a primitive long, but that is splitting hairs

ghadi18:06:06

Long. constructor is deprecated

ghadi18:06:14

use Long/parseLong for sure

plins18:06:28

thanks 🙂

emccue21:06:45

doing some creative classpath scanning to try to make an all interface implementing function

emccue21:06:53

(god-function '(fn [x] (+ x 1)))
=>
(clojure.core/reify
 java.lang.Object
 (toString [____3373__auto__] "GodFunction")
 com.codahale.metrics.Gauge
 (getValue [G__3498] (clojure.core/apply (fn [x] (+ x 1)) []))
 com.codahale.metrics.MetricRegistry$MetricSupplier
 (newMetric [G__3499] (clojure.core/apply (fn [x] (+ x 1)) []))
 com.github.benmanes.caffeine.cache.AsyncCacheLoader
 (asyncLoad [G__3500 G__3501 G__3502] (clojure.core/apply (fn [x] (+ x 1)) [G__3501 G__3502]))
 com.github.benmanes.caffeine.cache.CacheLoader
 (load [G__3503 G__3504] (clojure.core/apply (fn [x] (+ x 1)) [G__3504]))
 com.github.benmanes.caffeine.cache.RemovalListener
 (onRemoval [G__3505 G__3506 G__3507 G__3508] (clojure.core/apply (fn [x] (+ x 1)) [G__3506 G__3507 G__3508]))
 com.github.benmanes.caffeine.cache.Scheduler
 (schedule
  [G__3509 G__3510 G__3511 G__3512 G__3513]
  (clojure.core/apply (fn [x] (+ x 1)) [G__3510 G__3511 G__3512 G__3513]))
 com.github.benmanes.caffeine.cache.Weigher
 (weigh [G__3514 G__3515 G__3516] (clojure.core/apply (fn [x] (+ x 1)) [G__3515 G__3516]))
 com.google.common.base.Function
 (apply [G__3517 G__3518] (clojure.core/apply (fn [x] (+ x 1)) [G__3518]))
 com.google.common.base.Predicate
 (apply [G__3519 G__3520] (clojure.core/apply (fn [x] (+ x 1)) [G__3520]))
 com.google.common.base.Supplier
 (get [G__3521] (clojure.core/apply (fn [x] (+ x 1)) []))
 com.google.common.cache.RemovalListener
 (onRemoval [G__3522 G__3523] (clojure.core/apply (fn [x] (+ x 1)) [G__3523]))
 com.google.common.cache.Weigher
 (weigh [G__3524 G__3525 G__3526] (clojure.core/apply (fn [x] (+ x 1)) [G__3525 G__3526]))
 com.google.common.collect.Maps$EntryTransformer
 (transformEntry [G__3527 G__3528 G__3529] (clojure.core/apply (fn [x] (+ x 1)) [G__3528 G__3529]))
 com.google.common.util.concurrent.AsyncCallable
 (call [G__3530] (clojure.core/apply (fn [x] (+ x 1)) []))
 com.google.common.util.concurrent.AsyncFunction
 (apply [G__3531 G__3532] (clojure.core/apply (fn [x] (+ x 1)) [G__3532]))
 com.lambdaworks.redis.output.KeyStreamingChannel
 (onKey [G__3533 G__3534] (clojure.core/apply (fn [x] (+ x 1)) [G__3534]))
 com.lambdaworks.redis.output.KeyValueStreamingChannel
 (onKeyValue [G__3535 G__3536 G__3537] (clojure.core/apply (fn [x] (+ x 1)) [G__3536 G__3537]))
 com.lambdaworks.redis.output.ScoredValueStreamingChannel
 (onValue [G__3538 G__3539] (clojure.core/apply (fn [x] (+ x 1)) [G__3539]))
 com.lambdaworks.redis.output.ValueStreamingChannel
 (onValue [G__3540 G__3541] (clojure.core/apply (fn [x] (+ x 1)) [G__3541]))
 io.github.classgraph.AnnotationInfoList$AnnotationInfoFilter
 (accept [G__3542 G__3543] (clojure.core/apply (fn [x] (+ x 1)) [G__3543]))
 io.github.classgraph.ClassGraph$ClasspathElementFilter
 (includeClasspathElement [G__3544 G__3545] (clojure.core/apply (fn [x] (+ x 1)) [G__3545]))
 io.github.classgraph.ClassGraph$FailureHandler
 (onFailure [G__3546 G__3547] (clojure.core/apply (fn [x] (+ x 1)) [G__3547]))
 io.github.classgraph.ClassGraph$ScanResultProcessor
 (processScanResult [G__3548 G__3549] (clojure.core/apply (fn [x] (+ x 1)) [G__3549]))
 io.github.classgraph.ClassInfoList$ClassInfoFilter
 (accept [G__3550 G__3551] (clojure.core/apply (fn [x] (+ x 1)) [G__3551]))
 io.github.classgraph.FieldInfoList$FieldInfoFilter
 (accept [G__3552 G__3553] (clojure.core/apply (fn [x] (+ x 1)) [G__3553]))
 io.github.classgraph.MethodInfoList$MethodInfoFilter
 (accept [G__3554 G__3555] (clojure.core/apply (fn [x] (+ x 1)) [G__3555]))
 io.github.classgraph.ModuleInfoList$ModuleInfoFilter
 (accept [G__3556 G__3557] (clojure.core/apply (fn [x] (+ x 1)) [G__3557]))
 io.github.classgraph.PackageInfoList$PackageInfoFilter
 (accept [G__3558 G__3559] (clojure.core/apply (fn [x] (+ x 1)) [G__3559]))
 io.github.classgraph.ResourceList$ByteArrayConsumer
 (accept [G__3560 G__3561 G__3562] (clojure.core/apply (fn [x] (+ x 1)) [G__3561 G__3562]))
 io.github.classgraph.ResourceList$ByteArrayConsumerThrowsIOException
 (accept [G__3563 G__3564 G__3565] (clojure.core/apply (fn [x] (+ x 1)) [G__3564 G__3565]))
 io.github.classgraph.ResourceList$ByteBufferConsumer
 (accept [G__3566 G__3567 G__3568] (clojure.core/apply (fn [x] (+ x 1)) [G__3567 G__3568]))
 io.github.classgraph.ResourceList$ByteBufferConsumerThrowsIOException
 (accept [G__3569 G__3570 G__3571] (clojure.core/apply (fn [x] (+ x 1)) [G__3570 G__3571]))
 io.github.classgraph.ResourceList$InputStreamConsumer
 (accept [G__3572 G__3573 G__3574] (clojure.core/apply (fn [x] (+ x 1)) [G__3573 G__3574]))
 io.github.classgraph.ResourceList$InputStreamConsumerThrowsIOException
 (accept [G__3575 G__3576 G__3577] (clojure.core/apply (fn [x] (+ x 1)) [G__3576 G__3577]))
 io.github.classgraph.ResourceList$ResourceFilter
 (accept [G__3578 G__3579] (clojure.core/apply (fn [x] (+ x 1)) [G__3579]))
 org.apache.commons.lang3.Functions$FailableBiConsumer
 (accept [G__3580 G__3581 G__3582] (clojure.core/apply (fn [x] (+ x 1)) [G__3581 G__3582]))
 org.apache.commons.lang3.Functions$FailableBiFunction
 (apply [G__3583 G__3584 G__3585] (clojure.core/apply (fn [x] (+ x 1)) [G__3584 G__3585]))
 org.apache.commons.lang3.Functions$FailableBiPredicate
 (test [G__3586 G__3587 G__3588] (clojure.core/apply (fn [x] (+ x 1)) [G__3587 G__3588]))
 org.apache.commons.lang3.Functions$FailableCallable
 (call [G__3589] (clojure.core/apply (fn [x] (+ x 1)) []))
 org.apache.commons.lang3.Functions$FailableConsumer
 (accept [G__3590 G__3591] (clojure.core/apply (fn [x] (+ x 1)) [G__3591]))
 org.apache.commons.lang3.Functions$FailableFunction
 (apply [G__3592 G__3593] (clojure.core/apply (fn [x] (+ x 1)) [G__3593]))
 org.apache.commons.lang3.Functions$FailablePredicate
 (test [G__3594 G__3595] (clojure.core/apply (fn [x] (+ x 1)) [G__3595]))
 org.apache.commons.lang3.Functions$FailableRunnable
 (run [G__3596] (clojure.core/apply (fn [x] (+ x 1)) []))
 org.apache.commons.lang3.Functions$FailableSupplier
 (get [G__3597] (clojure.core/apply (fn [x] (+ x 1)) []))
 org.apache.commons.lang3.ThreadUtils$ThreadGroupPredicate
 (test [G__3598 G__3599] (clojure.core/apply (fn [x] (+ x 1)) [G__3599]))
 org.apache.commons.lang3.ThreadUtils$ThreadPredicate
 (test [G__3600 G__3601] (clojure.core/apply (fn [x] (+ x 1)) [G__3601]))
 org.apache.commons.lang3.builder.Builder
 (build [G__3602] (clojure.core/apply (fn [x] (+ x 1)) []))
 org.apache.commons.lang3.builder.Diffable
 (diff [G__3603 G__3604] (clojure.core/apply (fn [x] (+ x 1)) [G__3604]))
 org.apache.commons.lang3.reflect.Typed
 (getType [G__3605] (clojure.core/apply (fn [x] (+ x 1)) []))
 org.eclipse.jetty.security.authentication.AuthorizationService
 (getUserIdentity [G__3606 G__3607 G__3608] (clojure.core/apply (fn [x] (+ x 1)) [G__3607 G__3608])))

emccue21:06:04

but i get this error when compiling

emccue21:06:08

Syntax error (IllegalArgumentException) compiling reify* at (C:\Users\Ethan\AppData\Local\Temp\form-init11178639555945433735.clj:1:1).
Must hint overloaded method: accept

emccue21:06:52

is the name of the interface not enough to diambiguate?

noisesmith21:06:35

no, because how would someone compiling a call to the method know which one was being called?

dominicm21:06:44

@emccue I expect the answer lies on what overload means. It might be the type of the arguments.

ghadi21:06:03

also whyyyyyyyy

😂 15
dominicm21:06:27

I'm assuming it's educational

ghadi21:06:40

fun fact, interface dispatch in Hotspot is a linear search through a class's implemented interfaces

👀 6
isak22:06:39

Currently connected websocket clients as global state - yay or nay?

isak22:06:11

Never mind, I think I see a way to avoid it