[comp.lang.misc] definitions

gudeman@cs.arizona.edu (David Gudeman) (04/27/91)

There seems to be a certain entropy operating in comp.lang.misc: first
a lot of the hot air gets generated over misunderstandings because
people are using different definitions for terms.  Then some
definitions get posted and everyone uses the same terminology for a
month or so.  Then new posters start appearing who haven't seen the
original defs and recreate the misunderstandings.  This seems to have
happened in the typing debates, so I'm going to post definitions
again.

I've added definitions for binding as well as typing since there seems
to have been some confusion over that as well.  I for one didn't even
know that binding was part of the debate :-).  Each definition is
given in a formal version, followed by an implementation description
for those who don't like formalism.  It should be remembered though
that the formalism is the definition and the implementation
description is only one way (the most common way) to implement the
formalism.

I've decided to be a little more explicit about the fact that typing
refers to machine representations, since that seems to be the major
difference between the two extreme views.  In other words, if typing
only refers to an arbitrary set of values, then most of the
differences of opinion disappear.

Typing: the machine representation of a value.  You must know the
typing of a memory location to know how to interpret the bits as a
value.

Static typing: the assignment of a typing to all the values that a
given syntactic expression might produce.  This is generally
implemented by having the programmer declare the typings of the
variables, and then inferring the typing of compound expressions by the
types of the operations.

Dynamic typing: a programming language feature where the typing of a
value can be determined from the value alone, without reference to the
way in which the value is used.  This is generally implemented by
adding a type tag to all values at runtime.  Note that since the sizes
of values are not known statically, some form of automatic storage
management is needed to implement dynamic typing.

Strong typing: the feature that an operation cannot return an
undefined result because it did not know the typing of one of its
operands.  Strong static typing is implemented by only allowing
operators to be applied to operands whose typing can be statically
inferred to be correct for that operator.  Strong dynamic typing is
implemented by having each operator dynamically check the type tags of
its operands to make sure they are correct.

Weak typing: the lack of strong typing.  Generally, this means that
when you call an operation on a value with an unrecognized typing, the
operator will return some strange result or core dump.

Static binding: the operation represented by a given name or symbol is
determined by the program text alone.  The simplest way to implement
this is to make sure each token represents a unique operation.  Some
languages allow a token to represent different operations as long as
the correct operation can be uniquely determined by considering the
static typing.

Dynamic binding: the operation represented by a given expression
cannot be determined by text alone -- it depends on the execution of
the program.  Usually the dynamic choice of operation is made based on
dynamic typing tags.
--
					David Gudeman
gudeman@cs.arizona.edu
noao!arizona!gudeman

rockwell@socrates.umd.edu (Raul Rockwell) (04/29/91)

I mostly agree with the recent posts giving definitions of things like
dynamic/static typing, ...  But I think the definitions given for
Strong typing were a bit cloudy.

David Gudeman  []
[] Strong typing: the feature that an operation cannot return an
[] undefined result because it did not know the typing of one of its
[] operands.

Strong typing also means that the function will terminate.

[] Strong static typing is implemented by only allowing operators to
[] be applied to operands whose typing can be statically inferred to
[] be correct for that operator.
[] Strong dynamic typing is implemented by having each operator
[] dynamically check the type tags of its operands to make sure they
[] are correct.

Note that checking type tags, without checking operand values is not
adequate for all cases.  This is why you cannot statically insure that
an inverse function is being applied to operands which are correct for
that function (or operator).

Darren New ::
:: Strong typing: values of the wrong type cannot be stored into
:: accessors (i.e., lvalues, function parameters, etc)

I believe this is static typing, not strong typing.

:: and functions may not be applied to values outside of their domain
:: without a compiletime or runtime error.

This, however, is strong typing.

:: (Note: a catchable runtime error (or exception), like "message not
:: understood" in Smalltalk, is not a runtime error. A non-catchable
:: error, like "new" running out of space in Pascal, is a runtime
:: error.)

Talk about foggy explanations ;-)

Maybe we need to define "error" ?

:: Values of the wrong type are assumed to possibly have incompatible
:: representations; i.e., valid integers may not be valid floats, etc.

"assumed to possibly" ???

I suppose this could mean that you can have an integer bignum which is
too large to represent using floating point notation in some
implementation of a language???

In any event, I don't think this is a meaningful way of describing
strong typing.

Raul Rockwell

hrubin@pop.stat.purdue.edu (Herman Rubin) (04/29/91)

I was of the opinion that strong typing meant that objects (bit patterns in
memory, registers, discs, etc.) of one type could not be used as objects of
another type.  As someone who has deliberately used this of course highly
non-portable feature often, it is this aspect to which I object.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907-1399
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet)   {purdue,pur-ee}!l.cc!hrubin(UUCP)

rockwell@socrates.umd.edu (Raul Rockwell) (04/29/91)

Herman Rubin:
>  I was of the opinion that strong typing meant that objects (bit patterns in
>  memory, registers, discs, etc.) of one type could not be used as objects of
>  another type.  As someone who has deliberately used this of course highly
>  non-portable feature often, it is this aspect to which I object.

It is entirely possible to define a function of the form
	pun(to_type, from_type, source_object)

All versions of this are portable, but defining such a function so
that it is efficient on one machine does not always mean that it is
efficient on another machine.  In the general case (arbitrary types,
arbitrary platform) you will need to copy the object when you change
its type.

Tomas Breuel:
>  Dynamically typed programs are also impossible to prove type-correct,
>  and many trivial errors go unchecked.

This is true when you are using a statically typed language (which
does not provide support of dynamically typed programs).  This is not
true in general, however.

On the hunch you've killed the subject thread where we've been
discussing this, I will repeat:

 You can implement static typing in a dynamically typed language by
 introducing "functions" which do no processing but which have limited
 domains.  These functions are equivalent to type declarations.

 In a well-written program, in a well-designed language, you should not
 _usually_ need such a function.  All primitive functions of the language
 should have such functionality built-in.

Raul Rockwell

new@ee.udel.edu (Darren New) (04/30/91)

In article <333124@socrates.umd.edu> rockwell@socrates.umd.edu (Raul Rockwell) writes:
>I think the definitions given for >Strong typing were a bit cloudy.
>Strong typing also means that the function will terminate.

Excuse me?  Any language implementing while loops has functions which
won't terminate, strong typing or not.  Or do you mean it will terminate
when passed values of the wrong type?

>Note that checking type tags, without checking operand values is not
>adequate for all cases.  

Nor is it in static typing.  

>Darren New ::
>:: Strong typing: values of the wrong type cannot be stored into
>:: accessors (i.e., lvalues, function parameters, etc)
>I believe this is static typing, not strong typing.

No.  Static typing is when you know what types of values are supposed
to be stored into variables.  For example, old K&R C (or old FORTRAN)
allows integers to be passed into float parameters of functions.
Hence, even tho these languages are statically typed (because each
syntactic expression (e.g., variable) has a certain type), they are
not strongly typed because the language does not guarantee that
there won't be type errors.  Similarly with printf().

Contrast this with Pascal, where function calls and writeln() calls
cannot cause the wrong type values to be stored into properly-declared
variables.

>:: and functions may not be applied to values outside of their domain
>:: without a compiletime or runtime error.
>This, however, is strong typing.

I disagree.  If I convert assignment to a function call, does this change
the fundamental strength of the typing system?  Preventing wrong-type
assignments is just as strong or dynamic as preventing invalid
function calls.

>:: (Note: a catchable runtime error (or exception), like "message not
>:: understood" in Smalltalk, is not a runtime error. A non-catchable
>:: error, like "new" running out of space in Pascal, is a runtime
>:: error.)
>Talk about foggy explanations ;-)
>Maybe we need to define "error" ?

My point is that if you have an exception-handling mechanism that
the programmer can use to catch "message not understood" errors, then
one cannot really say that the behavior of a function generating a
message-not-understood is "undefined".  Something that aborts the
program without giving the program a chance to clean up could be
considered a runtime error.  Undetected errors are also "errors".

>:: Values of the wrong type are assumed to possibly have incompatible
>:: representations; i.e., valid integers may not be valid floats, etc.
>"assumed to possibly" ???

Merely meaning that the strong vs weak distinction is moot if there
is only one type of value.

>In any event, I don't think this is a meaningful way of describing
>strong typing.

So how would you describe it clearly  and concisely?

-- 
--- Darren New --- Grad Student --- CIS --- Univ. of Delaware ---
----- Network Protocols, Graphics, Programming Languages, FDTs -----
+=+ Nails work better than screws, when both are driven with hammers +=+

yodaiken@chelm.cs.umass.edu (victor yodaiken) (04/30/91)

In article <52164@nigel.ee.udel.edu> new@ee.udel.edu (Darren New) writes:
>Excuse me?  Any language implementing while loops has functions which
>won't terminate, strong typing or not.  Or do you mean it will terminate

Not necessarily. Only if we allow "types" that are not well-founded.
And, why we would want to do that in a computer programming language
is beyond me.

>My point is that if you have an exception-handling mechanism that
>the programmer can use to catch "message not understood" errors, then
>one cannot really say that the behavior of a function generating a
>message-not-understood is "undefined".  Something that aborts the
>program without giving the program a chance to clean up could be
>considered a runtime error.  Undetected errors are also "errors".
>

Not undefined, but not well defined. i.e. f(x) = { g(x) or unroll
                                                   program state ...}
Not very nice.

tmb@ai.mit.edu (Thomas M. Breuel) (04/30/91)

   T[h]omas Breuel:
   >  Dynamically typed programs are also impossible to prove type-correct,
   >  and many trivial errors go unchecked.

   This is true when you are using a statically typed language (which
   does not provide support of dynamically typed programs).  This is not
   true in general, however.

Dynamic typing lets you write programs like the following:

  ;;; Scheme
  (define (fermat-conjecture-is-true?) ...)
  (define (f) (if (fermat-conjecture-is-true?) 9 #f))
  (define (g) (+ (f) 1))
  (g)

Now, you cannot determine statically whether this program is
type-correct (i.e., whether this program will never give you
a runtime type error).

A statically typed language will simply not allow you to
write such functions:

  (* SML *)
  fun f () = if fermat_conjecture_is_true_p() then 9 else false
  ---> type error

In order to express the same concept in a statically typed
language like SML, you have to use unions:

  (* SML *)
  datatype bool_or_int = BOOL of bool | INT of int;
  fun f () = if fermat_conjecture_is_true_p() then INT(9) else BOOL(false)
  ---> f: unit -> bool_or_int

In essence, you are introducing a little bit of dynamic typing into
the statically typed language.

   You can implement static typing in a dynamically typed language by
   introducing "functions" which do no processing but which have limited
   domains.  These functions are equivalent to type declarations.

You can write:

  ;;; Scheme
  (define (NUMBER-+ x y)
    (if (not (and (number? x) (number? y))) (error "number+")
        (+ x y)))

  (define (DOUBLE x) (NUMBER-+ 'a 'b))

However, this does not give you static typing, since the Scheme
compiler is not required to check statically whether all uses of
NUMBER-+ satisfy the type constraints. In fact, in most cases, it
cannot even determine the type correctness of your program statically
because of language semantics. For example, in the above example, the
compiler cannot flag a type error for the function DOUBLE because
NUMBER-+ could have been rebound by the time DOUBLE is called.

Static typing is added functionality in the compiler. If you want to,
you can use dynamic typing on top of a statically typed language, but
the converse is not true.

  In a well-written program, in a well-designed language, you should not
  _usually_ need such a function.  All primitive functions of the language
  should have such functionality built-in.

I disagree. It is very useful to be able to flag the type error in the
function DOUBLE shown above at compile time. DOUBLE may be called only
very rarely, so that it doesn't get detected on testing, but the
runtime type error might "make your airplane crash".

Trivial type errors like this occur even in well-written programs, and
cannot be caught by many well-designed dynamically typed languages
(like Scheme) at compile time.

						Thomas.

olson@juliet.ll.mit.edu ( Steve Olson) (05/01/91)

In article <TMB.91Apr29182914@volterra.ai.mit.edu> tmb@ai.mit.edu (Thomas M. Breuel) writes:
   Static typing is added functionality in the compiler. If you want to,
   you can use dynamic typing on top of a statically typed language, but
   the converse is not true.

Perhaps this statement is correct in many specific cases, but its not
correct in general.  Common Lisp supports a wide variety of compile-time
type declarations.  The definition of CL does not force an implementation to
use the declarations, but the major UNIX CL implementations do use the 
declarations.  The CL compiler I use (Lucid) is much better at using the
decls for optimization than for error checking, but this undoubtably will
improve in the future.

This lead to s semi-related pet observation of mine --

In general, type errors are quite rare when programming in a Lisp enviroment.
How many times do I confuse a pathanme with a array?  How many times do I 
confuse a number and a window?  N-E-V-E-R.  But a funny thing started happening
when I started to optimize the inner loops of some of my CL programs ...
I started getting type errors.  Getting a integer and a float confused or
a single and a double confused is something that does happen quite a bit.
To make matters worse, my compiler isn't too great at detecting these types of
errors.  In this situation I do need static type checking.

My contention is that a typical statically typed language causes type errors
by forcing the programmer to make micro-decisions about storage layout and
machine representation of data.  Sometimes you may want to do this for
efficiency, but often its a needless burden.

--
-- Steve Olson
-- MIT Lincoln Laboratory
-- olson@juliet.ll.mit.edu
--

mathew@mantis.co.uk (mathew) (05/02/91)

yodaiken@chelm.cs.umass.edu (victor yodaiken) writes:
> In article <52164@nigel.ee.udel.edu> new@ee.udel.edu (Darren New) writes:
> >Excuse me?  Any language implementing while loops has functions which
> >won't terminate, strong typing or not.  Or do you mean it will terminate
> 
> Not necessarily. Only if we allow "types" that are not well-founded.

So in what way is

function f() :=
   while true do-nothing
   return

using a type which is not well founded?

For that matter, what about   function f() := f()  ?


mathew

-- 
mathew - mathew@mantis.co.uk or mcsun!ukc!ibmpcug!mantis!mathew

yodaiken@chelm.cs.umass.edu (victor yodaiken) (05/03/91)

In article <2494@optima.cs.arizona.edu> gudeman@cs.arizona.edu (David Gudeman) writes:
>I've decided to be a little more explicit about the fact that typing
>refers to machine representations, since that seems to be the major
>difference between the two extreme views.  In other words, if typing
>only refers to an arbitrary set of values, then most of the
>differences of opinion disappear.
>
>Typing: the machine representation of a value.  You must know the
>typing of a memory location to know how to interpret the bits as a
>value.
>

Oh, well, here's the problem. To me a "type" is not necessarily a
machine-related notion. The "type" of a mathematical object refers to the
operations which are meaningful on the object and the laws which govern
the behavior of the object. For example "1" can be an element of a boolean
algebra, the identity element of a group, an integer, or an abbreviation
for the textual symbol "successor(zero())".  Depending on the type which
we assign to "1" we will interpret "1+1" differently.  

>Static typing: the assignment of a typing to all the values that a
>given syntactic expression might produce.  This is generally
>implemented by having the programmer declare the typings of the
>variables, and then inferring the typing of compound expressions by the
>types of the operations.
>
>Dynamic typing: a programming language feature where the typing of a
>value can be determined from the value alone, without reference to the
>way in which the value is used.  This is generally implemented by
>adding a type tag to all values at runtime.  Note that since the sizes
>of values are not known statically, some form of automatic storage
>management is needed to implement dynamic typing.
>


>Strong typing: the feature that an operation cannot return an
>undefined result because it did not know the typing of one of its
>operands.  Strong static typing is implemented by only allowing
>operators to be applied to operands whose typing can be statically
>inferred to be correct for that operator.  Strong dynamic typing is
>implemented by having each operator dynamically check the type tags of
>its operands to make sure they are correct.
>

In fact, "dynamic typing" as you have defined it, forbids strong
typing unless we are willing to allow for "bad type" aborts and to 
consider these to be well defined results.