Why does Clojure have 5 ways to define a class instead of just one?

随声附和 提交于 2019-11-28 13:45:50

问题


Clojure has gen-class, reify, proxy and also deftype and defrecord to define new class-like datatypes. For a language that values syntactic simplicity and abhors unnecessary complexity, it seems like an aberration. Could someone explain why it is so? Could Common Lisp-style defclass have sufficed?


回答1:


This is a mix of three different factors:

  1. The particular type system of the jvm
  2. The need for slightly different semantics for different use cases when defining types
  3. The fact that some of these were developed earlier, and some later, as the language has evolved.

So first, let's consider what these do. deftype and gen-class are similar in that they both define a named class for ahead-of-time compilation. Gen-class came first, followed by deftype in clojure 1.2. Deftype is preferred, and has better performance characteristics, but is more restrictive. A deftype class can conform to an interface, but cannot inherit from another class.

Reify and proxy are both used to dynamically create an instance of an anonymous class at runtime. Proxy came first, reify came along with deftype and defrecord in clojure 1.2. Reify is preferred, just as deftype is, where the semantics are not too restrictive.

That leaves the question of why both deftype and defrecord, since they appeared at the same time, and have a similar role. For most purposes, we will want to use defrecord: it has all the various clojure goodness that we know and love, sequability and so forth. Deftype is intended for use as a low level building block for the implementation of other datastructures. It doesn't include the regular clojure interfaces, but it does have the option of mutable fields (though this isn't the default).

For further reading check out:

The clojure.org datatypes page

The google group thread where deftype and reify were introduced




回答2:


The short answer is that they all have different and useful purposes. The complexity is due to the need to interoperate effectively with different features of the underlying JVM.

If you don't need any Java interop then 99% of the time you are best off sticking with either defrecord or a simple Clojure map.

  • Use defrecord if you want to use protocols
  • Otherwise a regular Clojure map is probably simplest and most understandable

If your needs are more complex, then the following flowchart is a great tool for explaining why you would choose one of these options over the others:

http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/



来源:https://stackoverflow.com/questions/7142495/why-does-clojure-have-5-ways-to-define-a-class-instead-of-just-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!