This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-16
Channels
- # announcements (8)
- # aws (28)
- # babashka (26)
- # beginners (125)
- # calva (18)
- # chlorine-clover (2)
- # cider (12)
- # cljs-dev (6)
- # cljsrn (4)
- # clojure (134)
- # clojure-europe (31)
- # clojure-italy (2)
- # clojure-nl (14)
- # clojure-uk (83)
- # clojurescript (81)
- # conjure (4)
- # cursive (2)
- # datomic (145)
- # emacs (13)
- # events (3)
- # figwheel-main (14)
- # fulcro (30)
- # graalvm (23)
- # graphql (15)
- # helix (21)
- # jackdaw (20)
- # juxt (1)
- # lambdaisland (4)
- # leiningen (2)
- # malli (12)
- # meander (22)
- # observability (22)
- # off-topic (27)
- # pedestal (3)
- # re-frame (12)
- # reitit (1)
- # releases (2)
- # rewrite-clj (3)
- # shadow-cljs (67)
- # spacemacs (7)
- # sql (1)
- # tools-deps (19)
- # unrepl (2)
- # xtdb (25)
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
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
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
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
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
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
if you want the api to simply be "load this if found"
That’s probably the nicest, since the namespace will only get loaded in if a deps alias is added
or manual addition to classpath, or copying the file onto classpath...
-i is better suited to this
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
assuming you put these namespaces in a different source root
actually I guess you don't even need the :extra-paths
-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
Is it possible & good to develop chat app in clojure using http://socket.io or firebase ?
or i suppose in the case of http://socket.io Javascript?
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
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?
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.
And you would be making byte code, because that's what let*
does
this is the impl of let*
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6319
My choice here is between worse performance and generating code from templates which would make security team pull their hair out
what's the difference between "generating code from templates" and a macro?
the fact that it's constructed after prod startup?
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
I think a refactor that looks for values in a map is the least bad option, if I understand your original question correctly
it's definitely safer than dynamic eval or runtime bytecode generation if security is a concern
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 eval
ing it?
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
(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]
...
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
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?
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
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?
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)
I’ve seen similar patterns, but it kind of depends on the purpose of :last-changes
is :last-changes
meant to be a log of operations? is it meant for some sort of undo?
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
this sounds very similar to the VDOM approach
which seems like it would work well here
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
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
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 :title
at the application level to actually allow it to be rendered
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
oh, I didn’t realize what map-to-merge
was. anyways. new-windows
would be returned from splith
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))
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
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)))
where splith
and splitv
would be similar to transducers and each would receive the current window state when they are run
not sure this is helpful ¯\(ツ)/¯
oh that's really interesting. I think I'm getting the sync thing, will have to think about that.
@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?
no idea, haven't thought about it
Hi, anybody knows what’s “dup” and “ctor” stands for in print-dup and print-ctor?
afaik dup = duplicate, as in "print so that it can be read as data"
Thanks, Alex, your answer is a confirmation.
thanks, that make sense,
duplicate a print method/representation form?
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 thoughMake sense too,
might be definition-use pair
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
duplicate as in, if you read
the thing emitted by print-dup, it will be a duplicate, =
to the original
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.
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 ignoredwhat's your use case? Seems not really in the spirit of test gen to restrict values like this
and you specifically don't want a monotonically increasing collection but your generators to follow a pattern of generation?
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))
It comes from code that generates examples that are inserted in to a database
Every example needs a unique int
in that case, why not spec the collection of examples, and fmap
to associate unique ids?
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
Thanks 🙂
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
if you generate a vector of things, then everything has a natural unique id (its position in the vector)
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?
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 %))))))
(while I'm at it that toString should be str)
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?
to say those things are even "modeled" seems like an overstatement - you have an object and it's stored somewhere
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)
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
though, depending on what you mean by "model", they also provide centralized control of how the resources are initialized and disposed of
I guess I mean to say implement - assuming you couldn't use something off the shelf and wanted to make your own in clojure
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
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
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: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
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
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
doing some creative classpath scanning to try to make an all interface implementing function
(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])))
Syntax error (IllegalArgumentException) compiling reify* at (C:\Users\Ethan\AppData\Local\Temp\form-init11178639555945433735.clj:1:1).
Must hint overloaded method: accept
no, because how would someone compiling a call to the method know which one was being called?
@emccue I expect the answer lies on what overload means. It might be the type of the arguments.