`specify!` and `set!` silently fail if object is not extensible

Description

Per https://ask.clojure.org/index.php/12898/specify-and-set-silently-fail-if-object-is-not-extensible

specify! implicitly relies on the provided object to be extensible so that protocol implementations can be provided. Here is a quick demonstration from a REPL.

cljs.user> (def obj #js {:current nil}) [#js {:current nil}] cljs.user> (js/Object.preventExtensions obj) {"current" nil} cljs.user> (specify! obj IDeref (-deref [^js this] (.-current this))) {"current" nil}

Note that reify does not document this requirement either. This leads to confusing situations where non-extensible objects returned by JavaScript libraries (e.g. React) are unable to be extended and the user has little clue why.

Similarly, set! silently fails when objects are not extensible.

cljs.user> (set! (.-foo obj) "bar") "bar" cljs.user> obj {"current" nil}

goog.object/set is able to detect this and throw an error.

cljs.user> (goog.object/set obj "foo" "bar") Execution error (TypeError) at (<cljs repl>:1). Cannot add property foo, object is not extensible :repl/exception!

Environment

None

Activity

Show:

Details

Assignee

Reporter

Priority

Created May 30, 2023 at 2:41 PM
Updated September 27, 2023 at 9:23 PM

Flag notifications