Skip to content
sogaiu edited this page Oct 28, 2020 · 6 revisions

Standard Clojure allows use of the symbols int, double, float, etc. in type hints to refer to the corresponding primitive types. ClojureCLR allows this and extends this to the numeric types present in the CLR but not in the JVM: uint, ulong, etc. Similarly, the shorthand array references such ints and doubles work, and are joined by uints, ulongs, etc.

Aside from these special cases, Clojure uses symbols to name types in two ways:

  • a package-qualified symbol (one containing periods internally) is taken to name the Java class with the same character sequence
  • a namespace may contain a mapping from a symbol to a Java class, via import

Resolving a symbol is the process of determining the value of a symbol during evaluation.

Identifying types via symbol names works reasonably well for Java because package-qualified class names are lexically compatible with symbols.

Not so for the CLR. Fully-qualified type names can contain an assembly identifier, which involves spaces and commas. Thus, fully-qualified type names cannot be represented as symbols. Generic type names include angle brackets and backquotes, and thus also are not representable as symbols. In fact, CLR typenames can contain arbitrary characters. Backslashes can escape characters that do have special meaning in the typename syntax (comma, plus, ampersand, asterisk, left and right square bracket, left and right angle bracket, backslash).

ClojureCLR extends the reader syntax for symbols to accommodate CLR type name by the mechanism of vertical bar quoting.

Vertical bars are used in pairs to surround the name (or part of the name) of a symbol that has any special characters (from the standard Clojure symbol viewpoint) in it. For example, |A(B)|, A|(|B|)|, and A|(B)| all mean the symbol whose name consists of the four characters A, (, B, and ).

|anything except a vertical bar...<>@#$@#$#$|

To include a vertical bar in a symbol name that is |-quoted, use a doubled vertical bar.

|This has a vertical bar in the name ...  || ...<>@#$@#$#$|

There is a special interaction of |-quoting with / used to separate namespace from name. Any / appearing |-quoted does not count as a namespace/name separator. Thus,

(namespace 'ab|cd/ef|gh)               ;=> nil
(name 'ab|cd/ef|gh)                    ;=> "abcd/efgh"
(namespace 'ab/cd|ef/gh|ij)            ;=> "ab"
(name 'ab/cd|ef/gh|ij)                 ;=> "cdef/ghij"

Though the vertical bars need only surround troublesome characters, I think it is more readable to quote the entire namespace name and or symbol name. Thus, for the two examples immediately above, you should prefer

|abcd/efgh| instead of ab|cd/ef|gh

ab/|cdef/ghij| instead of ab/cd|ef/gh|ij

With this mechanism we can make a symbol referring to a type such as: (|com.myco.mytype+nested, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b14a123334343434|/DoSomething x y)

or

(reify 
  |AnInterface`2[System.Int32,System.String]| 
  (m1 [x] ...)
  I2
  (m2 [x] ...))

Special note should be made of the proper way to refer to generic types (instantiated or not).

|System.Collections.Generic.IList`1[System.Int32]|

This is the official CLR way of referring to the type that would be referred to in C# (with using) by IList<int>. We do not implement C# or Visual Basic lexical conventions for type names.

Note that you need to specify System.Int32, not just Int32 as the type parameter.

Note: |-quoting defined in ClojureCLR differs from the similar mechanism in CommonLisp in one significant way:

  • CommonLisp allows a literal vertical bar in a symbol name with backslash-escaping: abc\|123 has name “abc|123”. ClojureCLR uses a doubled vertical bar, and only within an |-quoted symbol name. We would write |abc||123| for the symbol with name “abc|123”.

Note: |-quoting prevents characters so quoted from stopping the scan of a token. However, post-scanning steps for violations such as starting with a digit or containing a non-initial colon are still performed.

Note: If printing a symbol with *print-dup* true, a symbol with namespace name or symbol name that contain 'bad' characters will be |-quoted.

Note: To turn off |-quoting just bind the dynamic Var *allow-symbol-escape* to false and invoke the reader.

Clone this wiki locally