summaryrefslogtreecommitdiff
path: root/README.md
blob: 418f3dab1ffcfed8dff1d81e163dde3349813f48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# `def`

A stupid project to dull the pain of using a few of CL's built-in `def*` forms.

## `def:var`

Isn't it annoying that, if you want to leave a `defvar`-defined
special variable uninitialized at the top-level, then you're not
allowed to give that variable a docstring? 

Sure, you can always 

    (setf (documentation *my-speical* 'variable) "oh good, docs")
    
but that's irritating too.

Enter `def:var`


    (def:var *oh-so-special* :doc "It's oh-so-special")
    
Of course, you may still initialize the variable:

    (def:var *oh-so-special* :init (random 10) :doc "It's oh-so-special")
    
## `def:const` 

Even more obnoxious is the behavior of `defconst` whenever you `C-c
C-c` in SLIME. You nearly always find yourself invoking a `CONTINUE`
restart when, according to common sense, you should not have had to.

Well no more! 

    (def:const +its-ten+ 10 "It's just the number 10")
    
If you re-evaluate that form, then nothing annoying happens. Of
course, the form still expands out to `defconstant` so that a
condition signals whenever you try to `setf` the name. 

## `def:class`

Admittedly, this one is less justfifed. There's already the extremely
elaborate `defclass/std` in the `defclass-std` system available
through quicklisp.  But I think `defclass/std` is a little *too*
thorough and ends up getting in its own way.

The case for using a macro like this is that, well, most classes are
defined in a very repetitive way.  This macro just saves you some
work:

    (def:class pt () 
      (x y z :prefix :type real :initform 0)
      (uuid :ro :type integer :initform (make-uuid) :documentation "A unique ID")
      :documentation "A point in real 3d space")
      
The above would expand out into

    (DEFCLASS PT NIL
      ((X :ACCESSOR PT-X :INITARG :X :TYPE REAL :INITFORM 0)
       (Y :ACCESSOR PT-Y :INITARG :Y :TYPE REAL :INITFORM 0)
       (Z :ACCESSOR PT-Z :INITARG :Z :TYPE REAL :INITFORM 0)
       (UUID :READER UUID :INITARG :UUID :TYPE INTEGER :INITFORM
             (MAKE-UUID) :DOCUMENTATION "A unique ID"))
      (:DOCUMENTATION "A point in real 3d space"))
      
See `def:class`'s docstring for details.

## `def:fast` 

Common Lisp compilers like SBCL can produce extremely fast code
... if, that is, you help them out a little.  

Declaring types and `optimize` declare expressions can be a little
verbose and irritating to add to every function that you want to be
fast.  

`def:fast` lightens some of the typing load by embedding types inside
the lambda list, and by declaring the return type of functions.  E.g.:


    (defun list-of-fixnum-p (xs)
      (and (listp xs) (every #'sb-int:fixnump xs)))
    
    (deftype list-of-fixnum ()
      '(satisfies list-of-fixnum-p))
    
    (def:fast sum-fixnum ((x fixnum) (y fixnum) &rest (xs list-of-fixnum)) -> fixnum
      "Sums fixnums"
      (+ x y (reduce #'+ xs)))
    

The above expands into

    (DEFUN SUM-FIXNUM (X Y &REST XS)
      "Sums fixnums"
      (DECLARE (TYPE LIST-OF-FIXNUM XS)
               (TYPE FIXNUM Y X)
               (VALUES FIXNUM)
               (OPTIMIZE (SPEED 3) (SAFETY 0)))
      (+ x y (REDUCE #'+ XS)))