From: deech
Subject: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <1171049680.613663.251840@l53g2000cwa.googlegroups.com>
Hi all,
I am new to Lisp and dynamic types. I have always programmed in
languages with static type checking Java and more recently Ocaml and
Haskell (which takes this concept to extremes). I am now checking out
Lisp, Smalltalk and Forth. I decided to learn lisp because it has the
best support.

I have looked at working Lisp programs and noticed that a lot of the
code is "if" statements to make sure that a function has received the
proper input. Most C programs seem to be written in this way too. It
seems to result in less readable code. Am I thinking about the program
in the wrong way? Should I not be thinking in terms of types at all?

I read a Best Practices book on Smalltalk and it never addressed this
issue.

Thanks for the help....
Deech

From: Zach Beane
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <m364abp1am.fsf@unnamed.xach.com>
"deech" <············@gmail.com> writes:

> I have looked at working Lisp programs and noticed that a lot of the
> code is "if" statements to make sure that a function has received the
> proper input.

That isn't my experience with typical Lisp code. What working Lisp
programs are you examining? Perhaps your sample isn't very
representative.

Zach
From: Pillsy
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <1171055783.399682.186390@v33g2000cwv.googlegroups.com>
On Feb 9, 2:40 pm, Zach Beane <····@xach.com> wrote:
> "deech" <············@gmail.com> writes:

> > I have looked at working Lisp programs and noticed that a lot of the
> > code is "if" statements to make sure that a function has received the
> > proper input.

> That isn't my experience with typical Lisp code. What working Lisp
> programs are you examining? Perhaps your sample isn't very
> representative.

ISTR one of the Lisp texts I read (Shapiro's, maybe?) tended to
emphasize use of typecases and such in order to due type checking of
arguments and raise more specific error messages. Haven't seen much of
it anywhere else, though.

Cheers, Pillsy
From: Ken Tilton
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <896zh.47$UD.26@newsfe12.lga>
deech wrote:
> Hi all,
> I am new to Lisp and dynamic types. I have always programmed in
> languages with static type checking Java and more recently Ocaml and
> Haskell (which takes this concept to extremes). I am now checking out
> Lisp, Smalltalk and Forth. I decided to learn lisp because it has the
> best support.
> 
> I have looked at working Lisp programs and noticed that a lot of the
> code is "if" statements to make sure that a function has received the
> proper input.

What has "if" got to do with type-checking? And how does type-checking 
tell you that input is "proper" in any way other than type?

Did you mean you found (if (typep...) do something)? That would be 
dispatching on (varying functionality by) type, not error-checking, and 
suggest the code was written before CLOS caught on or by a person who 
does not like CLOS (and generic functions).

You better post some code next time, this makes no sense. Even if you 
found someone saying (if (typep..) (do-soemthing) (error "bad arg!!!")), 
hey that's their problem, few Lispniks work that way. Conversely, if you 
love the validation of arg checking and miss it in CL, just write a 
defun-typed macro that accepts types with parameters and expands into so 
many assertions so they at least get checked at runtime.

Your whole premise is whether Lisp has to be written a certain way, and 
that itself misses a huge point about Lisp: you can write any kind of 
garbage in any kind of paradigm you like.

ken


-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Alan Crowe
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <86lkj7oupt.fsf@cawtech.freeserve.co.uk>
"deech" <············@gmail.com> writes:

> Hi all,
> I am new to Lisp and dynamic types. I have always programmed in
> languages with static type checking Java and more recently Ocaml and
> Haskell (which takes this concept to extremes). I am now checking out
> Lisp, Smalltalk and Forth. I decided to learn lisp because it has the
> best support.
> 
> I have looked at working Lisp programs and noticed that a lot of the
> code is "if" statements to make sure that a function has received the
> proper input. Most C programs seem to be written in this way too. It
> seems to result in less readable code. Am I thinking about the program
> in the wrong way? Should I not be thinking in terms of types at all?

That doesn't sound right to me. Common Lisp has macro
specifically for this job, so you might write

> (defun add (x y)
    (check-type x integer)
    (check-type y rational)
    (+ x y))
ADD

> (add 1 1/2)
3/2

> (add 1/2 1)
; Evaluation aborted

but the usual idea is to declare types, and make type
checking a matter of compilation policy. With CMUCL the
interpreter just ignores the type information

CL-PROMPT>>> (defun add (x y)
               (declare (integer x)
                        (rational y))
               (+ x y))
ADD

CL-PROMPT>>> (add 1/2 1)
3/2

But the default settings for the compiler take the
declarations as requests by the programmer for type checks
that signal type errors.

CL-PROMPT>>> (compile 'add)
; Compiling LAMBDA (X Y): 
; Compiling Top-Level Form: 
ADD
NIL
NIL

CL-PROMPT>>> (add 1/2 1)
; Evaluation aborted

The alternative is for the compiler to take the declarations
as promises by the programming which the compiler is to
trust and use to produce faster code.

There is a natural progression. Once the code works and no
longer contains type errors, one recompiles with the second
policy and obtains an improvement in performance.

Alan Crowe
Edinburgh
Scotland
From: Rob Warnock
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <h5OdncnenK8GulLYnZ2dnUVZ_s6onZ2d@speakeasy.net>
Alan Crowe  <····@cawtech.freeserve.co.uk> wrote:
+---------------
| ...but the usual idea is to declare types, and make type
| checking a matter of compilation policy. With CMUCL the
| interpreter just ignores the type information...
+---------------

But given that the OP is a newbie, one should point out that in
CMUCL (as with several other CLs), there is *both* a full compiler
and a (half-compiling) interpreter available to the user at all
times; interpreted code may call compiled code and vice-versa.

And while "the CMUCL interpreter just ignores the type information",
the CMUCL compiler very much does *not* ignore it, but treats it as
a promise by the programmer[1] that the types will be as declared --
which often allows *much* more efficient compiled code to be generated
but risks snot demons[2] if the programmer's promise is violated.


-Rob

[1] In ANSI Common Lisp, unlike most other languages, type declarations
    are not requests by the programmer asking the compiler to check
    the types, but rather are promises *by* the programmer *to* the
    compiler that the the declarations will be satisfied at runtime:
    
	http://alu.org/HyperSpec/Body/sec_3-3.html>.
	3.3 Declarations
	...
	The consequences are undefined if a program violates a
	declaration or a proclamation. 

[2] One of the possible outcomes of anything in Common Lisp for
    which the ANSI standard says "the consequences are undefined".
    It is frequently noted that such undefined behavior could range
    from "nothing" to "42" to "a core dump" to "snot demons flying
    out of your nose" to "starting a thermonuclear war".[3]

[3] Any similarity to the plot of the movie "Wargames" (1983)
    <http://en.wikipedia.org/wiki/WarGames> is purely coincidental.
    Really. (And if you believe that, I have this bridge...)

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: deech
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <1171221997.210259.124920@v45g2000cwv.googlegroups.com>
Thank you all,
I really appreciate the help and I feel confident what with such a
knowledgeable community helping out, that Lisp is a great language to
work with.

Cheers,
Deech
From: Rainer Joswig
Subject: Re: I am new to Lisp and Dynamic Type Checking
Date: 
Message-ID: <2007020923241116807-joswig@lispde>
On 2007-02-09 20:34:40 +0100, "deech" <············@gmail.com> said:

> Hi all,
> I am new to Lisp and dynamic types. I have always programmed in
> languages with static type checking Java and more recently Ocaml and
> Haskell (which takes this concept to extremes). I am now checking out
> Lisp, Smalltalk and Forth. I decided to learn lisp because it has the
> best support.
> 
> I have looked at working Lisp programs and noticed that a lot of the
> code is "if" statements to make sure that a function has received the
> proper input. Most C programs seem to be written in this way too. It
> seems to result in less readable code. Am I thinking about the program
> in the wrong way? Should I not be thinking in terms of types at all?
> 
> I read a Best Practices book on Smalltalk and it never addressed this
> issue.
> 
> Thanks for the help....
> Deech


In Common Lisp you apply functions to objects.

The function takes arguments (zero or more).
These arguments may need to be of some types to make sense.
Example: (SIN "foo")   <-  you would guess that "foo" is not of the 
right argument type.

? (SIN "foo")
> Error: value "foo" is not of the expected type REAL.


If you write your functions, how would you express that arguments 
should be of some type in Common Lisp?

What would you may want to achieve:

* the code should be readable and self documenting
* the code should be as little code as possible
* the code should reuse standard facilities for type checking and error 
handling
* the code should not cause your Lisp system to crash
* the code should not make debugging more difficult
* the code should be testable
* the code should give the user some useful feedback
* the code should not be much slower due to added checks
* the code should be changeable at runtime

Here are five different approaches:

1) Naming

(defun my-sin (a-real-number)
  (sin a-real-number))

? (my-sin "foo")
> Error: value "foo" is not of the expected type REAL.
> While executing: CCL::%SHORT-FLOAT, in process listener(1).


Problem: the error is signalled somewhere in SIN and not within your function.

Usually you would hope that your Lisp system can recover from those 
errors and that you can get some meaningful backtrace to locate the 
problem.

2) Homegrown runtime type checking.

(defun my-sin (a-real-number)
  (if (typep a-real-number 'real)
    (sin a-real-number)
    (error "~a is not a real number" a-real-number)))

? (my-sin "foo")
> Error: foo is not a real number
> While executing: MY-SIN, in process listener(1).


3) Builtin standard runtime type checking using CHECK-TYPE.

(defun my-sin (a-real-number)
  (check-type a-real-number real)
  (sin a-real-number))

? (my-sin "foo")
> Error: value "foo" is not of the expected type REAL.
> While executing: MY-SIN, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.

You also get an additional restart (Assing a new value ...) with this version.

1 > :r
   (:C <n>) can be used to invoke one of the following restarts in this 
break loop:
0. Return to break level 1.
1. #<RESTART ABORT-BREAK #xE384CD>
2. Assign a new value of type REAL to A-REAL-NUMBER
3. Return to toplevel.
4. #<RESTART ABORT-BREAK #xE389DD>
5. Reset this process
6. Kill this process


4) Use methods.

(defmethod my-sin ((n real))
    (sin n))

? (my-sin "foo")
> Error: No applicable method for args:
>         ("foo")
>         to #<STANDARD-GENERIC-FUNCTION MY-SIN #x300040DA0D1F>
> While executing: #<CCL::STANDARD-KERNEL-METHOD NO-APPLICABLE-METHOD 
(T)>, in process listener(1).

Above version is similar to the Smalltalk situation, where you could 
send a message to an object and where the object might not understand 
the message. In this case Common Lisp cannot find a method given that 
you have called MY-SIN with a string.



5) Use non-standard static type checking (here using the SBCL compiler).

(defun my-sin (a-real-number)
  (declare (type real a-real-number))
  (sin a-real-number))

(defun foo (a)
  (my-sin (concatenate 'string a "-baz")))


* (compile-file "/tmp/test.lisp")

; compiling file "/tmp/test.lisp" (written 09 FEB 2007 11:03:38 PM):
; compiling (DEFUN MY-SIN ...)
; compiling (DEFUN FOO ...)
; file: /tmp/test.lisp
; in: DEFUN FOO
;     (MY-SIN (CONCATENATE 'STRING A "-baz"))
;
; note: deleting unreachable code
;
; caught WARNING:
;   Asserted type REAL conflicts with derived type
;   (VALUES (OR (SIMPLE-ARRAY * (*)) (AND SEQUENCE (NOT VECTOR))) &OPTIONAL).
;   See also:
;     The SBCL Manual, Node "Handling of Types"


Also: if your function would do different things based on the types of 
inputs, you also have several choices:

1) use IF or COND and check the types and select the code to run
2) use TYPECASE or ETYPECASE
3) write methods for the various types with DEFMETHOD.
4) retrieve a new function based on the type of the input and invoke it.
5) Convert the input to some other type and reinvoke the function.
6) Change the class of the object to some other class and reinvoke the 
function.
...