Public Vars

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))
  )