The next function we’re describing is upgraded-array-element-type. This function takes a type specifier and returns another type specifier. So, let’s talk about Lisp type specifiers a bit. There are the expected ones for floating-point numbers, integers, complex numbers, and many more non-numeric types. The programmer can also declare certain variables to be within a specified sub-range of the intrinsic numeric types. For example, a variable can be declared as holding integers between 7 and 23, very much like the “subrange” types in the Pascal programming language. The programmer might, however, be interested to know how that variable is stored in an array, where multiple objects of the same type might be laid out contiguously in memory. The upgraded-array-element-type returns the most specific intrinsic type capable of holding the supplied type. It allows the programmer to query the implementation and determine what intrinsic types are available. I’ll post an example below.
This is a different perspective on data than that supplied in C++ by the stdint.h header file. There, the programmer chooses types based on the minimum range that the variable is to hold and the desired tradeoff between speed and space. The Lisp standard does not define something equivalent to, say uint_fast16_t, which might expand to different types on a 16-bit CPU and a 32-bit CPU, at the discretion of the implementation(s).
So, an example of the use of upgraded-array-element-type on SBCL 1.1.14:
CL-USER> (upgraded-array-element-type '(integer 7 23)) (UNSIGNED-BYTE 7) CL-USER> (upgraded-array-element-type '(integer 0 1)) BIT CL-USER> (upgraded-array-element-type '(integer -128 127)) (SIGNED-BYTE 8) CL-USER> (upgraded-array-element-type '(integer 0 1000000)) (UNSIGNED-BYTE 31) CL-USER> (upgraded-array-element-type '(integer 0 3000000000)) (UNSIGNED-BYTE 32) CL-USER> (upgraded-array-element-type '(double-float 0.0d0 2.0d0)) DOUBLE-FLOAT