When I define a private function in Clojure, I usually use a - prefix as a visual indicator that the function cannot be used outside of my namespace, e.g.
(defn- -name []
(let [formatter (formatter "yyyy-MM-dd-HH-mm-ss-SSSS")]
(format "fixjure-%s" (unparse formatter (now)))))
But the - prefix seems to also be a convention for public methods when using gen-class.
Is there any generally accepted convention for defn-'d functions in the Clojure community, or should I simply use non-prefixed names?
It seems that lots of code in clojure.contrib (may it rest in peace) uses normal names for private functions, so maybe that is best, but I really like the visual indicator--maybe my C / Perl background is just too strong! ;)
There's not a convention; the visual indicator is prevalent in languages with no built-in notion of private functions. Since Clojure's functions defined with defn- are not visible outside their namespace, there is no need to prefix functions with an uglifier ;)
So do what you but, but you should probably want to just do as the rest of community does and just name them normally! It'll make your life easier.
I am unaware of any naming conventions but you can attach ^:private metadata tag for defining private functions. This is exactly equivalent to defn-, but is a little clearer, IMHO.
(defn ^:private foo [])
Related
I found some of the Clojure functions in clojure.core are not documented.
Some of them are private functions. But others like chunk-* and await1 and so on are public but do not have documents. Does that have a specially meaning, or just because of they are new added functions?
Thanks!
The undocumented functions in clojure.core are considered to be part of the implementation, not part of the public interface (so the lack of docstring is intentional). In some cases, undoc'ed functions are called by the expansion of public macros so they must be public.
I'm trying to advise a number of methods in one library with utility functions from another library, where some of the methods to be advised are defined with (defn) and some are defined with (defprotocol).
Right now I'm using this library, which uses (alter-var-root). I don't care which library I use (or whether I hand-roll my own).
The problem I'm running into right now is that protocol methods sometimes can be advised, and sometimes cannot, depending on factors that are not perfectly clear to me.
If I define a protocol, then define a type and implement that protocol in-line, then advising never seems to work. I am assuming this is because the type extends the JVM interface directly and skips the vars.
If, in a single namespace, I define a protocol, then advise its methods, and then extend the protocol to a type, the advising will not work.
If, in a single namespace, I define a protocol, then extend the protocol to a type, then advise the protocol's methods, the advising will work.
What I would like to do is find a method of advising that works reliably and does not rely on undefined implementation details. Is this possible?
Clojure itself doesn't provide any possibilities to advice functions in a reliable way, even those defined via def/defn. Consider the following example:
(require '[richelieu.core :as advice])
(advice/defadvice add-one [f x] (inc (f x)))
(defn func-1 [x] x)
(def func-2 func-1)
(advice/advise-var #'func-1 add-one)
> (func-1 0)
1
> (func-2 0)
0
After evaluation of the form (def func-2 func-1), var func-2 will contain binding of var func-1 (in other words its value), so advice-var won't affect it.
Eventhough, definitions like func-2 are rare, you may have noticed or used the following:
(defn generic-function [generic-parameter x y z]
...)
(def specific-function-1 (partial generic-function <specific-arg-1>))
(def specific-function-2 (partial generic-function <specific-arg-2>))
...
If you advice generic-function, none of specific functions will work as expected due to peculiarity described above.
If advising is critical for you, as a solution that may work, I'd suppose the following: since Clojure functions are compiled to java classes, you may try to replace java method invoke with other method that had desired behaviour (however, things become more complicated when talking about replacing protocol/interface methods: seems that you'll have to replace needed method in every class that implements particular protocol/interface).
Otherwise, you'll need explicit wrapper for every function that you want to advice. Macros may help to reduce boilerplate in this case.
Given that each Clojure namespace corresponds to a file, isn't it the case that a public function, macro, etc. can never be moved out of that file without breaking backward compatibility?
This seems like a surprisingly rigid system--essentially, refactoring of public-facing code can only be done within a single file.
Is there a technical reason for this limitation? Something to do with Java interop, maybe?
You can split a single namespace into multiple files ( see Splitting a Clojure namespace over multiple files ) but it is quite rare to do so. Also you can import-vars using https://github.com/ztellman/potemkin but again this is rarely done in practice. Clojure libraries tend to have relatively small public interfaces, perhaps because they usually operate on common data structures. As such there are rarely files with much code in them.
If you are wanting to preserve backwards compatibility, you can def a var into a namespace (or even within a namespace with a different name), to ensure that any callers will still resolve to the right function.
Functions that are not considered part of the public api can be marked private, which leaves the opportunity for later refactoring without breaking calling code. Any changes to a public api will, of course, risk breaking backwards compatibility and there will a trade off between that breaking change and introducing a new api with redundant functionality.
(ns foo)
;; only visible in the foo ns
(defn- a-private-fn [] ...)
;; only visible in the foo ns
(def ^:private a-private-var BAR 1)
In Clojure, functions that modify their input conventionally end with an ! to warn the user. I even extended this: two !! means that the function has a side effect that modifies something that was not put in (i.e. global states that must persist across user-GUI interactions).
What is the convention for a function that is impure in that it uses an external state, such as file loading, etc?
There is no such convention. Impurity should be apparent from the functions name or docstring or purpose.
Examples:
get-settings-from-file
(get-settings :source :file)
load-configuration
import-data
Metatdata is a useful way to annotate functions that are impure. By convention, I've been labeling functions with an ^:impure marker thusly:
(defn ^:impure blech []
(mq/publish ...)
(spit ...)
(time/now ...)
(http/request ...)
(db/write-something ...))
I tend to only do this to bottom-layer functions. So if bar calls blech, it can be inferred that bar is also impure, and I don't have to pollute every impure function this way.
With this metadata in place, other tools (editors, reports, etc) can assist by indicating that a given function appears to have no impurities all the way down, and you can then see that it's a strong candidate for a unit test (vs those that will need mocking). You can also perform analytics to indicate how much of your code base is trending toward pure.
After defining a record and the interfaces it implements, I can call its methods either by its name or using the java interop way using the dot operator.
user=> (defprotocol Eat (eat [this]))
Eat
user=> (defrecord animal [name] Eat (eat [this] "eating"))
user.animal
user=> (eat (animal. "bob"))
"eating"
user=> (.eat (animal. "bob"))
"eating"
user=>
Under the surface, what is going on there? Are there new clojure functions being defined? What happens when there are functions you defined that share the same name (is this possible?), how are these ambiguities resolved?
Also, is it possible to "import" java methods for other java objects so that you do not need the . operator so that behavior is like above? (For the purpose, for example, of unifying the user interface)
When you define a protocol, each of its methods are created as functions in your current namespaces. It follows that you can't have two protocols defining the same function in the same namespace. It also means that you can have them in separate namespaces and that a given type can extend both[1] of them without any nameclash because they are namespaced (in opposition to Java where a single class can't implement two interfaces with homonymous methods).
From a user perspective, protocol methods are no different from plain old non-polymorphic functions.
The fact that you can call a protocol method using interop is an implementation detail. The reason for that is that for each protocol, the Clojure compiler creates a corresponding backing interface. Later on when you define a new type with inline protocol extensions, then this type will implement these protocols' backing interfaces.
Consequently you can't use the interop form on an object for which the extension hasn't been provided inline:
(defrecord VacuumCleaner [brand model]
(extend-protocol Eat
VacuumCleaner
(eat [this] "eating legos and socks"))
(.eat (VaacumCleaner. "Dyson" "DC-20"))
; method not found exception
The compiler has special support for protocol functions so they are compiled as an instance check followed by a virtual method call, so when applicable (eat ...) will be as fast as (.eat ...).
To reply to "can one import java methods", you can wrap them in regular fns:
(def callme #(.callme %1 %2 %3))
(obviously you may need to add other arities to account for overloads and type hints to remove reflection)
[1] however you can't extend both inline (at least one of them must be in a extend-* form), because of an implementation limitation