Subject: Re: static, dynamic and implicitely typed languages
From: (Rob Warnock)
Date: Tue, 14 Oct 2008 03:07:09 -0500
Newsgroups: comp.lang.lisp
Message-ID: <>
Rainer Joswig  <> wrote:
| (Rob Warnock) wrote:
| > Chris Barts  <> wrote:
| > +---------------
| > | You can also explicitly declare the types of variables,
| > | as in this function: ...
| > +---------------
| > 
| > To really get the maximum speed, you have to be able to assure the
| > compiler that the *result* of multiplying B by 2 will also still be
| > a FIXNUM. If you *are* sure of that, then you can tell a CL compiler
| > about it this way:
| > 
| >   (defun foo (a b c)
| >      (declare (type number a)
| >               (type fixnum b)
| >               (type cons c))
| >      (cons (+ a (the fixnum (* 2 b))) c))
| > 
| > As you note, this may not be of much benefit, since the compiler
| > will still have to use fully-generic "+" when adding "A"...  :-{
| But see this (simplifying your example):

[Chris Barts's example, actually...]

| (defun foo (a b)
|   (declare (type number a)
|            (type fixnum b))
|   (+ a (the fixnum (* 2 b))))

That's just what I wrote above, less the CONS with C.

| (defun bar (a b c)
|   (declare (type fixnum a b c)
|            (inline foo))
|   (the fixnum (+ a (foo b c))))

But A was given in the original example as a NUMBER, *not* a FIXNUM!
You can't just change the rules in the middle like that.

| Which can be seen as something like this:
| (defun foobar (a b c)
|   (declare (type fixnum a b c))
|   (the fixnum (+ a (+ b (the fixnum (* 2 c))))))
| So the type of the arguments gets propagated into inlined functions.
| So, FOO may use a generic +. But BAR may use a FIXNUM +
| in the inlined code of FOO.

(*sigh*) Even if you change the rules so that A is a FIXNUM
(not a NUMBER), your re-write *still* isn't correct unless
you *know* that the intermediate sums are all still FIXNUMs!!
As it stands above, you're lying to the compiler. Even if you
*know* that the final result (+ A (+ B (THE FIXNUM (* 2 C))))
is a FIXNUM, you *DON'T* know [or, if you do know, you
haven't yet promised the compiler] that the intermediate sum
(+ B (THE FIXNUM (* 2 C))) is a FIXNUM. Consider what happens
when C is positive, B is MOST-POSITIVE-FIXNUM, and A is a
negative FIXNUM less than (- (* 2 C)). The sum with B will
push the intermediate result into a BIGNUM [*expensive!*],
but the sum with A will bring it back into the FIXNUM range.

But if you *know* that can't happen, you could tell the
compiler about it and make the code faster still:

    (defun foobar (a b c)
      (declare (type fixnum a b c))
      (the fixnum (+ a (the fixnum (+ b (the fixnum (* 2 c)))))))

But in these kinds of cases it might be better to just tell
the compiler the actual value ranges of the variables, and
then you don't have to sprinkle THE around all over the place
[if the compiler's type propagation is smart enough], e.g.:

    (defun foobar (a b c)
      (declare (type (integer -1000 1000) a b)
	       (type (integer -500 500) c))
      (+ a b (* 2 c)))  ; *Must* be (INTEGER -3000 3000), so no THE needed.


p.s. If you compile the latter with (SAFETY 0) in CMUCL, it will
even eliminate the range checks on the args, giving this code with
all the ops inlined (on x86):

    48AEE540:   .ENTRY "LAMBDA (A B C)"(a b c) ; (FUNCTION
                                               ;  ((INTEGER -1000 1000) ..))
      58:       POP     DWORD PTR [EBP-8]
      5B:       LEA     ESP, [EBP-32]

      5E:       MOV     EBX, EDX             ; [:NON-LOCAL-ENTRY]

      60:       LEA     EDX, [EBX+EDI]       ; No-arg-parsing entry point
                                             ; [:NON-LOCAL-ENTRY]
      63:       LEA     EAX, [ESI*2]
      6A:       ADD     EDX, EAX

      6C:       MOV     ECX, [EBP-8]         ; [:BLOCK-START]
      6F:       MOV     EAX, [EBP-4]
      72:       ADD     ECX, 2
      75:       MOV     ESP, EBP
      77:       MOV     EBP, EAX
      79:       JMP     ECX

Rob Warnock			<>
627 26th Avenue			<URL:>
San Mateo, CA 94403		(650)572-2607