Fork me on GitHub
#clojure
<
2017-11-02
>
qqq00:11:53

1. imagine I'm editing foo.clj I can define a macro, and use it later in the same file 2. now, imagine I'm editing foo.cljc and I define a macro, say via #?(:cljs (defmacro ...)) now, I should be able to use this macro in foo.cljc on the clojure side -- but is there anyway to also use it from the cljs side? or does cljs absolutely require macros come from other namespaces, that are pure *.clj files ?

vemv00:11:19

(binding [*out* /dev/null]) Obviously /dev/null isn't a thing in Clojure, but how to supress stdout? Forgot

qqq00:11:10

will the output overwhelm with-out-string ?

vemv00:11:03

possibly not. resulting string wouln't be colossal, still I'd like to learn the cleanest pattern

darwin00:11:49

implement your own PrintWriter class, which does nothing

csm00:11:15

( "/dev/null") too

noisesmith00:11:29

=> (binding [*out* (proxy [java.io.Writer] [] (append [& _]) (close []) (flush []) (write [& _]))] (println "hello, black hole"))
nil

qqq02:11:07

https://stackoverflow.com/questions/29914967/can-cljc-single-file-macro-definitions-to-work-with-clojurescript <-- does this trick still work ? I'm getting 'macro not found from my cljs compilation'

mattly02:11:19

I’m trying to find an article I read a while ago, told as a parable about a guy named Rich in the land of boxes, about how complex objects were and how simple composable tools could be more enjoyable

mattly02:11:47

and my google-fu is failing me… so, does anyone know this piece and can remember the title?

bfabry04:11:59

@mattly not referring to kingdom of nouns are you?

mattly04:11:44

no, I very specifically remember it referring to objects as some kind of blocks or boxes, and a shout-out to Rich

mattly14:11:35

yes! this is it. Thanks!

sundarj14:11:53

glad i could help 🙂

bfabry05:11:26

ah yeah that does sound different

viesti06:11:12

hmm, is there a plan to have https://github.com/clojure/brew-install in a apt/yum repository?

viesti06:11:03

seeing great potential for JVM/Clojure command line scripting 🙂

wusticality06:11:58

hey folks - veteran c++ game engine programmer here, emacs hacker / elisp user, getting into clojure

wusticality06:11:04

I was thinking about trying to do some kind of music visualizer (think g-force / milkdrop / etc) - what's the best approach to get framebuffer access and / or shader access in clojure? thanks in advance!

Empperi06:11:57

@iwannaseethelight making a brower UI or desktop?

viesti06:11:58

replacing ruby with sed from install.sh and nearly there :)

viesti06:11:44

framebuffer/shader sounds like native interop

Empperi06:11:49

for ClojureScript you can use https://github.com/thi-ng/shadergraph to get easy GLSL access

Empperi06:11:00

@viesti GLSL is shader access

wusticality06:11:32

@niklas.collin I'm just doing this for fun to learn the language - I love Lisp and its derivatives 🙂

Empperi06:11:04

yeah, well for ClojureScript and browsers there are several options out there, less so for Clojure

Empperi06:11:14

maybe quil?

wusticality06:11:24

I'll take a look - I mostly wondered if Clojure would even be capable of something like this given its immutable state

Empperi06:11:49

yes it can do anything, you can ask though if Clojure is the right tool for the job

wusticality06:11:57

In this particular case I'm just doing it for fun / learning - I build game engines for a living, it's definitely not the right language for graphics, but we'll see what it can do 😉

Empperi06:11:58

for the performance intensive mutable data stuff your code will end up looking an awful lot like java

wusticality06:11:22

I remember John Carmack rewrote Wolfenstein 3D in Haskell, it was pure madness

Empperi06:11:55

one could write a very efficient 3d engine with immutable data structures but only if the hardware drivers and APIs supported that properly

Empperi06:11:10

opengl etc have been written to handle this mutable state machine

phronmophobic06:11:26

which is no longer developed

phronmophobic06:11:52

but maybe as a way to get started

wusticality06:11:53

Thanks guys, I'll take a look - I have to run to a meeting, bbs

wusticality06:11:21

For this toy example I'm wondering if I can just modify a framebuffer directly and blit it to the screen

Macroz06:11:06

for the browser just use some Canvas wrapper or WebGL wrapper or interop

Empperi06:11:44

I think you can do that stuff with GLSL, accessing framebuffer that is. Been a while since I last did any GPU level coding 🙂

viesti07:11:05

@niklas.collin yeah, getting to shaders through the browser may help, don’t need to write the interop yourself since there’s stuff in the browser already 🙂

viesti07:11:44

Quil might be the best option here

viesti07:11:09

if the idea was to learn the language while doing something graphical

viesti07:11:31

too much to ask for to “go write some JNI” while learning Clojure the language 🙂

viesti07:11:50

results in “wtf” moments

viesti07:11:32

on other GPU related, but not graphics, Dragan Djuric has done great work on getting the compute side of GPU’s available to Clojure with http://uncomplicate.org/

viesti07:11:42

totally unrelated to graphics though

jumar08:11:55

I'd like to parse clojure source file. What's the good way to do this? Using clojure.tools.reader/read-string gives me only the first namespace form:

(r/read-string (slurp "src/clojure_repl_experiments/experiments.clj"))
;;=> (ns
 clojure-repl-experiments.experiments
 (:require [clojure.set :as set] [criterium.core :as c] [seesaw.core :as see]))
What I'd like to get is the list of all forms in that source file

cddr09:11:07

You could just use a loop to read the whole file. What's the context?

bronsa09:11:11

@jumar because of clojure's evaluation model it's not generally possible to read a whole namespace w/o compiling each form as you go

bronsa09:11:57

altho since 1.9.0-alpha<something> (or by using tools.reader) there's ways to make this work, but it's still tricky

jumar09:11:59

@cddr let's say I want to analyze which clojure functions are called in that code

jumar09:11:37

will do, thanks!

mseddon13:11:14

that's odd. their data suggests typescript is more likely to contain bugs than unadorned js.

jsa-aerial14:11:52

Yeah, real data has a way of messing up 'intuition' and theorizing...

tatut14:11:57

IIRC, the .ts extensions would also match C++ projects as they are Qt translation files

tatut14:11:26

there was a long twitter thread with critique about that study, but I’m failing to find it now

roberto14:11:40

yeah, I have my issues with a study like this too. It misses lots of context

roberto14:11:19

for example, I’m working on TS project at the moment, and we ran into an issue that was not TS’s fault, but the JS library that did not have a type file.

roberto14:11:53

and because I commit often, I committed the buggy code, but fixed it later, before the PR was made. So in a study like this, that would appear as a bug.

roberto14:11:59

while it misses the context

roberto14:11:49

Especially for languages that compile to JS, it won’t catch the edge cases when you try to interact with JS libraries

jsa-aerial14:11:05

Of course there are issues with it - any such study is going to have issues. But at least it is actual data and not just sitting around making goofy claims

tatut14:11:30

agreed, it’s better than just claiming things based on anecdotes

andrea.crotti14:11:14

what would be a good/easy way to disable logging when running tests?

andrea.crotti14:11:25

(using leiningen)

andrea.crotti14:11:45

well also setting the level to WARN is enough (probably better)

andrea.crotti14:11:07

in Python for example pytest captures all the logs during tests and only display the relevant logs in case of failure

dominicm14:11:09

@andrea.crotti depends how you're logging, logback supports a logback_test.xml for example.

andrea.crotti14:11:09

which is quite handy

andrea.crotti14:11:30

just using tools.logging at the moment

dominicm14:11:30

I'm not sure what that uses by default

the2bears14:11:01

@iwannaseethelight take a look at https://github.com/oakes/play-clj, it's got bindings to OpenGL etc through libgdx. I've been using it for making arcade games.

dominicm14:11:19

@andrea.crotti apparently the fallback is java.util.logging if nothing else is found 🙂 so you'll have to figure out how to configure that for testing.

andrea.crotti14:11:30

well in theory I just need (.setLevel (Logger/getRootLogger) Level/WARN)

andrea.crotti14:11:37

the only question is where to hook that up

dominicm14:11:46

there are hooks in clojure.test

andrea.crotti14:11:51

I have something like this for lein run

andrea.crotti14:11:50

mm not sure I find anything useful there

andrea.crotti14:11:00

unless I make a fixture for each test namespace that does that?

andrea.crotti14:11:10

which is not very convenient

langmartin15:11:22

I'm trying to recreate an aot behavior I've accidentally seen before, I'd like to capture a couple of environment variables at build time, so I can use version data automatically. I'm on 1.9.0-beta3, perhaps aot capture changed a bit? I've just got

(def DESCRIBE (System/getenv "GIT_DESCRIBE"))
in a file that's in the :aot lein config for the uberjar profile (and is being aot compiled, going by the output. That value is interpreted at runtime, though

langmartin15:11:00

whoops, dropped this: )

seancorfield15:11:56

Top-level defs are run at namespace load time (so, essentially, runtime).

dominicm15:11:23

@seancorfield correct me if I'm wrong, but if you AOT, doesn't that make the load time earlier? (which is why you shouldn't (launch-missiles) at the top level)

langmartin15:11:28

it certainly does sometimes, because it's been a pretty common confusing deployment issue. that's where I've encountered it in the past

seancorfield15:11:52

It loads namespaces for AOT and for running -- so it will execute both times:

(! 510)-> lein uberjar
Compiling aotit.core
I'm a top-level form
Created /Users/sean/clojure/aotit/target/uberjar/aotit-0.1.0-SNAPSHOT.jar
Created /Users/sean/clojure/aotit/target/uberjar/aotit-0.1.0-SNAPSHOT-standalone.jar

Thu Nov 02 08:28:52
(sean)-(jobs:0)-(~/clojure/aotit)
(! 511)-> java -jar target/uberjar/aotit-0.1.0-SNAPSHOT-standalone.jar 
I'm a top-level form
Hello, World!

seancorfield15:11:11

That's with (def foo (println "I'm a top-level form"))

dominicm15:11:27

oh interesting, I thought it stored the "result" in some way. Cool.

KeithP16:11:44

Am i misunderstanding spec? It should return whether something is a spec, correct?

mgrbyte16:11:20

2nd arg to s/valid? should be a spec

mgrbyte16:11:42

so: (s/valid? ::first-name "mgrbyte") -> true

mgrbyte16:11:53

(s/spec? ::first-name) -> true

KeithP16:11:48

I get (s/spec? ::first-name) -> nil

KeithP16:11:12

on 1.9.0-beta2

mgrbyte16:11:48

ignore me, I'm wrong

mgrbyte17:11:05

string? returns a spec-predicate, not a spec i think

KeithP17:11:53

from https://clojure.org/guides/spec: Any existing Clojure function that takes a single argument and returns a truthy value is a valid predicate spec

bfabry17:11:04

string? is a predicate, (s/spec string?) is a spec that conforms to the string? predicate

bfabry17:11:53

specs and predicates are interchangeable in lots of places but not all

bfabry17:11:42

and ::first-name is a keyword, not a spec

KeithP17:11:56

ah. (s/spec? (s/spec int?)) returns an obj

bfabry17:11:39

you can use keywords that represent spec definitions in lots of places that you can use specs and predicates, but not all (and specifically it seems not in s/spec?)

bfabry17:11:18

you can get the spec object from the registry using (s/get-spec ::first-name)

bfabry17:11:31

so (s/spec? (s/get-spec ::first-name)) should return true

bfabry17:11:35

or... truthy

KeithP17:11:07

thx for the insight

bfabry17:11:34

no worries

deg18:11:03

I'm hitting an anti-pattern often, and wonder if there is a better approach... I write a function, fn-a, that takes a map of parameters and does nothing with them but pass on to fn-b. It could be written as (defn fn-a [options] (fn-b options) ...) But, I want to supply useful arglist info, so I write (defn fn-a [{:keys [param1 params2 params3] :as options}] (fn-b options) ...)

deg18:11:43

But, later, fn-b gains a few more parameters. My code continues to work, but my arglist is out of date.

deg18:11:07

I'd love some way to declare that arglist info should be taken from another function.

noisesmith18:11:23

sounds like a job for spec, or prismatic/schema

noisesmith18:11:12

also, as Rich Hickey eloquently argues, it's good to have an open information model - specify the keys you need, but it should be OK if other things end up in there too

deg18:11:23

@noisesmith How? I see how I could use them for checking, but I'm looking for arglist as documentation.

noisesmith18:11:56

the fact that the check passed in dev mode (even if turned off in prod) is more useful than pure documentation that isn't executable

noisesmith18:11:09

if all you need is documentation, we have doc strings too

noisesmith18:11:52

I can write (defn foo [{:keys [a b c d]}] ...) and pass it an empty map - clojure doesn't care

noisesmith18:11:10

the a b c d there isn't any more informative than text in the doc string would be, nor is it more enforcible

deg18:11:32

That just begs the issue. I would still see the doc string of fn-a. But, really, the caller of fn-a needs to know the parameters of fn-b in order to effectively use the fn-a wrapper.

noisesmith18:11:03

which is why an executable validation that can optionally be turned off is more useful

deg18:11:06

I'm not lookinf for enforcement in the question, I'm looking for, if you will, enlightenment.

noisesmith18:11:32

why would a name that isn't enforced in an arg map be more enlightening than a string that isn't enforced in a doc string?

deg18:11:43

When I'm writing code in emacs, I want to do a quick C-c d d to see what parameters to type.

deg18:11:09

But, that forces me to keep the doc-string or the parameters of fn-a in lockstep with fn-b.

noisesmith18:11:09

sounds like an emacs problem - a doc string can give you a lot more nuance and information than names in a destructure can

noisesmith18:11:34

and an optional validation verifies that the code you are using actually works that way

deg18:11:48

When, really, fn-a's mandate is, rightly "take whatever I get and pass it to fn-b, because I have no right to care"

deg18:11:20

I would much rather spend one second when I'm typing my code, rather than one minute later, when a runtime check finds a problem. (and that's even assuming that someone did the unlikely task of writing a run-time checker for misspelled parameters in a map).

noisesmith18:11:59

spec and prismatic/schema can both warn you about such things, and can be turned off in production

deg18:11:52

Spec can, but not naturally. As you pointed out above "specify the keys you need, but it should be OK if other things end up in there too".

deg18:11:20

But, even that is not the point. I want auto-maintained arglist documentation that I can see when I'm writing code.

deg18:11:40

Emacs, and all other sane tools give this naturally for most functions.

deg18:11:52

But, there is just one missing case, which is pretty common in my code.

deg18:11:02

So, let me restate my question:

deg18:11:29

What is a tasteful way to document a function whose mandate is to pass a map of parameters to deeper code? The user typically knows only about this function, but needs to see an accurate list of the parameters that it expects.

noisesmith18:11:42

he already explicitly turned down using spec or schema for this

mpenet18:11:42

Not to mention a docstring.

noisesmith18:11:48

and doc string 😄

deg18:11:16

doc string requires repeating myself in both functions.

noisesmith18:11:20

I feel like I've made my cases so won't belabor them here

deg18:11:35

Spec is really the right answer, but I don't think the tooling is quite right yet.

mpenet18:11:38

You could abuse destructuring {:as foo :keys [...]} but that d be odd if you dont use them

sundarj18:11:09

(def ^{:arglists (-> (var map) (meta) (:arglists))} my-map (fn [f coll] (map f coll)))
#'boot.user/my-map

(doc my-map)
-------------------------
boot.user/my-map
([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
nil
something like this could work?

deg18:11:18

@mpenet. Yes, that was my original anti-pattern in my initial quesiton.

mpenet18:11:18

Or use a record but even then, they re quite open

bfabry18:11:44

spec is really really the right answer seeing as it shows up in docstrings

deg18:11:07

Does spec show up in docstrings? I'd not realized that.

noisesmith18:11:28

@deg this is also true for prismatic.schema/defn btw

noisesmith18:11:49

+user=> (s/defn foo :- s/Num [] 42)
#'user/foo
+user=> (doc foo)
-------------------------
user/foo
([])
  Inputs: []
  Returns: s/Num
nil
`

deg18:11:59

@sundarj Nice idea. But, currently, does not quite work in ClojureScript because there is an open bug in the handling of some arglists.

sundarj18:11:55

ah, unfortunate

noisesmith18:11:41

these tools are imperfect, but they really are designed with these issues in mind

deg18:11:19

Re spec, one problem is that this forces creating a name to describe this map. For a simple set of parameters used in only a few functions, this is a bit heavy.

noisesmith18:11:44

if it's worth describing it's worth giving a name IMHO

mpenet18:11:01

Some people wrote macros to work around this. But ultimately you ll grow to like this (I did)

deg18:11:21

But, agreed, spec does the heavy lifting nicely for "big" cases. And, arglist spoofing covers the remaining cases, I guess.

bfabry18:11:36

why does it force you to create a name? (s/fdef my-fun :args (s/cat :the-arg-map (s/keys :req-un [::foo ::bar ::bash]))) is fine

deg18:11:09

Because I need to use it twice. (in fn-a and fn-b in my original example)

deg18:11:41

And, of course, I still need to list the parameters in the definition of fn-b.

bfabry18:11:49

how could you use it twice without assigning it to some sort of name for any solution? 0_o

deg18:11:31

In the code, I only need to use it once. fn-b requires me to list the parameters. fn-a only needs (defn fn-a [options] (fn-b options))

bfabry18:11:31

you do need to list the parameters twice, that's true

deg18:11:43

Right. I'm trying to avoid any need to list the options in or near fn-a, which may well be in a different file than fn-b.

mpenet18:11:44

You can combine the groups of keys with s/and

pelletier18:11:57

Is there a way to add annotations to an interface when using gen-interface?

deg18:11:01

Which groups of keys?

mpenet18:11:44

So your fist takes a spec with (s/and ::mapfoo ::mapbar etc)

mpenet18:11:02

And rest of fns just the precise submap

mpenet18:11:15

Thats one way

deg18:11:30

I don't think you are answering the same question that I'm asking.

pelletier18:11:24

nice. i saw that example, but figured it would only work for gen-class

pelletier18:11:32

i'll give it a go, thanks!

noisesmith18:11:54

oh - if you keep reading there's a gen-interface example in the same file haha!

pelletier18:11:32

yep but the example doesn't use annotations 🙂

pelletier18:11:18

meh, i guess if i dug one level deeper i would have seen the add-annotations call

deg18:11:25

My functions take exactly the same parameters as each other. Only fn-b cares about them in detail. fn-a is just an exposed surface wrapped around it.

bfabry18:11:16

imo you're working too hard to avoid duplication here. just

(s/def ::param-list (s/cat :opts-map (s/keys ...) :other-arg ...))
(s/fdef fn-a :args ::param-list)
(s/fdef fn-b :args ::param-list)

deg18:11:04

Yes, understood, and not terrible since the duplicated code can sit next to its copy. But, this still requires: - Repeating the param list in both the spec and fn-b (admittedly, this is no worse than any other spec, so ok...) - Creating the name ::param-list -- Well, more likely ::fn-b-param-list which, again, is not terrible but adds a bit of weight. In short. Yes, this is a reasonable answer and about the best that can be done today (with the arguable exception of the meta :arglists hack above). But, there is still a bit of a smell here that bothers me. Sorry that I obviously can't pin down my discomfort well enough... I'm clearly in the minority here. 🙂

phronmophobic18:11:26

fwiw, I don’t think your crazy. I’ve used libraries that have similar wrapper functions and I wish that they had gone through the trouble you’re going through so I can use my C-c d d 🙂. It seems @sundarj’s recommendation is a decent fix if it worked with cljs. It looks a lot like https://docs.python.org/2/library/functools.html#functools.wraps from python

len18:11:11

I am using at-at to schedule some functions and want to persist the schedules (preferably to datomic) - is there anything that can help with that or any pointers ?

Garrett Hopper18:11:35

I have some macros in a clj file (no coresponding cljs file exists). I want to import these from some cljc files. Doing a normal :require in the cljc files fails, because the cljs namespace doesn't exist:

No such namespace: common.css, could not locate common/css.cljs, common/css.cljc, or JavaScript source providing "common.css" in file src/common/pages/timesheet.cljc
I could do them in a cljc file, but the macros require java stuff, so almost everything would be reader conditionaled to clj. I managed to get it working with (:require-macros [common.css :as css]), but I'm very confused, because as far as I know clj files don't recognize require-macros. Could someone explain?

noisesmith18:11:58

@len I'm sure it's possible (and I've done variations on it myself) but quartzite is made for this purpose http://clojurequartz.info/

hiredman18:11:18

@ghopper cljc files may be compiled as clojurescript or clojure, you are compiling it as clojurescript, so clojurescript features are there

len18:11:25

thanks @noisesmith looks like thats the option

Garrett Hopper18:11:56

@hiredman Except it's being compiled as clojure as well without issue.

hiredman18:11:02

@ghopper the error message mentioning JavaScript is the clue

Garrett Hopper18:11:24

The error message was with the normal (:require), not the (:require-macros).

Garrett Hopper18:11:31

There isn't any error with :require-macros.

hiredman18:11:50

and between those two attempts, are you loading the code the exact same way?

Garrett Hopper18:11:14

Shouldn't there be? When it's compile to clojure and it can't find the namespace, because it doesn't recognize the require-macros method?

Garrett Hopper18:11:19

Yeah, same way.

hiredman18:11:35

so clojurescript

hiredman18:11:05

the error message can only come from compiling clojurescript, if you are loading them the same way then they are being compiled the same way, so both are being compiled as clojurescript ∎

Garrett Hopper18:11:13

Oh... you're right. It wasn't being compiled to clojure as well. It thows a ns doesn't comform error now.

Garrett Hopper18:11:37

So I need a reader conditional to switch between require-macros and require?

dpsutton18:11:32

(ns hitch.selector
  #?(:cljs (:require-macros hitch.selector))
  (:require [hitch.oldprotocols :as oldproto]
            [hitch.protocol :as proto]
            [hitch.tracking.halt :as halt]
            [hitch.selector-tx-manager]))

dpsutton18:11:45

an example from us ^

Garrett Hopper18:11:07

@dpsutton Well, the second require would be only for clj, since I don't have a cljs namespace of the macros namespace.

Garrett Hopper18:11:58

(ns common.core
  #?(:clj
     (:require [common.css :as css])
     :cljs
     (:require-macros [common.css :as css])))
How's that? Can I have multiple (:require) calls in a ns?

Garrett Hopper18:11:21

I suppose that works:

(ns common.core
  (:require
   ...
   #?(:clj [common.css :as css]))
  #?(:cljs (:require-macros [common.css :as css])))
A bit ugly

Garrett Hopper18:11:44

What does https://clojurescript.org/about/differences#_namespaces mean by "implicit macro loading". It's not clear to me how that's accomplished.

zignd21:11:24

Is there anything I use to purposely return nil from a function's tail when there's a call at the tail returning something?

Alex Miller (Clojure team)21:11:01

yeah, just put nil at the end

zignd21:11:35

oh, so it's totally ok to do so?

Alex Miller (Clojure team)21:11:55

I’ve run into this occasionally and don’t know of any other solution

Alex Miller (Clojure team)21:11:17

you could write a function and wrap the validate if that was nicer looking to you

the2bears21:11:17

Reminds me of actual Java code I saw once, 'if (c==null) return null else return c;'

zignd21:11:20

nice, thanks alex! i'm still learning, so just looking for best practices

Alex Miller (Clojure team)21:11:39

(defmacro swallow [& body]
  `(do ~@body nil))

Alex Miller (Clojure team)21:11:51

then (swallow (s/validate …))

zignd21:11:03

woah, that's interesting

Alex Miller (Clojure team)21:11:13

prob a simpler way to do that

Alex Miller (Clojure team)21:11:09

if it’s always wrapping a single expression, you could just do (def swallow (constantly nil))

zignd21:11:10

i guess i prefer this alternative with constantly, most of the time it would be used for calls at the function's tail

zignd21:11:31

thanks again alex! i didn't know about constantly

noisesmith22:11:34

I had a hunch that constantly obviates the need for a macro that creates a do form

+user=> (def foo (constantly :OK))
#'user/foo
+user=> (foo (println :a) (println :b) (println :c))
:a
:b
:c
:OK

noisesmith22:11:45

I wonder if it still works for large arg lists

zignd22:11:12

oh yeah, constantly creates a functions that accepts any number of arguments. that invalidates my argument to prefer it over the macro form

bfabry23:11:53

I do not understand what the n argument does in practice in pipeline-async 0_o

Mudge23:11:40

How do I use apply with a Java object?

Mudge23:11:55

I want to call a method on a java object using the apply function. Is this possible?

Mudge23:11:16

How do I call a java method with potentially different number of arguments?

bfabry23:11:19

@nick319 afaik not without explicitly using reflection

bfabry23:11:40

and even if you could figure out how to do it implicitly... it would still be expensive

Mudge23:11:01

How expensive is reflection?

bfabry23:11:23

quite a few orders of magnitude more expensive than a regular function call

bfabry23:11:35

but, if you're in a context where you're doing io... not at all

bfabry23:11:46

ta, sounds like what I thought. practically it's only a limit if tasks are completing and sending results