Back
swap-vals! (clj)
(source)function
(swap-vals! atom f)
(swap-vals! atom f x)
(swap-vals! atom f x y)
(swap-vals! atom f x y & args)
Atomically swaps the value of atom to be:
(apply f current-value-of-atom args). Note that f may be called
multiple times, and thus should be free of side effects.
Returns [old new], the value of the atom before and after the swap.
Examples
typedclojure/typedclojure
(ns ^:no-doc typed.ann.clojure
"Type annotations for the base Clojure distribution."
#?(:cljs (:require-macros [typed.ann-macros.clojure :as macros]))
(:require [clojure.core :as cc]
[typed.clojure :as t]
#?(:clj [typed.ann-macros.clojure :as macros])
#?(:clj typed.ann.clojure.jvm) ;; jvm annotations
#?(:clj clojure.core.typed))
#?(:clj
(:import (clojure.lang PersistentHashSet PersistentList
APersistentMap #_IPersistentCollection
#_ITransientSet
IRef)
(java.util Comparator Collection))))
cc/reset! (t/All [x] [(t/Atom x) x :-> x])
cc/swap! (t/All [x b :..] [(t/Atom x) [x b :.. b :-> x] b :.. b :-> x])
#?@(:cljs [] :default [
cc/reset-vals! (t/All [x] [(t/Atom x) x :-> '[x x]])
cc/swap-vals! (t/All [x b :..] [(t/Atom x) [x b :.. b :-> x] b :.. b :-> '[x x]])
])
cc/vreset! (t/All [x] [(t/Volatile x) x :-> x])
cc/volatile? (t/Pred t/AnyVolatile)
cc/compare-and-set! (t/All [x] [(t/Atom x) t/Any x :-> t/Bool])
typedclojure/typedclojure
(ns typed-test.spec.clojure.core
(:require [typed.spec.clojure.core :as api]
[clojure.alpha.spec :as s]
[clojure.alpha.spec.gen :as gen]
[clojure.alpha.spec.test :as stest]
[typed.clj.spec :as t]
[typed.clj.spec.test-utils :as tu]
[clojure.test :refer :all]))
(s/def ::swap-vals!-2
(t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r))
:ret (t/tv :w)))
:ret (s/tuple (t/tv :r) (t/tv :w)))))
(s/def ::swap-vals!
(t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (s/tuple (t/tv :r) (t/tv :w)))))
(deftest atom-spec-test
;; deref
(tu/is-valid (s/fspec :args (s/cat :atom (api/atom-spec :read integer?))
:ret integer?)
deref)
(tu/is-invalid (s/fspec :args (s/cat :atom (api/atom-spec :read integer?))
:ret boolean?)
deref)
(tu/is-valid ::deref deref)
(tu/is-invalid ::deref (comp str deref))
;; reset!
(tu/is-valid ::reset! reset!)
(tu/is-invalid ::reset! deref)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w))
:w (t/tv :w))
; bad return
:ret integer?))
reset!)
;; swap! (arity 2)
(tu/is-valid ::swap!-2 swap!)
(tu/is-valid ::swap!-2
; spec does not require the write to actually happen
(fn [a f]
(f @a)))
(tu/is-invalid ::swap!-2
; cannot just return deref
(fn [a f]
@a))
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r))
;returns wrong val
:ret any?))
:ret (t/tv :w)))
swap!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :w)) ;takes :w
:ret (t/tv :w)))
:ret (t/tv :w)))
swap!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :r) ;swap :r and :w
:read (t/tv :w))
:f (s/fspec :args (s/cat :r (t/tv :r))
:ret (t/tv :w)))
:ret (t/tv :w)))
swap!)
;; swap! (arity 3+)
(tu/is-valid ::swap! swap!)
(tu/is-invalid ::swap!
;drops args
(fn [a f & args] (swap! a f)))
(tu/is-invalid ::swap!
swap-vals!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
;provided args too broad
:extra-args (t/fold-binders any? :extra-args))
:ret (t/tv :w)))
swap!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
; no extra args passed
#_#_:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w)))
swap!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
; no extra args accepted
#_#_:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w)))
swap!)
;; swap-vals! (arity 2)
(tu/is-valid ::swap-vals!-2
swap-vals!)
(tu/is-invalid ::swap-vals!-2
swap!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r))
:ret (t/tv :w)))
;swapped return order
:ret (s/tuple (t/tv :w) (t/tv :r))))
swap-vals!)
;; swap-vals! (arity 3+)
(tu/is-valid ::swap-vals!
swap-vals!)
(tu/is-invalid ::swap-vals!
;drops args
(fn [a f & args] (swap-vals! a f)))
(tu/is-invalid ::swap-vals!
swap!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
;provided args too broad
:extra-args (t/fold-binders any? :extra-args))
:ret (s/tuple (t/tv :r) (t/tv :w))))
swap-vals!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
; no extra args passed
#_#_:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (s/tuple (t/tv :r) (t/tv :w))))
swap-vals!)
(tu/is-invalid (t/all :binder (t/binder :w (t/bind-tv)
:r (t/bind-tv)
:extra-args (t/bind-tv
:kind (s/* (t/binder
:arg (t/bind-tv)))))
:body
(s/fspec :args (s/cat :atom (api/atom-spec :write (t/tv :w)
:read (t/tv :r))
:f (s/fspec :args (s/cat :r (t/tv :r)
; no extra args accepted
#_#_:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (t/tv :w))
:extra-args (t/fold-binders (t/tv :arg) :extra-args))
:ret (s/tuple (t/tv :r) (t/tv :w))))
swap-vals!)
;; clojure.core/atom
;(tu/is-valid ::atom atom) ;;FIXME fails in CI
(tu/is-invalid ::atom (comp atom str))
(tu/is-invalid ::atom (comp #(doto % (reset! "a")) atom))
)