fully-satisfies icon indicating copy to clipboard operation
fully-satisfies copied to clipboard

Utility functions for Clojure.

fully-satisfies

Utilities for Clojure.

Latest API documentation

Current version API documentation

Dependency

Available on Clojars.

Leiningen:

[io.github.frenchy64/fully-satisfies "1.12.0"]

Clojure CLI (Maven deps):

  :deps {io.github.frenchy64/fully-satisfies 
         {:mvn/version "1.12.0"}}

Clojure CLI (git deps):

  ;; requires `clj -X:deps prep` to compile java
  :deps {io.github.frenchy64/fully-satisfies 
         {:git/tag "1.12.0", :git/sha "861204b"}}

Try it in a REPL:

# compile
clj -Sdeps '{:deps {io.github.frenchy64/fully-satisfies {:git/tag "1.12.0", :git/sha "861204b"}}}' -X:deps prep
# start REPL
clj -Sdeps '{:deps {io.github.frenchy64/fully-satisfies {:git/tag "1.12.0", :git/sha "861204b"}}}'

Usage

fully-satisfies?

Docstring

(require '[io.github.frenchy64.fully-satisfies :refer [fully-satisfies?]])

(defprotocol A
  (a [this])
  (b [this]))

(fully-satisfies? A (reify))
;=> false
(fully-satisfies? A (reify A))
;=> false
(fully-satisfies? A (reify A (a [this])))
;=> false
(fully-satisfies? A (reify A (a [this]) (b [this])))
;=> true

run-all!

(require '[io.github.frenchy64.fully-satisfies.run-all :refer [run-all!]])

(run-all! println [1 (reduced 2) 3])
;1
;2
;3
;=> nil
;; does not short-circuit on reduced
(run-all! println [1 (reduced 2) 3])
;1
;#object[clojure.lang.Reduced 0x3deeac1 {:status :ready, :val 2}]
;3
;=> nil

Releasing

  1. Change project.clj version to desired version + SNAPSHOT
    • eg., 1.0.0-SNAPSHOT
  2. Commit with message Release {:major,:minor,:patch}
    • this releases the current version then bumps to the next {:major,:minor,:patch} SNAPSHOT
  3. Pull

Thanks

Thanks Wanderson Ferreira for the idea of fully-satisfies? and its name. My initial stance that fully-satisfies? was impossible to implement quickly proved to be incorrect after Wanderson's asked the right questions and decompiled some bytecode.

Wanderson and Mark Herman, II also helped improve early iterations of fully-satisfies?.

Related work

  • https://clojure.atlassian.net/browse/CLJ-2426
  • https://clojure.atlassian.net/browse/CLJ-1814
  • https://clojure.atlassian.net/browse/CLJ-2656
    • result of making this library and realizing supers call is suspicious

TODO

  • https://clojure.atlassian.net/browse/CLJ-2162
  • https://clojure.atlassian.net/browse/CLJ-2069
  • agents memory leak via conveyed bindings
  • https://ask.clojure.org/index.php/11080/get-find-assoc-vectors-overflows-key-when-passed-large-longs?show=11137#c11137
Clojure 1.10.3
user=> (get (into-array [1 2 42]) 4294967296)
1
user=> (get "123" 4294967296)
\1
user=> (get (into-array [1 2 42]) 4294967296 :not-found)
1
user=> (get "123" 4294967296 :not-found)
\1
  • https://clojure.atlassian.net/browse/CLJ-2322
  • throwArity(21) in AFn.java should be throwArity(20+args.length)
    • reprod:
Clojure 1.11.1
user=> (apply {} (range 21))
Execution error (ArityException) at user/eval214 (REPL:1).
Wrong number of args (21) passed to: clojure.lang.PersistentArrayMap
user=> (apply {} (range 22))
Execution error (ArityException) at user/eval216 (REPL:1).
Wrong number of args (21) passed to: clojure.lang.PersistentArrayMap
user=> (apply {} (range 24))
Execution error (ArityException) at user/eval218 (REPL:1).
Wrong number of args (21) passed to: clojure.lang.PersistentArrayMap
  • same in RestFn.java
    • reprod:
Clojure 1.11.1
user=> (defmacro big-fn [nargs] `(fn ~(conj (mapv #(gensym (do % "arg")) (range nargs)) 'last)))
#'user/big-fn
user=> (apply (big-fn 19) (range 21))
Execution error (ArityException) at user/eval145 (REPL:1).
Wrong number of args (21) passed to: user/eval145/fn--165
user=> (apply (big-fn 19) (range 22))
Execution error (ArityException) at user/eval168 (REPL:1).
Wrong number of args (21) passed to: user/eval168/fn--188
user=> (apply (big-fn 19) (range 24))
Execution error (ArityException) at user/eval191 (REPL:1).
Wrong number of args (21) passed to: user/eval191/fn--211
  • direct-linkable protocols

    • apparently a matter of makings protocols non-closures
    • https://ask.clojure.org/index.php/10967/are-protocol-methods-guaranteed-to-not-be-directly-linked?show=10990#a10990
    • approach:
      • add new field to clojure.lang.MethodImplCache$Entry which distinguishes between the (.isInstance c x) test in -cache-protocol-fn
      • update the identical? clause in the with-meta-extension part to grab this entry raw (eg., replace the fnFor with fnEntryFor)
      • move ginterf into the -cache-protocol-fn calls (1 arity at a time)
  • defmulti with cache controls https://clojure.atlassian.net/browse/CLJ-2626

  • count+last vs count+butlast+last

  • thrown?, thrown-with-msg? inherits try syntax https://github.com/clojure/clojure/blob/5ffe3833508495ca7c635d47ad7a1c8b820eab76/src/clj/clojure/test.clj#L504-L535

    • report another some-fn and every-pred short-circuiting inconsistencies
;; # some-fn
;; these are `(some #(some % args) fs)`, or `(some #(some % fs) args)`, or some hybrid
;; should be `(some #(some % args) fs)`
       ([x y z & args] (or (sp2 x y z)
                           (some #(or (p1 %) (p2 %)) args)))))
       ([x y z & args] (or (sp3 x y z)
                           (some #(or (p1 %) (p2 %) (p3 %)) args)))))
         ([x y z & args] (or (spn x y z)
                             (some #(some % args) ps)))))))

;; # every-pred
;; these are `(every? #(every? % args) preds)` or `(every? #(every? % preds) args)`, or some hybrid
;; should be `(every? #(every? % args) preds)`.
       ([x y z & args] (boolean (and (ep2 x y z)
                                     (every? #(and (p1 %) (p2 %)) args))))))
       ([x y z & args] (boolean (and (ep3 x y z)
                                     (every? #(and (p1 %) (p2 %) (p3 %)) args))))))
         ([x y z & args] (boolean (and (epn x y z)
                                       (every? #(every? % args) ps))))))))
  • (count (eduction)) => count not supported on this type: Eduction

License

Where noted, contains code from Clojure under license:

Copyright (c) Rich Hickey. All rights reserved.
The use and distribution terms for this software are covered by the
Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
which can be found in the file epl-v10.html at the root of this distribution.
By using this software in any fashion, you are agreeing to be bound by
the terms of this license.
You must not remove this notice, or any other, from this software.

Otherwise:

Copyright © 2021 Ambrose Bonnaire-Sergeant

This program and the accompanying materials are made available under the
terms of the Eclipse Public License 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0.

This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the Eclipse
Public License, v. 2.0 are satisfied: GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or (at your
option) any later version, with the GNU Classpath Exception which is available
at https://www.gnu.org/software/classpath/license.html.