source: project/wiki/man/5/Types @ 37594

Last change on this file since 37594 was 37594, checked in by Kooda, 15 months ago

man/5/Types: Add new CHICKEN 5 number types (bignum, ratnum, cplxnum, integer)

File size: 13.7 KB
Line 
1[[tags: manual]]
2[[toc:]]
3
4
5=== Types
6
7A dynamically typed language like Scheme does not restrict the type of
8values bound or assigned to variables to be constant troughout the
9run-time of a program. This provides a lot of flexibility and makes it
10easy to get code up and running quickly, but can make maintenance of
11larger code bases more difficult as the implicit assignment of types
12to variables done by the programmer has to be "recovered" when the
13code is inspected or debugged again. Statically typed languages
14enforce distinct types for all variables, optionally providing
15type-inference to compute types without requiring the user to specify
16explicit type declarations in many cases.
17
18If the compiler has some knowledge of the types of local or global
19variables then it can help in catching type-related errors like
20passing a value of the wrong type to a user-defined or built-in
21procedure. Type-information also can be used to generate more
22efficient code by omitting unnecessary type-checks.
23
24CHICKEN provides an intra-procedural flow-analysis pass and two
25compiler options for using type-information in this manner:
26
27{{-specialize}} will replace certain generic library procedure calls
28with faster type-specific operations.
29
30{{-strict-types}} makes type-analysis more optimistic and gives
31more opportunities for specialization, but may result in unsafe
32code if type-declarations are violated.
33
34Note that the interpreter will always ignore type-declarations
35and will not perform any flow-analysis of interpreted code.
36
37
38==== Declaring types
39
40Type information for all core library units is available by default.
41User-defined global variables can be declared to have a type using
42the {{(declare (type ...))}} or {{:}} syntax.
43
44All syntax described hereafter is exported from the {{(chicken type)}}
45module.
46
47
48===== :
49
50<syntax>(: IDENTIFIER TYPE)</syntax>
51
52Declares that the global variable {{IDENTIFIER}} is of the given type.
53
54
55===== the
56
57<syntax>(the TYPE EXPRESSION)</syntax>
58
59Equivalent to {{EXPRESSION}}, but declares that the result will be of the
60given type. Note that this form always declares the type of a single result,
61{{the}} can not be used to declare types for multiple result values. {{TYPE}}
62should be a subtype of the type inferred for {{EXPRESSION}}, the compiler
63will issue a warning if this should not be the case.
64
65
66===== assume
67
68<syntax>(assume ((VARIABLE TYPE) ...) BODY ...)</syntax>
69
70Declares that at the start of execution of {{BODY ..}}, the variables will
71be of the given types. This is equivalent to
72
73<enscript hightlight=scheme>
74(let ((VARIABLE (the TYPE VARIABLE)) ...)
75  BODY ...)
76</enscript>
77
78
79===== define-type
80
81<syntax>(define-type NAME TYPE)</syntax>
82
83Defines a type-abbreviation {{NAME}} that can be used in place of
84{{TYPE}}.  Type-abbreviations defined inside a module are not visible
85outside of that module.
86
87
88==== Type syntax
89
90Types declared with the {{type}} declaration (see [[Declarations]])
91or {{:}} should follow the syntax given below:
92
93<table>
94<tr><th>TYPE</th><th>meaning</th></tr>
95<tr><td>{{deprecated}}</td><td>any use of this variable will generate a warning</td></tr>
96<tr><td>{{(deprecated NAME)}}</td><td>generate a warning and advise alternative NAME</td></tr>
97<tr><td>VALUETYPE</td><td></td></tr>
98</table>
99
100<table> 
101<tr><th>VALUETYPE</th><th>meaning</th></tr>
102<tr><td>{{(or VALUETYPE ...)}}</td><td>"union" or "sum" type</td></tr>
103<tr><td>{{(not VALUETYPE)}}</td><td>non-matching type (*)</td></tr>
104<tr><td>{{(struct STRUCTURENAME)}}</td><td>record structure of given kind</td></tr>
105<tr><td>{{(procedure [NAME] (VALUETYPE ... [#!optional VALUETYPE ...] [#!rest [VALUETYPE]]) . RESULTS)}}</td><td>procedure type, optionally with name</td></tr>
106<tr><td>{{(VALUETYPE ... [#!optional VALUETYPE ...] [#!rest [VALUETYPE]] -> . RESULTS)}}</td><td>alternative procedure type syntax</td></tr>
107<tr><td>{{(VALUETYPE ... [#!optional VALUETYPE ...] [#!rest [VALUETYPE]] --> . RESULTS)}}</td><td>procedure type that is declared not to modify locally held state</td></tr>
108<tr><td>{{(VALUETYPE -> VALUETYPE : VALUETYPE)}}</td><td>predicate procedure type</td></tr>
109<tr><td>{{(forall (TYPEVAR ...) VALUETYPE)}}</td><td>polymorphic type</td></tr>
110<tr><td>COMPLEXTYPE</td><td></td></tr>
111<tr><td>BASICTYPE</td><td></td></tr>
112<tr><td>TYPEVAR</td><td>{{VARIABLE}} or {{(VARIABLE TYPE)}}</td></tr>
113</table>
114
115<table>
116<tr><th>BASICTYPE</th><th>meaning</th></tr>
117<tr><td>{{*}}</td><td>any value</td></tr>
118<tr><td>{{bignum}}</td><td>arbitrary precision integer</td></tr>
119<tr><td>{{blob}}</td><td>byte vector</td></tr>
120<tr><td>{{boolean}}</td><td>true or false</td></tr>
121<tr><td>{{char}}</td><td>character</td></tr>
122<tr><td>{{cplxnum}}</td><td>complex number</td></tr>
123<tr><td>{{eof}}</td><td>end-of-file object</td></tr>
124<tr><td>{{false}}</td><td>boolean false</td></tr>
125<tr><td>{{fixnum}}</td><td>word-sized integer</td></tr>
126<tr><td>{{float}}</td><td>floating-point number</td></tr>
127<tr><td>{{integer}}</td><td>exact integer (either fixnum or bignum)</td></tr>
128<tr><td>{{list}}</td><td>null or pair</td></tr>
129<tr><td>{{locative}}</td><td>locative object</td></tr>
130<tr><td>{{null}}</td><td>empty list</td></tr>
131<tr><td>{{number}}</td><td>fixnum or float</td></tr>
132<tr><td>{{pair}}</td><td>pair</td></tr>
133<tr><td>{{pointer-vector}}</td><td>vector or native pointers</td></tr>
134<tr><td>{{pointer}}</td><td>native pointer</td></tr>
135<tr><td>{{input-port}} {{output-port}}</td><td>input- or output-port</td></tr>
136<tr><td>{{procedure}}</td><td>unspecific procedure</td></tr>
137<tr><td>{{ratnum}}</td><td>rational number</td></tr>
138<tr><td>{{string}}</td><td>string</td></tr>
139<tr><td>{{symbol}}</td><td>symbol</td></tr>
140<tr><td>{{true}}</td><td>boolean true</td></tr>
141<tr><td>{{vector}}</td><td>vector</td></tr>
142</table>
143
144<table>
145<tr><th>COMPLEXTYPE</th><th>meaning</th></tr>
146<tr><td>{{(pair TYPE1 TYPE2)}}</td><td>pair with given component types</td></tr>
147<tr><td>{{(list-of TYPE)}}</td><td>proper list with given element type</td></tr>
148<tr><td>{{(list TYPE1 ...)}}</td><td>proper list with given length and element types</td></tr>
149<tr><td>{{(vector-of TYPE)}}</td><td>vector with given element types</td></tr>
150<tr><td>{{(vector TYPE1 ...)}}</td><td>vector with given length and element types</td></tr>
151</table>
152
153<table> 
154<tr><th>RESULTS</th><th>meaning</th></tr>
155<tr><td>{{*}}</td><td>any number of unspecific results</td></tr>
156<tr><td>{{(RESULTTYPE ...)}}</td><td>specific number of results with given types</td></tr>
157</table>
158
159<table> 
160<tr><th>RESULTTYPE</th><th>meaning</th></tr>
161<tr><td>{{undefined}}</td><td>a single undefined result</td></tr>
162<tr><td>{{noreturn}}</td><td>procedure does not return normally</td></tr>
163<tr><td>VALUETYPE</td><td></td></tr>
164</table>
165
166(*) Note: no type-variables are bound inside {{(not TYPE)}}.
167
168Note that type-variables in {{forall}} types may be given "constraint" types, i.e.
169
170  (: sort (forall (e (s (or (vector-of e) (list-of e))))
171            (s (e e -> *) -> s)))
172
173declares that {{sort}} is a procedure of two arguments, the first
174being a vector or list of an undetermined element type {{e}} and the
175second being a procedure that takes two arguments of the element type.
176The result of {{sort}} is of the same type as the first argument.
177
178Some types are internally represented as structure types, but you can also use
179these names directly in type-specifications - {{TYPE}} corresponds to
180{{(struct TYPE)}} in this case:
181
182<table> 
183<tr><th>Structure type</th><th>meaning</th></tr>
184<tr><td>{{u8vector}}</td><td>SRFI-4 byte vector</td></tr>
185<tr><td>{{s8vector}}</td><td>SRFI-4 byte vector</td></tr>
186<tr><td>{{u16vector}}</td><td>SRFI-4 byte vector</td></tr>
187<tr><td>{{s16vector}}</td><td>SRFI-4 byte vector</td></tr>
188<tr><td>{{u32vector}}</td><td>SRFI-4 byte vector</td></tr>
189<tr><td>{{s32vector}}</td><td>SRFI-4 byte vector</td></tr>
190<tr><td>{{u64vector}}</td><td>SRFI-4 byte vector</td></tr>
191<tr><td>{{s64vector}}</td><td>SRFI-4 byte vector</td></tr>
192<tr><td>{{f32vector}}</td><td>SRFI-4 byte vector</td></tr>
193<tr><td>{{f64vector}}</td><td>SRFI-4 byte vector</td></tr>
194<tr><td>{{thread}}</td><td>SRFI-18 thread</td></tr>
195<tr><td>{{environment}}</td><td>evaluation environment</td></tr>
196<tr><td>{{time}}</td><td>SRFI-18 "time" object</td></tr>
197<tr><td>{{continuation}}</td><td>continuation object</td></tr>
198<tr><td>{{lock}}</td><td>lock object from "posix" unit</td></tr>
199<tr><td>{{condition}}</td><td>object representing exception</td></tr>
200<tr><td>{{hash-table}}</td><td>SRFI-69 hash-table</td></tr>
201<tr><td>{{tcp-listener}}</td><td>listener object from "tcp" unit</td></tr>
202</table>
203
204Additionally, some aliases are allowed:
205
206<table>
207<tr><th>Alias</th><th>Type</th></tr>
208<tr><td>{{any}}</td><td>{{*}}</td></tr>
209<tr><td>{{immediate}}</td><td>{{(or eof null fixnum char boolean)}}</td></tr>
210<tr><td>{{port}}</td><td>{{(or input-port output-port)}}</td></tr>
211<tr><td>{{void}}</td><td>{{undefined}}</td></tr>
212</table>
213
214For portability the aliases {{&optional}} and {{&rest}} are allowed
215in procedure type declarations as an alternative to {{#!optional}} and
216{{#!rest}}, respectively.
217
218
219==== Predicates
220
221Procedure-types of the form {{(DOM -> RNG : TYPE)}} specify that the declared
222procedure will be a predicate, i.e. it accepts a single argument of type
223{{DOM}}, returns a result of type {{RNG}} (usually a boolean) and returns
224a true value if the argument is of type {{TYPE}} and false otherwise.
225
226
227==== Purity
228
229Procedure types are assumed to be not referentially transparent and
230are assumed to possibly modify locally held state. Using the
231{{(... --> ...)}} syntax, you can declare a procedure to not modify
232local state, i.e. not causing any side-effects on local variables or
233data contain in local variables. This gives more opportunities for
234optimization but may not be violated or the results are undefined.
235
236
237==== Using type information in extensions
238
239Type information of declared toplevel variables can be used in client
240code that refers to the definitions in a compiled file. The following
241compiler options allow saving type-declarations to a file and consulting
242the type declarations retained in this manner:
243
244{{-emit-types-file FILENAME}} writes the type-information for all declared
245definitions in an internal format to {{FILENAME}}.
246
247{{-consult-types-file FILENAME}} loads and registers the type-information
248in {{FILENAME}} which should be a file generated though a previous use
249of {{-emit-types-file}}.
250
251If library code is used with {{import}}
252and a {{.types}} file of the same name exists in the
253extension repository path, then it is automatically consulted. This
254allows code using these libraries to take advantage of type-information
255for library definitions.
256
257Note that procedure-definitions in dynamically loaded code that was
258compiled with {{-strict-types}} will not check the types of their
259arguments which will result in unsafe code. Invoking such procedures
260with incorrectly typed arguments will result in undefined program
261behaviour.
262
263
264==== Optimizations done by specialization
265
266If argument types are known, then calls to known library procedures
267are replaced with non-checking variants (if available). Additionally,
268procedure checks can be omitted in cases where the value in operator
269position of a procedure call is known to be a procedure. Performance
270results will vary greatly depending on the nature of the compiled
271code. In general, specialization will not make code that is compiled
272in unsafe mode any faster: compilation in unsafe mode will omit most
273type checks anyway. But specialization can often improve the
274performance of code compiled in safe (default) mode.
275
276Specializations can also be defined by the user:
277
278===== define-specialization
279
280<syntax>(define-specialization (NAME ARGUMENT ...) [RESULTS] BODY)</syntax>
281
282Declares that calls to the globally defined procedure {{NAME}} with
283arguments matching the types given by {{ARGUMENT}}s should be replaced
284by {{BODY}} (a single expression). Each {{ARGUMENT}} should be an
285identifier naming a formal parameter, or a list of the form
286{{(IDENTIFIER TYPE)}}. In the former case, this argument specializes on
287the {{*}} type. If given, {{RESULTS}} (which follows the syntax given
288above under "Type Syntax") adjusts the result types from those
289previously declared for {{NAME}}.
290
291{{NAME}} must have a declared type (for example by using {{:}}). If it
292doesn't, the specialization is ignored.
293
294User-defined specializations are always local to the compilation unit in
295which they occur and cannot be exported. When encountered in the
296interpreter, {{define-specialization}} does nothing and returns an
297unspecified result.
298
299When multiple specializations may apply to a given call, they are
300prioritized by the order in which they were defined, with earlier
301specializations taking precedence over later ones.
302
303There is currently no way of ensuring specializations take place.  You
304can use the {{-debug o}} compiler options to see the total number of
305specializations performed on a particular named function call during
306compilation.
307
308===== compiler-typecase
309
310<syntax>(compiler-typecase EXP (TYPE BODY ...) ... [(else BODY ...)])</syntax>
311
312Evaluates {{EXP}} and executes the first clause which names a type that
313matches the type inferred during flow analysis as the result of {{EXP}}.
314The result of {{EXP}} is ignored and should be a single value. If a
315{{compiler-typecase}} form occurs in evaluated code, or if it occurs in
316compiled code but specialization is not enabled, then it must have
317an {{else}} clause which specifies the default code to be executed
318after {{EXP}}. If no {{else}} clause is given and no {{TYPE}} matches,
319then a compile-time error is signalled.
320
321
322==== Caveats
323
324Assignments make flow-analysis much harder and remove opportunities
325for optimization. Generally you should avoid using a lot of mutations
326of both local variables and data held in local variables. It may
327even make your code do unexpected things when these mutations violate
328type-declarations.
329
330Note that using threads which modify local state makes all
331type-analysis pointless.
332
333---
334Previous: [[Modules]]
335
336Next: [[Declarations]]
Note: See TracBrowser for help on using the repository browser.