Skip to content

Commit 2dffcc0

Browse files
Update alter-var-root to return new val, updated docs (#1171)
Hi, can you please review change to have have `alter-var-root` to return the new value. It addresses #1166. I've also updated various part of the documentation to note the effect of direct linking on this fn. Please feel free to adjust partially or completely. I've also added test cases for the `alter-var-root` for the new change plus to demo the direct linking behavior. Thanks --------- Co-authored-by: ikappaki <[email protected]> Co-authored-by: Chris Rink <[email protected]>
1 parent 66f7773 commit 2dffcc0

File tree

7 files changed

+55
-7
lines changed

7 files changed

+55
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Changed
10+
* `alter-var-root` now returns the new value to align with Clojure behavior. Updated the docstring to highlight side effects of direct linking optimization (#1166)
11+
912
## [v0.3.4]
1013
### Added
1114
* Added support for the optional `attr-map?` on the `ns` macro (#1159)

docs/compiler.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ You can suppress those warnings locally by attaching the ``^:no-warn-on-var-indi
131131

132132
.. note::
133133

134-
Changes to Vars which were direct linked will not be propagated to any code that used the direct link, rather than Var indirection.
134+
Changes to Vars (such as with :lpy:fn:`alter-var-root`) which were direct linked will not be propagated to any code that used the direct link, rather than Var indirection.
135135

136136
.. note::
137137

docs/differencesfromclojure.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ basilisp.core
159159

160160
- :lpy:fn:`basilisp.core/float` coerces its argument to a floating-point number. When given a string input, Basilisp will try to parse it as a floating-point number, whereas Clojure will raise an error if the input is a character or a string.
161161

162+
- :lpy:fn:`basilisp.core/alter-var-root`: updates to a Var’s root via this function may not reflect in code that directly references the Var unless the Var is marked with ``^:redef`` metadata or declared as a dynamic variable. This is due to the :ref:`Direct Linking Optimization <direct_linking>` and differs with Clojure where such changes are always visible.
163+
162164
.. _refs_and_transactions_differences:
163165

164166
Refs and Transactions

src/basilisp/core.lpy

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4735,7 +4735,14 @@
47354735

47364736
(defn alter-var-root
47374737
"Atomically alter the Var root by calling ``(apply f root args)`` and setting the root
4738-
as the result."
4738+
as the result. Returns the new value.
4739+
4740+
.. note::
4741+
4742+
Due to Basilisp's :ref:`Direct Linking Optimization <direct_linking>`, changes to
4743+
a Var's root value may not be reflected in the code unless the Var is dynamic.
4744+
To ensure updates propagate, set the Var's `^:redef` metadata, which disables
4745+
direct linking."
47394746
[v f & args]
47404747
(apply-method v alter-root f args))
47414748

src/basilisp/lang/runtime.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ def _set_root(self, newval) -> None:
309309
self._is_bound = True
310310
self._root = newval
311311
self._notify_watches(oldval, newval)
312+
return newval
312313

313314
@property
314315
def root(self):
@@ -322,9 +323,10 @@ def bind_root(self, val) -> None:
322323

323324
def alter_root(self, f, *args) -> None:
324325
"""Atomically alter the root binding of this Var to the result of calling
325-
f with the existing root value and any additional arguments."""
326+
f with the existing root value and any additional arguments. Returns the
327+
new value."""
326328
with self._lock:
327-
self._set_root(f(self._root, *args))
329+
return self._set_root(f(self._root, *args))
328330

329331
def push_bindings(self, val):
330332
if not self._dynamic or self._tl is None:

tests/basilisp/test_core_fns.lpy

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,14 +1565,16 @@
15651565
(is (= true (realized? fut)))))
15661566

15671567
(testing "timed deref of future"
1568-
(let [fut (future (time/sleep 3))
1568+
(let [pre (time/perf-counter)
1569+
fut (future (time/sleep 3))
15691570
start (time/perf-counter)
15701571
;; block for 100ms
15711572
ret (deref fut 100 :timed-out)
15721573
end (time/perf-counter)
15731574
diff (- end start)]
15741575
(is (= :timed-out ret))
1575-
(is (< 0.1 diff 0.5) (str "deref timeout outside of [100ms, 500ms] range: " diff "ms"))
1576+
(is (< 0.1 diff 0.5) (str "deref timeout outside of [100ms, 500ms] range: " diff "ms"
1577+
" -- :pre " pre " :start " start " :end " end))
15761578
(is (= false (future-cancelled? fut)))
15771579
(is (= false (future-done? fut)))
15781580
;; can't always cancel a sleep-ed Future
@@ -1849,6 +1851,37 @@
18491851
(testing "calling vars"
18501852
(is (= '(1 2) (#'basilisp.core/list 1 2)))))
18511853

1854+
;;;;;;;;;;;;;;;;;;;
1855+
;; Var Utilities ;;
1856+
;;;;;;;;;;;;;;;;;;;
1857+
1858+
(def test-var-unadorned 7)
1859+
(def ^:redef test-var-redef 19)
1860+
(def ^:dynamic test-var-dynamic 23)
1861+
1862+
(deftest test-alter-var-root
1863+
(testing "on unadorned var"
1864+
(is (= 8 (alter-var-root #'test-var-unadorned inc)))
1865+
;; Basilisp Direct Linking Optimization side effect: altering the
1866+
;; root var on variables is not reflected back to the code ...
1867+
(is (= 7 test-var-unadorned))
1868+
;; ... unless the var is referenced explicitly.
1869+
(is (= 8 @#'test-var-unadorned)))
1870+
1871+
(testing "on ^:redef var"
1872+
(is (= 20 (alter-var-root #'test-var-redef inc)))
1873+
;; altering the root is reflected in the code because the variable
1874+
;; was defined with ^:redef.
1875+
(is (= 20 test-var-redef))
1876+
(is (= 20 @#'test-var-redef)))
1877+
1878+
(testing "on dynamic var"
1879+
(is (= 24 (alter-var-root #'test-var-dynamic inc)))
1880+
;; altering the root is reflected in the code because the variable
1881+
;; is dynamic.
1882+
(is (= 24 test-var-dynamic))
1883+
(is (= 24 @#'test-var-dynamic))))
1884+
18521885
;;;;;;;;;;;;;;;;;
18531886
;; Hierarchies ;;
18541887
;;;;;;;;;;;;;;;;;

tests/basilisp/var_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,9 @@ def alter_root(root, *args):
392392
assert alter_args == args
393393
return new_root
394394

395-
v.alter_root(alter_root, *alter_args)
395+
return_value = v.alter_root(alter_root, *alter_args)
396396

397+
assert new_root == return_value
397398
assert new_root == v.root
398399
assert new_root == v.value
399400
assert new_root == v.deref()

0 commit comments

Comments
 (0)