Thanks, I'm checking it out now. It's fun trying to wrap one's mind around P2P 😄
Hi everybody, is there any known problem with satisfies?
not working on protocols that use :extend-with-metadata
?
oooh ok I need a :refer
- I was using namespace/Protocol
inside satisfies?
duh
thanks a lot to the author of this post https://matthewboston.com/blog/clojure-protocol-namespaces/
nope it's not that - that works on extend
ed things though
That isn't the name of a protocol
A protocol is not imported
A protocol is a var defined using defprotocol
Yeah I am doing that ... I was thinking of adding a spec that make sure the passed object satisfies?
my protocol
Ok sounds good, i tried refer as well as namespace/protocol
but not a var. I had to take a break from the madness but will try again tomorrow, do you have any example by any chance I can look at? Thanks for answering!
refer and namespace/protocol should both work (just like normal vars)
but back to your original question - satisfies? does NOT work with metadata extended instances, in case that's the real problem you're seeing
I am just saying, if you use import to get access to a name, that name does not name a protocol
Import let's you refer to a java class or interface by its simple name, a protocol is not a java class or interface
So of you use import, it's not a protocol
@alexmiller @hiredman I went down the rabbit hole (on mobile) and checked github code. It seems there is at least one other instance of my problem here https://github.com/psagers/links-clj/blob/9e8795dfc1ce407720d5f1f1b683cba3983deeee/src/server/net/ignorare/links/db.clj#L30 Has this been reported? That is exactly what I am seing. In any case tomorrow I will try an isolated repro..
yes, you can vote for it here: https://ask.clojure.org/index.php/4622/satisfies-doesnt-work-instance-based-protocol-polymorphism
Cool thank you Alex
in general, you should not actually be using satisfies? much - it's better to rely on just invoking the protocol methods and fallback to default behavior (Object etc) if needed
I remembered that I saw something about measuring thread allocations. This could be a good enough approximation. It uses ThreadMXBean: https://stackoverflow.com/questions/61539760/benchmarking-jvm-memory-consumption-similarly-to-how-it-is-done-by-the-android-o Here's an example: https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/performance/memory.clj#L166-L187
(defn thread-allocated-bytes [t]
(let [thread-mbean (java.lang.management.ManagementFactory/getThreadMXBean)
thread-id (.getId t)]
(.getThreadAllocatedBytes thread-mbean thread-id)))
(defn allocated-bytes
[f]
(let [thread (Thread/currentThread)
start (thread-allocated-bytes thread)]
(f)
(- (thread-allocated-bytes thread) start)))
(comment
(let [t (Thread. (fn []
(let [v (vec (range 1e8))])
(Thread/sleep 1000) (println "DONE.")))]
(println "Thread allocated - before start:" (thread-allocated-bytes t))
(.start t)
(println "Thread allocated - after start:" (thread-allocated-bytes t))
(Thread/sleep 100)
(println "Thread allocated - after 100 ms:" (thread-allocated-bytes t))
(when (< 1e6 (thread-allocated-bytes t))
(println "Stopping the thread...")
;; note that `(.interrupt t)` isn't enough here - the thread is busy allocating and cannot be interrupted
(.stop t)
(println "Thread stopped")
(println "Thread allocated - after stop:" (thread-allocated-bytes t)))
(Thread/sleep 200)
(println "Thread allocated - after 300 ms:" (thread-allocated-bytes t))
(Thread/sleep 800)
(println "Thread allocated - after 1100 ms:" (thread-allocated-bytes t)))
,)
;; prints:
;; Thread allocated - before start: -1
;; Thread allocated - after start: 14064
;; Thread allocated - after 100 ms: 125412240
;; Stopping the thread...
;; Thread stopped
;; Thread allocated - after stop: -1
;; Thread allocated - after 300 ms: -1
;
Super basic macro question: How can I turn {:x 1 :y 2}
into (def x 1)
+ (def y 2)
?
At least now it’s not going to disappear in the voids of this Slack https://martinklepsch.org/posts/clojure-macro-magic-vars-from-map.html
(defmacro def-all [m]
(->> (for [[n v] m]
`(def ~(symbol n) ~v))
(into [])))
This kind of works, curious if there’s better waysI've recently discovered https://clojuredocs.org/clojure.template/do-template could be useful for your scenario
huh, cool! never seen that before and it’s kind of nice
I have a question about licensing. I’m working on something that could be construed as a Clojure interpreter - early in the works but planning to be as compatible as possible, probably to the point of being able to crunch clojure.core
. I don’t necessarily plan to distribute clojure.core
with the interpreter as I would rather write my own. But even then, some macros and functions would end up looking 1:1 same as in clojure.core
. Given the above - am I forced to make my project EPL-1.0?
Disclaimer: IANAL and this is not legal advice. It seems to me that if you are copying clojure.core all or in part, you are effectively making a "contribution" under the terms of the license and a derivative work provided in source code form must be made available under the EPL 1.0 agreement per the license. Distributing in object form has different constraints.
If you are doing this as part of a project for a company you work for, and plan to distribute source code for it, then perhaps the company you have actually hires intellectual property lawyers that can give you actual legal advice. If this is a personal project, you can hire an intellectual property lawyer yourself for such advice, but that can be expensive, and is pretty uncommonly done.
Stated more positively, the existence of Clojure implementation distributed under the EPL gives you the option to read it, learn from it, and copy parts of it into your own project, but then you have accepted the EPL and its terms. You can also make the project you want in a clean room implementation where you never look at the Clojure implementation code, and then it is your code and you can use any license you choose.
I learned about that like two days ago looking at the implementation of “are”. I had never heard of it either
; offtopic - would be great if we could just write code & solve problems and not have to deal with money or licenses that the latter requires
I understand the feeling, but unless you think that the idea of intellectual and/or all property should be abolished, licenses will exist.
i'd vote for robots doing all the annoying work for us so we'd be left with the fun parts
such robots do not automatically spring into existence by the mere act of voting/wishing 🙂
well once they do we'll be in trouble 😄
not in an armageddon war style trouble, trouble in the way that we still have to stay sane and somehow behave
so this is a personal project
I wanted to use the MIT license but I’m just wondering if defining my when
as (list 'if test (cons 'do body))
would count as copying parts of clojure and forcing me into EPL
as there would be multiple cases when, even if not intended, code would look the same because sometimes there is only one sane way to implement something
if you separate that part of the code out and publish that under epl with correct references , and use it as a library in your project .... would that enable you to "mit" the rest?
I’d guess so but IANAL
There are examples of companies wanting to be squeaky clean about a reimplementation actually adopting so called "clean room reimplementation" techniques, which you can study more about if you want to be squeaky clean. These same kinds of 'fuzzy boundaries' exist in copyright law for published books and papers, e.g. copying one or a few sentences with attribution is covered under "fair use" in many countries law, copying entire chapters is not. Is the dividing line a particular number of characters or words? I doubt it.
So I’m doing my own compiler and bytecode vm which I have to design and write myself based on: • my knowledge of clojure (top of my head) • available user-facing docs on how clojure and its APIs should behave Thus, I’m not concerned about infringing on anything at this point - the fun will start when the interpreter matures enough to run actual Clojure code
And you have a strong preference to release your code under a license that is something different than EPL 1.0 ?
I’m going for MIT, I’m not fond of copyleft licenses like EPL
Still not a lawyer, but if you "write your own replacement for clojure.core", without referring to the contents of clojure.core, from the top of your head understanding of how things should behave, then you are probably fine. If 100 of those definitions are character-for-character identical with sections of the clojure.core source file, it is hard to believe that you actually implemented it independently.
right
If two one-line functions are character-for-character identical and the rest are slightly different (or more), then it seems plausible that you wrote them yourself.
Those kinds of micro-analysis of differences would only ever be an issue if someone wanted to take this up in a court case, which if you truly implemented your own code, and even briefly described your process in a project README or something, seems unlikely to ever happen.
that makes sense
As a coding practicality side issue, making something 100% compatible with Clojure/JVM implementation in all ways sounds extremely time consuming to do without referring to its implementation code. ClojureScript and Clojure/JVM have differences, partly due to differing underlying JVM and ClojureScript runtimes, but partly due to the fact that it is hard to make two implementations 100% compatible.
yeah
You could ask @borkdude for his estimates of % compatibility (if a percent number makes sense at all) between his sci interpreter and Clojure/JVM, but there are a list of known differences there.
I mean, I’m just making an interpreter that could only be considered a toy when compared to Clojure itself - my goal is to have as much compat as possible but, as you pointed out, this will not be 100% due to runtime differences and time constraints
The main diff between sci and JVM Clojure is features that rely on defining new classes at runtime like defprotocol and defrecord are basically "faked" using multi-methods. And deftype and definterface aren't supported at all.
These things aren't supported by joker at all maybe for the same reason. In your interpreter, if you support Go interop, maybe this will be a funny mix of Go structs and defprotocol, that's up to you to find out and I will be interested to look what you come up with :)
I want ns.Def("x", &MyGoStuff{foo: 1})
show up as a record on the other side, with methods if MyGoStuff
has any
I’ve been experimenting with this and it’s def doable
anyway, thank you @andy.fingerhut, @alexmiller and @borkdude. This clears things up a bit for me 👍
as an obvious test, I think if you ever find yourself copying and pasting code from clojure itself into your files, that is clearly ... "copying" ... and "copyright" is in play :)
I love copying clojure
Hello, I have an issue with a https://gist.github.com/scttnlsn/9744501 that @borkdude helped finding to me, and when I use it seems to only print the value on the first or multiple times `put!, the second, fourth, etc are not called:
(defn debounce [in ms]
(let [out (chan)]
(go-loop [last-val nil]
(let [val (if (nil? last-val) (<! in) last-val)
timer (timeout ms)
[new-val ch] (alts! [in timer])]
(condp = ch
timer (do (>! out val) (recur nil))
in (recur new-val))))
out))
(def in (chan 1))
(go-loop [value (<! (debounce in 1000))]
(println value)
(recur (<! (debounce in 1000))))
(put! in {:bar (rand-int 100)})
(go-loop [value (<! (debounce in 1000))]
(println value)
(recur (<! (debounce in 1000))))
This is calling debounce
again for each iteration (constructing its lexically scoped out
channel again each time). Also, did you want the first value to be debounced?(def cin (a/chan 1))
(def cin-d (debounce cin 2000))
(a/go-loop []
(println "Read" (a/<! cin-d))
(recur))
(a/put! cin 5)
^ this is how I would expect to use it, just call debounce
on your input channel once, and keep a reference to the resulting channel
So when I call the put!
, the first time it's printed the value, when called a second time, it's not
but If I call quickly multiple times the put!, only the last value is printed as expected
AFAI could understand, the debounce function waits for a second input to them start the debounce
when you recur nil after putting, if you don't get anything with the timer, you >! nil which isn't great for async. I think you need some sentinel value for a lack of value other than nil. and if your timer goes off with this sentinel just recur without the >! to out
oh, it makes sense, actually, there is a if that check if the last value is nil and waits for a next <!, that seems to be the issue too
I'd replace the (into [])
with an outer do
(ins)user=> (defmacro def-all [m] (cons 'do (for [[n v] m] `(def ~(symbol n) ~v))))
#'user/def-all
(ins)user=> (def-all {:x 1 :y 2})
#'user/y
(ins)user=> x
1
(ins)user=> y
2
How to find in spec
which specs make an issue with Couldn't satisfy such-that predicate after 100 tries.
?
How to see for each spec how many tries was make during generate?
I have complex data structure and I really don’t want to guess this manually 🙂
you'll need to
for anything complex you should just write a custom generator
I expect it will be an issue about a few specs maybe. But I don’t know which one.
any spec with s/and
Does it mean there is no way to > How to find in spec which specs make an issue with Couldn’t satisfy such-that predicate after 100 tries.? > How to see for each spec how many tries was make during generate? ?
post a full stack trace
I don't believe so, once generation is happening, things are actually pretty opaque to spec, it is in the hands of test.check
like a leaf generator used in a collection generator, maybe nested indirectly
it is reality, using s/and makes the couldn't satisfy error very likely, unless you use a custom generator
the way generation works for s/and specs is it generates data with the first spec, then filters it through the predicates of the rest of the specs
yes, I was hoping to be able to track this to find issues
without this… this is really dark side of spec heh. Even my own generators can be not optimised and there is no good way to test it.
there is #clojure-spec and #test-check
ime it's almost always something with s/and
so I'll echo the advice to start there. struggled with this a bunch and the best I came up with is to use a binary search approach - e.g., for the case you are looking at, eliminate half at a time
#test-check can be very helpful for writing generators
also get in the habit of testing generation whenever you update your specs. it's a pain if you go and change a bunch of specs and then have to go through each
☝️:skin-tone-2: Definitely this.
I have a situation where there was no spec before and I wrote spec for data just now.
so not always the case 😉
I tend to have an RCF with s/exercise
calls in while I'm developing new specs and I try to make sure every spec generates as I'm writing them.
fib :: [Integer]
fib = 0 : 1 : zipWith (+) fib (tail fib)
Saw this in another chat medium. It’s a haskell sample to create a Fibonacci sequence. Is there a slick equivalent like that for Clojure or is https://blog.klipse.tech/clojurescript/2016/04/19/fibonacci.html the best out there?(def fib (lazy-cat [1 1] (map + (rest fib) fib)))
^ that's pretty much the Haskell equivalent yeah
except that the list and the tail are flipped in order (doesn't matter for correctness since + doesn't care)
yeah. i remembered seeing it and just googled. credit to SO user Joe Lehmann
they also mentioned that clojure-docs has examples of this for iterate and lazy-seq
I saw the iterate example but it used an anonymous function, which wasn’t bad but was curious if a cleaner version existed.
Though should it be lazy-cat [0 1]
?
fib normally starts with 1, 1
the mathematical definition (and the haskell example) starts with 0,1
it also might be kinda both. depending on the branch of mathematics, the natural numbers begin with 0 or 1, depending on what kind of edge cases you are more annoyed by
"In some older books, the value {\displaystyle F_{0}=0} is omitted"
Interesting. I don’t really know much about the fibonacci sequence.
https://clojuredocs.org/clojure.core/lazy-cat Btw what does that mean in the warning about it retaining the head? Does that mean it’s storing every value in memory?
> ;; N.B. this example holds onto the head of a lazy seq which should generally be avoided
I know this doesn’t exactly amount to return value for your help on this but hopefully getting someone excited about something in Clojure is worth something to you.
More efficient fn to create a fibonacci seq
(def m-fib
(memoize (fn [n]
(condp = n
0 1
1 1
(+ (m-fib (dec n)) (m-fib (- n 2)))))))
i wish all this cool ninja code automatically went into a mega list of how to do stuff in clj
the lazy version is already memoized (and the memoization has the same memory usage problems that holding onto the head does in terms of heap usage for larger values)
I guess it is true that the memoized version doesn't need to walk the spine of a lazy seq to get the pre-computed answer though
@gustavobertolino Nice! I shared that in the chat and someone had a question I don’t know how to answer: > Why use (- n 2) when you can do (nth (iterate dec 5) 2)?