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

Last change on this file since 36260 was 36260, checked in by Kooda, 2 years ago

man/5/Types: touching the file

File size: 13.5 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>{{blob}}</td><td>byte vector</td></tr>
119<tr><td>{{boolean}}</td><td>true or false</td></tr>
120<tr><td>{{char}}</td><td>character</td></tr>
121<tr><td>{{eof}}</td><td>end-of-file object</td></tr>
122<tr><td>{{false}}</td><td>boolean false</td></tr>
123<tr><td>{{fixnum}}</td><td>word-sized integer</td></tr>
124<tr><td>{{float}}</td><td>floating-point number</td></tr>
125<tr><td>{{list}}</td><td>null or pair</td></tr>
126<tr><td>{{locative}}</td><td>locative object</td></tr>
127<tr><td>{{null}}</td><td>empty list</td></tr>
128<tr><td>{{number}}</td><td>fixnum or float</td></tr>
129<tr><td>{{pair}}</td><td>pair</td></tr>
130<tr><td>{{pointer-vector}}</td><td>vector or native pointers</td></tr>
131<tr><td>{{pointer}}</td><td>native pointer</td></tr>
132<tr><td>{{input-port}} {{output-port}}</td><td>input- or output-port</td></tr>
133<tr><td>{{procedure}}</td><td>unspecific procedure</td></tr>
134<tr><td>{{string}}</td><td>string</td></tr>
135<tr><td>{{symbol}}</td><td>symbol</td></tr>
136<tr><td>{{true}}</td><td>boolean true</td></tr>
137<tr><td>{{vector}}</td><td>vector</td></tr>
138</table>
139
140<table>
141<tr><th>COMPLEXTYPE</th><th>meaning</th></tr>
142<tr><td>{{(pair TYPE1 TYPE2)}}</td><td>pair with given component types</td></tr>
143<tr><td>{{(list-of TYPE)}}</td><td>proper list with given element type</td></tr>
144<tr><td>{{(list TYPE1 ...)}}</td><td>proper list with given length and element types</td></tr>
145<tr><td>{{(vector-of TYPE)}}</td><td>vector with given element types</td></tr>
146<tr><td>{{(vector TYPE1 ...)}}</td><td>vector with given length and element types</td></tr>
147</table>
148
149<table> 
150<tr><th>RESULTS</th><th>meaning</th></tr>
151<tr><td>{{*}}</td><td>any number of unspecific results</td></tr>
152<tr><td>{{(RESULTTYPE ...)}}</td><td>specific number of results with given types</td></tr>
153</table>
154
155<table> 
156<tr><th>RESULTTYPE</th><th>meaning</th></tr>
157<tr><td>{{undefined}}</td><td>a single undefined result</td></tr>
158<tr><td>{{noreturn}}</td><td>procedure does not return normally</td></tr>
159<tr><td>VALUETYPE</td><td></td></tr>
160</table>
161
162(*) Note: no type-variables are bound inside {{(not TYPE)}}.
163
164Note that type-variables in {{forall}} types may be given "constraint" types, i.e.
165
166  (: sort (forall (e (s (or (vector-of e) (list-of e))))
167            (s (e e -> *) -> s)))
168
169declares that {{sort}} is a procedure of two arguments, the first
170being a vector or list of an undetermined element type {{e}} and the
171second being a procedure that takes two arguments of the element type.
172The result of {{sort}} is of the same type as the first argument.
173
174Some types are internally represented as structure types, but you can also use
175these names directly in type-specifications - {{TYPE}} corresponds to
176{{(struct TYPE)}} in this case:
177
178<table> 
179<tr><th>Structure type</th><th>meaning</th></tr>
180<tr><td>{{u8vector}}</td><td>SRFI-4 byte vector</td></tr>
181<tr><td>{{s8vector}}</td><td>SRFI-4 byte vector</td></tr>
182<tr><td>{{u16vector}}</td><td>SRFI-4 byte vector</td></tr>
183<tr><td>{{s16vector}}</td><td>SRFI-4 byte vector</td></tr>
184<tr><td>{{u32vector}}</td><td>SRFI-4 byte vector</td></tr>
185<tr><td>{{s32vector}}</td><td>SRFI-4 byte vector</td></tr>
186<tr><td>{{u64vector}}</td><td>SRFI-4 byte vector</td></tr>
187<tr><td>{{s64vector}}</td><td>SRFI-4 byte vector</td></tr>
188<tr><td>{{f32vector}}</td><td>SRFI-4 byte vector</td></tr>
189<tr><td>{{f64vector}}</td><td>SRFI-4 byte vector</td></tr>
190<tr><td>{{thread}}</td><td>SRFI-18 thread</td></tr>
191<tr><td>{{environment}}</td><td>evaluation environment</td></tr>
192<tr><td>{{time}}</td><td>SRFI-18 "time" object</td></tr>
193<tr><td>{{continuation}}</td><td>continuation object</td></tr>
194<tr><td>{{lock}}</td><td>lock object from "posix" unit</td></tr>
195<tr><td>{{condition}}</td><td>object representing exception</td></tr>
196<tr><td>{{hash-table}}</td><td>SRFI-69 hash-table</td></tr>
197<tr><td>{{tcp-listener}}</td><td>listener object from "tcp" unit</td></tr>
198</table>
199
200Additionally, some aliases are allowed:
201
202<table>
203<tr><th>Alias</th><th>Type</th></tr>
204<tr><td>{{any}}</td><td>{{*}}</td></tr>
205<tr><td>{{immediate}}</td><td>{{(or eof null fixnum char boolean)}}</td></tr>
206<tr><td>{{port}}</td><td>{{(or input-port output-port)}}</td></tr>
207<tr><td>{{void}}</td><td>{{undefined}}</td></tr>
208</table>
209
210For portability the aliases {{&optional}} and {{&rest}} are allowed
211in procedure type declarations as an alternative to {{#!optional}} and
212{{#!rest}}, respectively.
213
214
215==== Predicates
216
217Procedure-types of the form {{(DOM -> RNG : TYPE)}} specify that the declared
218procedure will be a predicate, i.e. it accepts a single argument of type
219{{DOM}}, returns a result of type {{RNG}} (usually a boolean) and returns
220a true value if the argument is of type {{TYPE}} and false otherwise.
221
222
223==== Purity
224
225Procedure types are assumed to be not referentially transparent and
226are assumed to possibly modify locally held state. Using the
227{{(... --> ...)}} syntax, you can declare a procedure to not modify
228local state, i.e. not causing any side-effects on local variables or
229data contain in local variables. This gives more opportunities for
230optimization but may not be violated or the results are undefined.
231
232
233==== Using type information in extensions
234
235Type information of declared toplevel variables can be used in client
236code that refers to the definitions in a compiled file. The following
237compiler options allow saving type-declarations to a file and consulting
238the type declarations retained in this manner:
239
240{{-emit-types-file FILENAME}} writes the type-information for all declared
241definitions in an internal format to {{FILENAME}}.
242
243{{-consult-types-file FILENAME}} loads and registers the type-information
244in {{FILENAME}} which should be a file generated though a previous use
245of {{-emit-types-file}}.
246
247If library code is used with {{import}}
248and a {{.types}} file of the same name exists in the
249extension repository path, then it is automatically consulted. This
250allows code using these libraries to take advantage of type-information
251for library definitions.
252
253Note that procedure-definitions in dynamically loaded code that was
254compiled with {{-strict-types}} will not check the types of their
255arguments which will result in unsafe code. Invoking such procedures
256with incorrectly typed arguments will result in undefined program
257behaviour.
258
259
260==== Optimizations done by specialization
261
262If argument types are known, then calls to known library procedures
263are replaced with non-checking variants (if available). Additionally,
264procedure checks can be omitted in cases where the value in operator
265position of a procedure call is known to be a procedure. Performance
266results will vary greatly depending on the nature of the compiled
267code. In general, specialization will not make code that is compiled
268in unsafe mode any faster: compilation in unsafe mode will omit most
269type checks anyway. But specialization can often improve the
270performance of code compiled in safe (default) mode.
271
272Specializations can also be defined by the user:
273
274===== define-specialization
275
276<syntax>(define-specialization (NAME ARGUMENT ...) [RESULTS] BODY)</syntax>
277
278Declares that calls to the globally defined procedure {{NAME}} with
279arguments matching the types given by {{ARGUMENT}}s should be replaced
280by {{BODY}} (a single expression). Each {{ARGUMENT}} should be an
281identifier naming a formal parameter, or a list of the form
282{{(IDENTIFIER TYPE)}}. In the former case, this argument specializes on
283the {{*}} type. If given, {{RESULTS}} (which follows the syntax given
284above under "Type Syntax") adjusts the result types from those
285previously declared for {{NAME}}.
286
287{{NAME}} must have a declared type (for example by using {{:}}). If it
288doesn't, the specialization is ignored.
289
290User-defined specializations are always local to the compilation unit in
291which they occur and cannot be exported. When encountered in the
292interpreter, {{define-specialization}} does nothing and returns an
293unspecified result.
294
295When multiple specializations may apply to a given call, they are
296prioritized by the order in which they were defined, with earlier
297specializations taking precedence over later ones.
298
299There is currently no way of ensuring specializations take place.  You
300can use the {{-debug o}} compiler options to see the total number of
301specializations performed on a particular named function call during
302compilation.
303
304===== compiler-typecase
305
306<syntax>(compiler-typecase EXP (TYPE BODY ...) ... [(else BODY ...)])</syntax>
307
308Evaluates {{EXP}} and executes the first clause which names a type that
309matches the type inferred during flow analysis as the result of {{EXP}}.
310The result of {{EXP}} is ignored and should be a single value. If a
311{{compiler-typecase}} form occurs in evaluated code, or if it occurs in
312compiled code but specialization is not enabled, then it must have
313an {{else}} clause which specifies the default code to be executed
314after {{EXP}}. If no {{else}} clause is given and no {{TYPE}} matches,
315then a compile-time error is signalled.
316
317
318==== Caveats
319
320Assignments make flow-analysis much harder and remove opportunities
321for optimization. Generally you should avoid using a lot of mutations
322of both local variables and data held in local variables. It may
323even make your code do unexpected things when these mutations violate
324type-declarations.
325
326Note that using threads which modify local state makes all
327type-analysis pointless.
328
329---
330Previous: [[Modules]]
331
332Next: [[Declarations]]
Note: See TracBrowser for help on using the repository browser.