I don't mean this as a subjective question -- I am trying to understand why exactly with-meta is in the language. I realize it can be used for many purposes (so can eval, but its use outside specific circumstances is a sign of Bad Design). From a design perspective, what unique purpose does Clojure's metadata structure serve? Is it primarily for documentation? Is it sugar?
What are some strong applications for with-meta/meta? In what cases is it a bad idea? Can you give an example of the use of metadata to do something that would be impossible/difficult/tedious without it?
Several of the core features of the language depend on metadata:
macros one feature that depends on metadata. A macro is a function with a bit of metadata that causes the function to run at compiletime.
user> (meta #'when)
{:macro true,
:ns #<Namespace clojure.core>,
:name when, :arglists ([test & body]),
:column 1, :added "1.0",
:doc "Evaluates test. If logical true, evaluates body in an implicit do.",
:line 471,
:file "clojure/core.clj"}
Types are another feature of the language that depends on metadata. The type of something is expressed as metadata on that object.
tests also use metadata. when you (or lein) call run-tests it looks at the metadata on the functions in each namespace to find the ones that are tests.
There are many more cases ranging from core of the language like types to peripheral things like n-repl/cider displaying the function arguments at the bottom of the screen while you work that use metadata. It is not a design smell to use metadata provided you are not using it to do ugly things of course ;)
Metadata is useful for attaching details to values that don't need it directly. For example, in a web server, you may use metadata for endpoint information on functions (e.g. does calling this function require authentication) and process them in your handler. Ring, for example, uses metadata to check if a session should be recreated.
In addition to what Arthur Ulfeldt mentions above, one of the unique features of Clojure is the use of metadata for extending protocols. This allows you to add protocols dynamically to pretty much any object (actually any value) after it has been created. As far as I am aware, this capability is not available in most other languages (possible exception of Smalltalk).
See Extend via Metadata for more.
Since adding metadata in Clojure does not impact equality semantics, if adding metadata causes your application to mistakenly consider two objects to be equal, you could run into semantic problems. This issue is domain-specific.
Related
In my Clojure project, I am using Clojure Spec but If I need to use some lib like compojure-api then I need to use Schema.
What is the advantage one over the others?
Why would I consider one over the others?
Which one is good for compile type checked?
These are three merely different approaches to give the developer some type safety. All the three offer their own DSL to describe the schema/type of data but they are very different in philosophy. They are all actively maintained and have a nice community.
This is an opinionated overview based of my experiences.
core typed
core typed tries to extend the clojure language with additional macros to annotate functions and vars with static type information. It then uses static type analysis to ensure that the code matches the type info (that is it produces and consumes data of the right types).
Some advantages:
Static typing in general is a very strong tool. If you are familiar with staticly typed programming languages you will appreciate this very much.
Many bugs can be found during compilation time. No more NullPointerExceptions!
Some drawbacks:
Changing something in type or code may require extra work to propagate the changes through all parts of your code. And sometimes it is just too complicated to write type info or correct programs.
Static code checking will slow down your compile times and may slow down your development workflow.
Schema
In Schema you also write type annotations but type checking happens runtime. It encourages you to construct schema declarations dynamically and lets you specify where you want to check for schema and where you do not want its funcionality.
Some advantages:
Very friendly DSL to describe data schema.
Various tools. For example: Data generation for generative testing, tools to explain why a schema does not match.
Some disadvantages:
Only checks for schema where and when you tell it to do so.
External library, not supported by the core team.
Spec
Spec is the latest player with a philosophy borrowed from Racket lang. It is (going to be) part of the Clojure core library from the Clojure version 1.9.
The basic idea is to have entity types specified by the (namespaced) keys in a map object. Spec declarations are stored in the application's registry bound to namespaced keywords. Spec is very strong in sequence validation.
Some advantages:
Part of the Clojure core, not an external library. It is now used for parsing macro arguments and also for documentation purposes.
The community is very excited about it resulting in interesting ideas such as using spec in genetic programming and generative testing.
Some disadvantages:
Will be available in Clojure 1.9 which is not yet a released stable version. It is still a new technology not widely used.
Spec do not look like the data they are describing.
Personally, core.typed feels intimidating and core.spec feels immature so I use schema in production. My advice is the following:
If you need static type checking then core.typed is the way to go.
If you want to do parsing then core.spec is a nice choice.
If you want simple type descriptions then schema will be a good fit.
I'm reading some Clojure code at the moment that has a bunch of uninitialised values as nil for a numeric value in a record that gets passed around.
Now lots of the Clojure libraries treat this as idiomatic. Which means that it is an accepted convention.
But it also leads to NullPointerException, because not all the Clojure core functions can handle a nil as input. (Nor should they).
Other languages have the concept of Maybe or Option to proxy the value in the event that it is null, as a way of mitigating the NullPointerException risk. This is possible in Clojure - but not very common.
You can do some tricks with fnil but it doesn't solve every problem.
Another alternative is simply to set the uninitialised value to a symbol like :empty-value to force the user to handle this scenario explicitly in all the handling code. But this isn't really a big step-up from nil - because you don't really discover all the scenarios (in other people's code) until run-time.
My question is: Is there an idiomatic alternative to nil-punning in Clojure?
Not sure if you've read this lispcast post on nil-punning, but I do think it makes a pretty good case for why it's idiomatic and covers various important considerations that I didn't see mentioned in those other SO questions.
Basically, nil is a first-class thing in clojure. Despite its inherent conventional meaning, it is a proper value, and can be treated as such in many contexts, and in a context-dependent way. This makes it more flexible and powerful than null in the host language.
For example, something like this won't even compile in java:
if(null) {
....
}
Where as in clojure, (if nil ...) will work just fine. So there are many situations where you can use nil safely. I'm yet to see a java codebase that isn't littered with code like if(foo != null) { ... everywhere. Perhaps java 8's Optional will change this.
I think where you can run into issues quite easily is in java interop scenarios where you are dealing with actual nulls. A good clojure wrapper library can also help shield you from this in many cases, and its one good reason to prefer one over direct java interop where possible.
In light of this, you may want to re-consider fighting this current. But since you are asking about alternatives, here's one I think is great: prismatic's schema. Schema has a Maybe schema (and many other useful ones as well), and it works quite nicely in many scenarios. The library is quite popular and I have used it with success. FWIW, it is recommended in the recent clojure applied book.
Is there an idiomatic alternative to nil-punning in Clojure?
No. As leeor explains, nil-punning is idiomatic. But it's not as prevalent as in Common Lisp, where (I'm told) an empty list equates to nil.
Clojure used to work this way, but the CL functions that deal with lists correspond to Clojure functions that deal with sequences in general. And these sequences may be lazy, so there is a premium on unifying lazy sequences with others, so that any laziness can be preserved. I think this evolution happened about Clojure 1.2. Rich described it in detail here.
If you want option/maybe types, take a look at the core.typed library. In contrast to Prismatic Schema, this operates at compile time.
In Clojure, some tasks (such as instantiating a PersistentQueue or using deftype to implement a custom data type that is compatible with the clojure.core functions) require knowledge of the classes and/or interfaces in clojure.lang.
However, according to clojure.lang/package.html:
The only class considered part of the public API is clojure.lang.IFn. All other classes should be considered implementation details.
Are these statements incorrect or outdated? If so, are there plans to correct them in the future? If not, is there a more preferred way to perform the tasks mentioned above, or should they simply not be done at all in idiomatic Clojure code?
Alex Miller has commented on this in the past (the whole thread is worth reading though):
I'd say there is a range of "public"-ness to the internals of Clojure.
The new Clojure API (clojure.java.api.Clojure) is an official public API for external callers of Clojure. This API basically consists of ways to resolve vars and invoke functions.
For Clojure users in Clojure, pretty much any var that's public and has a docstring, and shows up in the api docs can be considered public API.
Clojure vars that are private or have no docstring (such that the var is omitted from public api docs) are likely places to tread very carefully.
The Clojure internal Java interfaces [clojure.lang] are certainly intended to allow library builders to create useful stuff that plays in the Clojure world. I do not know that anyone has ever said that they are "public", but I certainly think that any change to a core interface likely to break external users would be considered very carefully.
The Clojure internal Java classes [clojure.lang] should in most cases be considered private and subject to change without notice. There are grey areas even there.
In general, we do not place a high value on encapsulation or hiding internals. In most cases, the internals are left available if they might be useful to an advanced user doing interesting things, with the caveat that the weirder things you do, the more likely you are to be accidentally broken in a future release.
While defrecord is the preferred form -for the general case- in Clojure for defining an "entity", in ClojureScript one can find far more references to deftype, as reflected in various documentation.
What is the difference between both forms? Which should one prefer?
deftype creates a bare-bones object which implements a protocol.
defrecord creates an immutable persistent map which implements a protocol.
Which to use depends on what you want. Do you want a full ClojureScript data structure? Then use a record. Do you just want a bare-bones thing that does nothing but satisfy a protocol? Then use a type.
The two bits of documentation you reference use types because they're trying to illustrate protocols at the most basic level, and types have less "going on" than records, so to speak.
However, most real-world uses of object-like things in Clojure/ClojureScript need to store fields of data along with the object, and for that you should emphatically use a record, for the same reason you should use any of Clojure's immutable collections.
According to DEFTYPE VS DEFRECORD,
you should distinguish programming constructs and domain constructs.
deftype is for programming constructs and defrecord is for domain constructs that need a custom type.
Hope this helps.
Other than lack of documentation, what is the difference between definterface and defprotocol in Clojure?
According to the Joy of Clojure:
The advantages of using definterface over defprotocol are restricted
entirely to the fact that the former allows primitive types for
arguments and returns. At some point in the future, the same advantage
will likely be extended to the interfaces generated [by protocols], so use
definterface sparingly and prefer protocols unless absolutely
necessary.
My possibly incomplete understanding was definterface produces an interface .class that java code can implement in order to create classes suitable to pass to your Clojure functions.
Protocols are, in short, a faster and more focused way of doing dispatch than multimethods. you actually have running code in a protocol that is used by other clojure code.