Share your thoughts in the 2021 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

Python has a data structure called Decorator, which allows changes to functionality without modifying the resource's structure. It's really helpful if you need to change a behaviour during runtime.

Some references:
https://python.org/dev/peps/pep-0318/
https://www.datacamp.com/community/tutorials/decorators-python

I did some searching and I didn't see any similar data structure to this in Clojure. Is there any other resource available that would have the same effect?

Thanks!

2 Answers

+2 votes
by

Decorators are not a data structure. It's an unnecessary syntax sugar that was implemented just to make some code a tiny bit more readable, that's it.
And you can't use them to change something in runtime unless you rely on some global variables or introduce some other referential opaqueness.

With that being said, a way to achieve the exact same functionality but maybe without some special sugar is available in any language that treats functions as first-class citizens.

The tutorial that you linked gives this example:

@split_string
@uppercase_decorator
def say_hi():
    return 'hello there'

And the most similar way to implement it in Clojure would be something like

(def say-hi (comp
             split-string 
             uppercase-decorator
             (fn [] "hello there")))

Although I would just wrap it all in a single function, which is much simpler in Clojure because there's no return statement that can appear anywhere, like there is in Python:

(defn say-hi []
  (-> "hello there"
    uppercase-decorator
    split-string))
0 votes
by

I completely agree with Eugene. Just for the sake of completeness I want to add that you can also write a macro which can simulate expected behaviour.

(defmacro with-decorators
  [decorators fname & body]
  `(def ~fname (comp ~@(reverse decorators) (fn ~@body))))

(require '[clojure.string :as s])

(with-decorators
  ;; decorators
  [s/upper-case #(s/split % #"\s+")]
  ;; function definition as in `defn`
  say-hi []
  "hello there")

(say-hi)
;; => ["HELLO" "THERE"]
...