diff --git a/docs/pyinterop.rst b/docs/pyinterop.rst index b511a67a..29d8ef18 100644 --- a/docs/pyinterop.rst +++ b/docs/pyinterop.rst @@ -267,6 +267,12 @@ Type hints may be applied to :lpy:form:`def` names, function arguments and retur Python Decorators ----------------- +.. note:: + + Users wishing to apply decorators to functions are not limited to using ``:decorators`` metadata. + This feature is provided primarily to simplify porting Python code to Basilisp. + In Python, decorators are syntactic sugar for functions which return functions, but given the rich library of tools provided for composing functions and the ease of defining anonymous functions in Basilisp, the use of ``:decorators`` is not typically necessary in standard Basilisp code. + Python decorators are functions that modify the behavior of other functions or methods. They are applied to a function by prefixing it with the ``@decorator_name`` syntax. A decorator takes a function as input, performs some action, and returns a new function that typically extends or alters the original function's behavior. @@ -299,7 +305,7 @@ These decorators are applied from right to left, similar to how Python decorator ((fn ^{:decorators [add-5-decorator]} seven [] 7)) ;; => 12 - ;;; Decorators with arguments, and order of application + ;;; Decorators with arguments, and order of application (right to left) ;; ;; example decorator (defn mult-x-decorator @@ -325,11 +331,6 @@ These decorators are applied from right to left, similar to how Python decorator (asyncio/run (six)) ;; => 13 -.. note:: - - Users wishing to apply decorators to functions are not limited to using ``:decorators`` metadata. - The ``:decorators`` feature is provided primarily to simplify porting Python code to Basilisp. - In Python, decorators are syntactic sugar for functions which return functions, but given the rich library of tools provided for composing functions and the ease of defining anonymous functions in Basilisp, the use of ``:decorators`` is not typically necessary in standard Basilisp code. .. _arithmetic_division: Arithmetic Division diff --git a/src/basilisp/core.lpy b/src/basilisp/core.lpy index 9a636840..303880db 100644 --- a/src/basilisp/core.lpy +++ b/src/basilisp/core.lpy @@ -6004,6 +6004,12 @@ decorators and the ``comp`` function, decorators are applied to the generated function from right to left. + .. note:: + + The ``name`` metadata (i.e., ``(fn ^{...} ...)``) takes + precedence over the ``form`` metadata (i.e., ``^{...} (fn ...)``) + when both specify the same key. + Function argument vectors support sequential and associative :ref:`destructuring` . See :lpy:form:`fn` for more details." diff --git a/tests/basilisp/test_core_macros.lpy b/tests/basilisp/test_core_macros.lpy index 884c75eb..a80ad352 100644 --- a/tests/basilisp/test_core_macros.lpy +++ b/tests/basilisp/test_core_macros.lpy @@ -8,24 +8,30 @@ (testing "decorators" (testing "in form meta" (let [add-5% #(fn [] (+ (%) 5)) - f1 ^{:decorators [add-5%]} (fn [] 7)] + f1 ^{:decorators [add-5%]} (fn [] 7)] (is (= 12 (f1))))) (testing "in fn name meta" (let [add-5% #(fn [] (+ (%) 5)) - f2 (fn ^{:decorators [add-5%]} f2 [] 13)] + f2 (fn ^{:decorators [add-5%]} f2 [] 13)] (is (= 18 (f2))))) + (testing "in both form and name meta" + (let [add-2% #(fn [] (+ (%) 2)) + add-7% #(fn [] (+ (%) 7)) + f3 ^{:decorators [add-2%]} (fn ^{:decorators [add-7%]} f3 [] 20)] + (is (= 27 (f3))))) + (testing "with single arg" (let [add-x% (fn [x] #(fn [] (+ (%) x))) - f3 (fn ^{:decorators [(add-x% 10)]} f3 [] 7)] - (is (= 17 (f3))))) + f4 (fn ^{:decorators [(add-x% 10)]} f4 [] 7)] + (is (= 17 (f4))))) (testing "order" - (let [add-5% #(fn [] (+ (%) 5)) + (let [add-5% #(fn [] (+ (%) 5)) mult-x% (fn [x] #(fn [] (* (%) x))) - fvar (defn f4 {:decorators [add-5% (mult-x% -1)]} [] 9)] - (is (= -4 (f4))))))) + f5 ^{:decorators [add-5% (mult-x% -1)]} (fn [] 9)] + (is (= -4 (f5))))))) (deftest defn-test (testing "single arity defn"