Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / July 2006

Tip: Looking for answers? Try searching our database.

What is Expressiveness in a Computer Language

Thread view: 
Xah Lee - 09 Jun 2006 06:04 GMT
in March, i posted a essay What is Expressiveness in a Computer
Language, archived at:
http://xahlee.org/perl-python/what_is_expresiveness.html

I was informed then that there is a academic paper written on this
subject.

On the Expressive Power of Programming Languages, by Matthias
Felleisen, 1990.
http://www.ccs.neu.edu/home/cobbe/pl-seminar-jr/notes/2003-sep-26/expressive-sli
des.pdf


Has anyone read this paper? And, would anyone be interested in giving a
summary?

thanks.

  Xah
  xah@xahlee.org
 http://xahlee.org/
Joe Marshall - 09 Jun 2006 15:34 GMT
> in March, i posted a essay "What is Expressiveness in a Computer
> Language", archived at:
[quoted text clipped - 9 lines]
> Has anyone read this paper? And, would anyone be interested in giving a
> summary?

The gist of the paper is this:  Some computer languages seem to be
`more expressive' than
others.  But anything that can be computed in one Turing complete
language can be computed in any other Turing complete language.
Clearly the notion of
expressiveness isn't concerned with ultimately computing the answer.

Felleisen's paper puts forth a formal definition of expressiveness in
terms of semantic
equivilances of small, local constructs.  In his definition, wholescale
program transformation is
disallowed so you cannot appeal to Turing completeness to claim program
equivalence.

Expressiveness isn't necessarily a good thing.  For instance, in C, you
can express the
addresses of variables by using pointers.  You cannot express the same
thing in Java, and
most people consider this to be a good idea.
Simon Richard Clarkstone - 09 Jun 2006 16:51 GMT
>>On the Expressive Power of Programming Languages, by Matthias
>>Felleisen, 1990.
[quoted text clipped - 10 lines]
> definition, wholescale program transformation is disallowed so you
> cannot appeal to Turing completeness to claim program equivalence.

I suspect that the small, local transformations versus global
transformations is also to do with the practice of not saying the same
thing twice.  Everything from subroutines to LISP macros also helps
here, increasing language expressiveness.

> Expressiveness isn't necessarily a good thing. For instance, in C,
> you can express the addresses of variables by using pointers. You
> cannot express the same thing in Java, and most people consider this
> to be a good idea.

Assuming the more-expressive feature does not preclude the
less-expressive one, good/bad depends on the programmer.  I know *I*
can't be trusted with pointers ;-) , but I know many programmers benefit
greatly from them.  Of course, knowing that the programmer cannot do
something does help the compiler stop you shooting yourself in the foot.

Signature

Simon Richard Clarkstone: s.r.cl?rkst?n?@durham.ac.uk/s?m?n.cl?rkst?n?@
hotmail.com ### "I have a spelling chequer / it came with my PC /
it plainly marks for my revue / Mistake's I cannot sea" ...
by: John Brophy (at: http://www.cfwf.ca/farmj/fjjun96/)

Ken Tilton - 09 Jun 2006 22:27 GMT
>>in March, i posted a essay "What is Expressiveness in a Computer
>>Language", archived at:
[quoted text clipped - 29 lines]
> thing in Java, and
> most people consider this to be a good idea.

Thanks for the summary.

Me, I would like to see a definition of expressiveness that would
exclude a programming mechanism from "things to be expressed".

If the subject is programmer productivity, well, I write programs to get
some behavior out of them, such as operating an ATM cash dispenser. If I
need to keep a list of transactions, I need to express the abstraction
"list" in some data structure or other, but below that level of
abstraction I am just hacking code, not expressing myself -- well, that
is the distinction for which I am arguing.

heck, in this case I will even give you as "thing to express" getting
back multiple values from a function. That comes up all the time, and it
can be an aggravation or a breeze. But then I would score C down because
it does not really return multiple values. One still has some heavy
lifting to do to fake the expressed thing. But I would still give it an
edge over java because Java's fakery would have to be a composite object
-- one could not have a primary return value as the function result and
ancillary values "somewhere else".

kt

Signature

Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
   -- Smiling husband to scowling wife, New Yorker cartoon

Xah Lee - 14 Jun 2006 10:03 GMT
hi Joe,

 Expressiveness isn't necessarily a good thing.  For instance, in C,
you can express the addresses ...

we gotta be careful here, because soon we gonna say binaries are the
most expressive. For instance, in assembly, you can express the
registers and stuff.

Expressiveness, with respect to  for lack of refined terms
semantics, is a good thing, period. When discussing a language's
semantical expressiveness, it goes without saying that a domain
are understood, or needs to be defined. This is almost never mentioned
because it is very difficult. Put it in driveler's chant for better
understanding: we can't compare apples with oranges.

Let me give a example. Let's say i invented a language, where, there's
no addition of numbers, but phaserfy and realify with respective
operators ph and re. So, in my language, to do 1+2, you write ph 1
re ph 2, which means, to phaserfy 1, and phaserfy 2, then realify
their results, which results in 3. Now, this language is the most
expressive, because it can deal with concepts of phaserfy and realify
that no other lang can.

This may seem ridiculous, but is in fact a lot imperative languages do.
I won't go long here, but for instance, the addresses or references of
C and Perl is such. And in Java and few other OOP langs, there's
iterator and enumerator things, are likewise immaterial.

As to OOP's iterator and enumerator things, and the general perspective
of extraneous concepts in languages, i'll have to write a essay in
detail some other day.

----

Thanks for the summary.

Is there no one else who are able to read that paper?

 Xah
 xah@xahlee.org
http://xahlee.org/

> > in March, i posted a essay "What is Expressiveness in a Computer
> > Language", archived at:
> > http://xahlee.org/perl-python/what_is_expresiveness.html
> > ...
> > On the Expressive Power of Programming Languages, by Matthias
> > Felleisen, 1990.

> > http://www.ccs.neu.edu/home/cobbe/pl-seminar-jr/notes/2003-sep-26/expressive-sli
des.pdf

> The gist of the paper is this:  Some computer languages seem to be
> `more expressive' than
[quoted text clipped - 15 lines]
> thing in Java, and
> most people consider this to be a good idea.
Torben Ægidius Mogensen - 14 Jun 2006 14:42 GMT
> > On the Expressive Power of Programming Languages, by Matthias
> > Felleisen, 1990.
[quoted text clipped - 11 lines]
> you cannot appeal to Turing completeness to claim program
> equivalence.

I think expressiveness is more subtle than this.  Basically, it boils
down to: "How quickly can I write a program to solve my problem?".

There are several aspects relevant to this issue, some of which are:

- Compactness: How much do I have to type to do what I want?

- Naturality: How much effort does it take to convert the concepts of
  my problem into the concepts of the language?

- Feedback: Will the language provide sensible feedback when I write
  nonsensical things?

- Reuse: How much effort does it take to reuse/change code to solve a
  similar problem?

Compactness is hard to measure.  It isn't really about the number of
characters needed in a program, as I don't think one-character symbols
instead of longer keywords make a language more expressive.  It is
better to count lexical units, but if there are too many different
predefined keywords and operators, this isn't reasonable either.
Also, the presence of opaque one-liners doesn't make a language
expressible.  Additionally, as mentioned above, Turing-completeness
(TC) allows you to implement any TC language in any other, so above a
certain size, the choice of language doesn't affect size.  But
something like (number of symbols in program)/log(number of different
symbols) is not too bad.  If programs are allowed to use standard
libraries, the identifiers in the libraries should be counted in the
number of different symbols.

Naturality is very difficult to get a grip on, and it strongly depends
on the type of problem you want to solve.  So it only makes sense to
talk about expressiveness relative to a set of problem domains.  If
this set is small, domain-specific languages win hands down, so if you
want to compare expressiveness of general-purpose languages, you need
a large set of very different problems.  And even with a single
problem, it is hard to get an objective measure of how difficult it is
to map the problem's concepts to those of the language.  But you can
normally observe whether you need to overspecify the concept (i.e.,
you are required to make arbitrary decisions when mapping from concept
to data), if the mapping is onto (i.e., can you construct data that
isn't sensible in the problem domain) and how much redundancy your
representation has.

Feedback is a mixture of several things.  Partly, it is related to
naturality, as a close match between problem concepts and language
concepts makes it less likely that you will express nonsense (relative
to the problem domain) that makes sense in the language.  For example,
if you have to code everything as natural numbers, untyped pure lambda
calculus or S-expressions, there is a good chance that you can get
nonsense past the compiler.  Additionally, it is about how difficult
it is to tie an observation about a computed result to a point in the
program.

Measuring reuse depends partly on what is meant by problems being
similar and also on whether you at the time you write the original
code can predict what types of problems you might later want to solve,
i.e., if you can prepare the code for reuse.  Some languages provide
strong mechanisms for reuse (templates, object hierarchies, etc.), but
many of those require that you can predict how the code is going to be
reused.  So, maybe, you should measure how difficult it is to reuse a
piece of code that is _not_ written with reuse in mind.

This reminds me a bit of last years ICFP contest, where part of the
problem was adapting to a change in specification after the code was
written.

> Expressiveness isn't necessarily a good thing.  For instance, in C,
> you can express the addresses of variables by using pointers.  You
> cannot express the same thing in Java, and most people consider this
> to be a good idea.

I think this is pretty much covered by the above points on naturality
and feedback: Knowing the address of a value or object is an
overspecification unless the address maps back into something in the
problem domain.

On a similar note, is a statically typed langauge more or less
expressive than a dynamically typed language?  Some would say less, as
you can write programs in a dynamically typed language that you can't
compile in a statically typed language (without a lot of encoding),
whereas the converse isn't true.  However, I think this is misleading,
as it ignores the feedback issue: It takes longer for the average
programmer to get the program working in the dynamically typed
language.

       Torben
Raffael Cavallaro - 14 Jun 2006 15:51 GMT
> It takes longer for the average
> programmer to get the program working in the dynamically typed
> language.

Though I agree with much of your post I would say that many here find
the opposite to be true - it takes us longer to get a program working
in a statically typed language because we have to keep adding/changing
things to get the compiler to stop complaining and actually compile and
run a program which would be perfectly permissible in a dynamically
typed language such as common lisp - for example - heterogeneous lists
and forward references to as yet non-existent functions.
Joachim Durchholz - 14 Jun 2006 20:04 GMT
Raffael Cavallaro schrieb:

>> It takes longer for the average
>> programmer to get the program working in the dynamically typed
[quoted text clipped - 5 lines]
> things to get the compiler to stop complaining and actually compile and
> run

I think Torben was assuming a language with type inference. You write
only those type annotations that really carry meaning (and some people
let the compiler infer even these).

> a program which would be perfectly permissible in a dynamically
> typed language such as common lisp - for example - heterogeneous lists
> and forward references to as yet non-existent functions.

Um... heterogenous lists are not necessarily a sign of expressiveness.
The vast majority of cases can be transformed to homogenous lists
(though these might then contain closures or OO objects).

As to references to nonexistent functions - heck, I never missed these,
not even in languages without type inference :-)

I don't hold that they are a sign of *in*expressiveness either. They are
just typical of highly dynamic programming environments such as Lisp or
Smalltalk.

Regards,
Jo
Pascal Bourguignon - 14 Jun 2006 21:36 GMT
> Raffael Cavallaro schrieb:
>> a program which would be perfectly permissible in a dynamically
[quoted text clipped - 5 lines]
> homogenous lists (though these might then contain closures or OO
> objects).

In lisp, all lists are homogenous: lists of T.

Signature

__Pascal Bourguignon__                     http://www.informatimago.com/

ADVISORY: There is an extremely small but nonzero chance that,
through a process known as "tunneling," this product may
spontaneously disappear from its present location and reappear at
any random place in the universe, including your neighbor's
domicile. The manufacturer will not be responsible for any damages
or inconveniences that may result.

Raffael Cavallaro - 15 Jun 2006 06:58 GMT
> In lisp, all lists are homogenous: lists of T.

CL-USER 123 > (loop for elt in (list #\c 1 2.0d0 (/ 2 3)) collect
(type-of elt))
(CHARACTER FIXNUM DOUBLE-FLOAT RATIO)

i.e., "heterogenous" in the common lisp sense: having different dynamic
types, not in the H-M sense in which all lisp values are of the single
union type T.
Torben Ægidius Mogensen - 16 Jun 2006 10:04 GMT
> > In lisp, all lists are homogenous: lists of T.
>
[quoted text clipped - 5 lines]
> dynamic types, not in the H-M sense in which all lisp values are of
> the single union type T.

What's the difference?  Dynamically types values _are_ all members of
a single tagged union type.  The main difference is that the tages
aren't always visible and that there are only a fixed, predefined
number of them.

       Torben
Pascal Costanza - 16 Jun 2006 10:47 GMT
>>> In lisp, all lists are homogenous: lists of T.
>> CL-USER 123 > (loop for elt in (list #\c 1 2.0d0 (/ 2 3)) collect
[quoted text clipped - 7 lines]
> What's the difference?  Dynamically types values _are_ all members of
> a single tagged union type.

Yes, but that's mostly a meaningless statement in a dynamically typed
language. In a dynamically typed language, you typically don't care
about the static types.

> The main difference is that the tages
> aren't always visible and that there are only a fixed, predefined
> number of them.

Depending on the language, the number of "tags" is not fixed.

Pascal

Signature

3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/

Raffael Cavallaro - 15 Jun 2006 06:42 GMT
> Um... heterogenous lists are not necessarily a sign of expressiveness.
> The vast majority of cases can be transformed to homogenous lists
[quoted text clipped - 6 lines]
> are just typical of highly dynamic programming environments such as
> Lisp or Smalltalk.

This is a typical static type advocate's response when told that users
of dynamically typed languages don't want their hands tied by a type
checking compiler:

"*I* don't find those features expressive so *you* shouldn't want them."

You'll have to excuse us poor dynamically typed language rubes - we
find these features expressive and we don't want to give them up just
to silence a compiler whose static type checks are of dubious value in
a world where user inputs of an often unpredictable nature can come at
a program from across a potentially malicious internet making run-time
checks a practical necessity.
Joachim Durchholz - 16 Jun 2006 10:22 GMT
Raffael Cavallaro schrieb:

>> Um... heterogenous lists are not necessarily a sign of expressiveness.
>> The vast majority of cases can be transformed to homogenous lists
[quoted text clipped - 10 lines]
>
> "*I* don't find those features expressive so *you* shouldn't want them."

And this is a typical dynamic type advocate's response when told that
static typing has different needs:

"*I* don't see the usefulness of static typing so *you* shouldn't want
it, either."

No ad hominem arguments, please. If you find my position undefendable,
give counterexamples.
Give a heterogenous list that would to too awkward to live in a
statically-typed language.
Give a case of calling nonexistent functions that's useful.
You'll get your point across far better that way.

Regards,
Jo
Sacha - 16 Jun 2006 11:10 GMT
> Raffael Cavallaro schrieb:
>>
[quoted text clipped - 9 lines]
> Give a heterogenous list that would to too awkward to live in a
> statically-typed language.

Many lists are heterogenous, even in statically typed languages.
For instance lisp code are lists, with several kinds of atoms and
sub-lists..
A car dealer will sell cars, trucks and equipment..
In a statically typed language you would need to type the list on a common
ancestor...
What would then be the point of statical typing , as you stilll need to type
check
each element in order to process that list ? Sure you can do this in a
statically-typed
language, you just need to make sure some relevant ancestor exists. In my
experience
you'll end up with the base object-class more often than not, and that's
what i call
dynamic typing.

> Give a case of calling nonexistent functions that's useful.

I might want to test some other parts of my program before writing this
function.
Or maybe will my program compile that function depending on user input.
As long as i get a warning for calling a non-existing function, everything
is fine.

Sacha
Hendrik Maryns - 16 Jun 2006 11:28 GMT
Sacha schreef:
>> Raffael Cavallaro schrieb:
>>>
[quoted text clipped - 24 lines]
> what i call
> dynamic typing.

In my experience you won’t.  I almost never have a List<Object> (Java),
and when I have one, I start thinking on how I can improve the code to
get rid of it.

H.
- --
Hendrik Maryns

==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
Joachim Durchholz - 16 Jun 2006 22:57 GMT
Sacha schrieb:

> Many lists are heterogenous, even in statically typed languages.
> For instance lisp code are lists, with several kinds of atoms and
> sub-lists..

Lisp isn't exactly a statically-typed language :-)

> A car dealer will sell cars, trucks and equipment..
> In a statically typed language you would need to type the list on a common
> ancestor...

Where's the problem with that?

BTW the OO way isn't the only way to set up a list from heterogenous data.
In statically-typed FPL land, lists require homogenous data types all
right, but the list elements aren't restricted to data - they can be
functions as well.
Now the other specialty of FPLs is that you can construct functions at
run-time - you take a function, fill some of its parameters and leave
others open - the result is another function. And since you'll iterate
over the list and will do homogenous processing over it, you construct
the function so that it will do all the processing that you'll later need.

The advantage of the FPL way over the OO way is that you can use ad-hoc
functions. You don't need precognition to know which kinds of data
should be lumped under a common supertype - you simply write and/or
construct functions of a common type that will go into the list.

> What would then be the point of statical typing , as you stilll need to type
> check each element in order to process that list ?

Both OO and FPL construction allow static type checks.

> Sure you can do this in a
> statically-typed
> language, you just need to make sure some relevant ancestor exists. In my
> experience
> you'll end up with the base object-class more often than not, and that's
> what i call dynamic typing.

Not quite - the common supertype is more often than not actually useful.

However, getting the type hierarchy right requires a *lot* of
experimentation and fine-tuning. You can easily spend a year or more
(sometimes *much* more) with that (been there, done that). Even worse,
once the better hierarchy is available, you typically have to adapt all
the client code that uses it (been there, done that, too).

That's the problems in OO land. FPL land doesn't have these problems -
if the list type is just a function mapping two integers to another
integer, reworking the data types that went into the functions of the
list don't require those global changes.

>> Give a case of calling nonexistent functions that's useful.
>
> I might want to test some other parts of my program before writing this
> function.

That's unrelated to dynamic typing. All that's needed is an environment
that throws an exception once such an undefined function is called,
instead of aborting the compilation.

I'll readily admit that very few static languages offer such an
environment. (Though, actually, C interpreters do exist.)

> Or maybe will my program compile that function depending on user input.

Hmm... do I really want this kind of power at the user's hand in the age
of malware?

> As long as i get a warning for calling a non-existing function, everything
> is fine.

That depends.
For software that's written to run once (or very few times), and where
somebody who's able to correct problems is always nearby, that's a
perfectly viable strategy.
For safety-critical software where problems must be handled within
seconds (or an even shorter period of time), you want to statically
ensure as many properties as you can. You'll take not just static
typing, you also want to ascertain value ranges and dozens of other
properties. (In Spark, an Ada subset, this is indeed done.)

Between those extremes, there's a broad spectrum.
Raffael Cavallaro - 16 Jun 2006 16:29 GMT
> And this is a typical dynamic type advocate's response when told that
> static typing has different needs:
>
> "*I* don't see the usefulness of static typing so *you* shouldn't want
> it, either."

But I haven't made this sort of argument. I never said you shouldn't
use static typing if you want to. There are indeed types of software
where one wants the guarantees provided by static type checks. For
example, software that controls irreplaceable or very expensive
equipment such as space craft, or software that can kill people if it
fails such as software for aircraft or medical devices. The problem for
static typing advocates is that most software is not of this type.

There is a very large class of software where user inputs are
unpredictable and/or where input data comes from an untrusted source.
In these cases run-time checks are going to be needed anyway so the
advantages of static type checking are greatly reduced - you end up
doing run-time checks anyway, precisely the thing you were trying to
avoid by doing static analysis. In software like this it isn't worth
satisfying a static type checker because you don't get much of the
benefit anyway and it means forgoing such advantages of dynamic typing
as being able to run and test portions of a program before other parts
are written (forward references to as yet nonexistent functions).

Ideally one wants a language with switchable typing - static where
possible and necessary, dynamic elsewhere. To a certain extent this is
what common lisp does but it requires programmer declarations. Some
implementations try to move beyond this by doing type inference and
alerting the programmer to potential static guarantees that the
programmer could make that would allow the compiler to do a better job.

In effect the argument comes down to which kind of typing one thinks
should be the default. Dynamic typing advocates think that static
typing is the wrong default. The notion that static typing can prove
program correctness is flawed - it can only prove that type constraints
are not violated but not necessarily that program logic is correct. It
seems to me that if we set aside that class of software where safety is
paramount - mostly embedded software such as aircraft and medical
devices - we are left mostly with efficiency concerns. The 80-20 rule
suggests that most code doesn't really need the efficiency provided by
static guarantees. So static typing should be invoked for that small
portion of a program where efficiency is really needed and that dynamic
typing should be the default elswhere. This is how common lisp works -
dynamic typing by default with static guarantees available where one
needs them.
Raffael Cavallaro - 16 Jun 2006 16:37 GMT
> In software like this it isn't worth satisfying a static type checker
> because you don't get much of the benefit
> anywaytext Dx¤description£text Dx¢fromname
> as being able to run and test portions of a program before other parts
> are written (forward references to as yet nonexistent functions).

I don't what bizarre key combination I accidentally hit here, but the
original read:

In software like this it isn't worth satisfying a static type checker
because you don't get much of the benefit anyway and it means forgoing
such advantages of dynamic typing as being able to run and test
portions of a program before other parts are written (forward
references to as yet nonexistent functions).
Raffael Cavallaro - 16 Jun 2006 16:49 GMT
> And this is a typical dynamic type advocate's response when told that
> static typing has different needs:
>
> "*I* don't see the usefulness of static typing so *you* shouldn't want
> it, either."

But I haven't made this sort of argument. I never said you shouldn't
use static typing if you want to. There are indeed types of software
where one wants the guarantees provided by static type checks. For
example, software that controls irreplaceable or very expensive
equipment such as space craft, or software that can kill people if it
fails such as software for aircraft or medical devices. The problem for
static typing advocates is that most software is not of this type.

There is a very large class of software where user inputs are
unpredictable and/or where input data comes from an untrusted source.
In these cases run-time checks are going to be needed anyway so the
advantages of static type checking are greatly reduced - you end up
doing run-time checks anyway, precisely the thing you were trying to
avoid by doing static analysis. In software like this it isn't worth
satisfying a static type checker because you don't get much of the
benefit anyway and it means forgoing such advantages of dynamic typing
as being able to run and test portions of a program before other parts
are written (forward references to as yet nonexistent functions).

Ideally one wants a language with switchable typing - static where
possible and necessary, dynamic elsewhere. To a certain extent this is
what common lisp does but it requires programmer declarations. Some
implementations try to move beyond this by doing type inference and
alerting the programmer to potential static guarantees that the
programmer could make that would allow the compiler to do a better job.

In effect the argument comes down to which kind of typing one thinks
should be the default. Dynamic typing advocates think that static
typing is the wrong default. The notion that static typing can prove
program correctness is flawed - it can only prove that type constraints
are not violated but not necessarily that program logic is correct. It
seems to me that if we set aside that class of software where safety is
paramount - mostly embedded software such as aircraft and medical
devices - we are left mostly with efficiency concerns. The 80-20 rule
suggests that most code doesn't really need the efficiency provided by
static guarantees. So static typing should be invoked for that small
portion of a program where efficiency is really needed and that dynamic
typing should be the default elswhere. This is how common lisp works -
dynamic typing by default with static guarantees available where one
needs them.
Joachim Durchholz - 16 Jun 2006 22:59 GMT
Raffael Cavallaro schrieb:
> There is a very large class of software where user inputs are
> unpredictable and/or where input data comes from an untrusted source. In
> these cases run-time checks are going to be needed anyway so the
> advantages of static type checking are greatly reduced - you end up
> doing run-time checks anyway, precisely the thing you were trying to
> avoid by doing static analysis.

There's still a large class of errors that *can* be excluded via type
checking.

> Ideally one wants a language with switchable typing - static where
> possible and necessary, dynamic elsewhere.

That has been my position for a long time now.

> To a certain extent this is
> what common lisp does but it requires programmer declarations. Some
> implementations try to move beyond this by doing type inference and
> alerting the programmer to potential static guarantees that the
> programmer could make that would allow the compiler to do a better job.

I think it's easier to start with a good (!) statically-typed language
and relax the checking, than to start with a dynamically-typed one and
add static checks.
With the right restrictions, a language can make all kinds of strong
guarantees, and it can make it easy to construct software where static
guarantees abound. If the mechanisms are cleverly chosen, they interfere
just minimally with the programming process. (A classical example it
Hindley-Milner type inference systems. Typical reports from languages
with HM systems say that you can have it verify thousand-line programs
without a single type annotation in the code. That's actually far better
than you'd need - you'd *want* to document the types at least on the
major internal interfaces after all *grin*.)
With a dynamically-typed language, programming style tends to evolve in
directions that make it harder to give static guarantees.

> It seems to
> me that if we set aside that class of software where safety is paramount
> - mostly embedded software such as aircraft and medical devices - we are
> left mostly with efficiency concerns.

Nope. Efficiency has taken a back seat. Software is getting slower
(barely offset by increasing machine speed), and newer languages even
don't statically typecheck everything (C++, Java). (Note that the
impossibility to statically typecheck everything in OO languages doesn't
mean that it's impossible to do rigorous static checking in general.
FPLs have been quite rigorous about static checks; the only cases when
an FPL needs to dynamically typecheck its data structures is after
unmarshalling one from an untyped data source such as a network stream,
a file, or an IPC interface.)

The prime factor nowadays seems to be maintainability.

And the difference here is this:
With dynamic typing, I have to rely on the discipline of the programmers
to document interfaces.
With static typing, the compiler will infer (and possibly document) at
least part of their semantics (namely the types).

> So static typing should be invoked for that small portion of a program
> where efficiency is really needed and that dynamic typing should be the
> default elswhere. This is how common lisp works - dynamic typing by
> default with static guarantees available where one needs them.

Actually static typing seems to become more powerful at finding errors
as the program size increases.
(Yes, that's a maintainability argument. Efficiency isn't *that*
important; since maintenance is usually the most important single
factor, squelching bugs even before testing is definitely helpful.)

Regards,
Jo
Raffael Cavallaro - 16 Jun 2006 23:25 GMT
> I think it's easier to start with a good (!) statically-typed language
> and relax the checking, than to start with a dynamically-typed one and
[quoted text clipped - 10 lines]
> With a dynamically-typed language, programming style tends to evolve in
> directions that make it harder to give static guarantees.

This is purely a matter of programming style. For explorative
programming it is easier to start with dynamic typing and add static
guarantees later rather than having to make decisions about
representation and have stubs for everything right from the start. The
lisp programming style is arguably all about using heterogenous lists
and forward references in the repl for everything until you know what
it is that you are doing, then choosing a more appropriate
representation and filling in forward references once the program gels.
Having to choose representation right from the start and needing
working versions (even if only stubs) of *every* function you call may
ensure type correctness, but many programmers find that it also ensures
that you never find the right program to code in the first place. This
is because you don't have the freedom to explore possible solutions
without having to break your concentration to satisfy the nagging of a
static type checker.
Joachim Durchholz - 17 Jun 2006 12:03 GMT
Raffael Cavallaro schrieb:

>> I think it's easier to start with a good (!) statically-typed language
>> and relax the checking, than to start with a dynamically-typed one and
[quoted text clipped - 4 lines]
> guarantees later rather than having to make decisions about
> representation and have stubs for everything right from the start.

Sorry for being ambiguous - I meant to talk about language evolution.

I agree that static checking could (and probably should) be slightly
relaxed: compilers should still do all the diagnostics that current-day
technology allows, but any problems shouldn't abort the compilation.
It's always possible to generate code that will throw an exception as
soon as a problematic piece of code becomes actually relevant; depending
on the kind of run-time support, this might abort the program, abort
just the computation, or open an interactive facility to correct and/or
modify the program on the spot (the latter is the norm in highly dynamic
systems like those for Lisp and Smalltalk, and I consider this actually
useful).

I don't see static checking and explorative programming as opposites.
Of course, in practice, environments that combine these don't seem to
exist (except maybe in experimental or little-known state).

Regards,
Jo
Raffael Cavallaro - 17 Jun 2006 14:08 GMT
> I don't see static checking and explorative programming as opposites.
> Of course, in practice, environments that combine these don't seem to
> exist (except maybe in experimental or little-known state).

Right. Unfortunately the philosophical leanings of those who design
these two types of languages tend to show themselves as different
tastes in development style - for example, static type advocates don't
often want a very dynamic development environment that would allow a
program to run for testing even when parts of it arent defined yet, and
dynamic type advocates don't want a compiler preventing them from doing
so because the program can't yet be proven statically correct. Dynamic
typing advocates don't generally want a compiler error for ambiguous
typing - for example, adding a float and an int - but static typing
advocates generally do. Of course there's little reason one couldn't
have a language that allowed the full range to be switchable so that
programmers could tighten up compiler warnings and errors as the
program becomes more fully formed. Unfortunately we're not quite there
yet. For my tastes something like sbcl*, with its type inference and
very detailed warnings and notes is as good as it gets for now. I can
basically ignore warnings and notes early on, but use them to allow the
compiler to improve the code it generates once the program is doing
what I want correctly.

[*] I don't mean to exclude other common lisp implementations that do
type inference here - I just happen to use sbcl.
Torben Ægidius Mogensen - 19 Jun 2006 09:19 GMT
> This is purely a matter of programming style. For explorative
> programming it is easier to start with dynamic typing and add static
> guarantees later rather than having to make decisions about
> representation and have stubs for everything right from the start.

I think you are confusing static typing with having to write types
everywhere.  With type inference, you only have to write a minimum of
type information (such as datatype declarations), so you can easily do
explorative progrmming in such languages -- I don't see any advantage
of dynamic typing in this respect.

> The
> lisp programming style is arguably all about using heterogenous lists
[quoted text clipped - 6 lines]
> ensures that you never find the right program to code in the first
> place.

If you don't have definitions (stubs or complete) of the functions you
use in your code, you can only run it up to the point where you call
an undefined function.  So you can't really do much exploration until
you have some definitions.

I expect a lot of the exploration you do with incomplete programs
amount to the feedback you get from type inference.

> This is because you don't have the freedom to explore possible
> solutions without having to break your concentration to satisfy the
> nagging of a static type checker.

I tend to disagree.  I have programmed a great deal in Lisp, Scheme,
Prolog (all dynamically typed) and SML and Haskell (both statically
typed).  And I don't find that I need more stubs etc. in the latter.
In fact, I do a lot of explorative programming when writing programs
in ML and Haskell.  And I find type inference very helpful in this, as
it guides the direction of the exploration, so it is more like a
safari with a local guide than a blindfolded walk in the jungle.

       Torben
George Neuner - 19 Jun 2006 11:11 GMT
>If you don't have definitions (stubs or complete) of the functions you
>use in your code, you can only run it up to the point where you call
>an undefined function.  So you can't really do much exploration until
>you have some definitions.

Well in Lisp that just drops you into the debugger where you can
supply the needed return data and continue.  I agree that it is not
something often needed.

>I expect a lot of the exploration you do with incomplete programs
>amount to the feedback you get from type inference.

The ability to write functions and test them immediately without
writing a lot of supporting code is _far_ more useful to me than type
inference.  

I'm not going to weigh in on the static v dynamic argument ... I think
both approaches have their place.  I am, however, going to ask what
information you think type inference can provide that substitutes for
algorithm or data structure exploration.

George
--
for email reply remove "/" from address
Torben Ægidius Mogensen - 19 Jun 2006 12:53 GMT
> >I expect a lot of the exploration you do with incomplete programs
> >amount to the feedback you get from type inference.
>
> The ability to write functions and test them immediately without
> writing a lot of supporting code is _far_ more useful to me than type
> inference.  

I can't see what this has to do with static/dynamic typing.  You can
test individula functions in isolation is statically typed languages
too.

> I'm not going to weigh in on the static v dynamic argument ... I think
> both approaches have their place.  I am, however, going to ask what
> information you think type inference can provide that substitutes for
> algorithm or data structure exploration.

None.  But it can provide a framework for both and catch some types of
mistakes early.

       Torben
George Neuner - 19 Jun 2006 18:33 GMT
>> >I expect a lot of the exploration you do with incomplete programs
>> >amount to the feedback you get from type inference.
[quoted text clipped - 6 lines]
>test individul functions in isolation is statically typed languages
>too.

It has nothing to do with static/dynamic typing and that was the point
... that support for exploratory programming is orthogonal to the
language's typing scheme.

George
--
for email reply remove "/" from address
Matthias Blume - 19 Jun 2006 19:09 GMT
>  I am, however, going to ask what
> information you think type inference can provide that substitutes for
> algorithm or data structure exploration.

Nobody wants to do such a substitution, of course.  In /my/
experience, however, I find that doing algorithm and data structure
exploration is greatly aided by a language with static types and type
inference.  YMMV.
Raffael Cavallaro - 16 Jun 2006 17:09 GMT
> And this is a typical dynamic type advocate's response when told that
static typing has different needs:
> "*I* don't see the usefulness of static typing so *you* shouldn't
want it, either."

But I haven't made this sort of argument. I never said you shouldn't
use static typing if you want to. There are indeed types of software
where one wants the guarantees provided by static type checks. For
example, software that controls irreplaceable or very expensive
equipment such as space craft, or software that can kill people if it
fails such as software for aircraft or medical devices. The problem for
static typing advocates is that most software is not of this type.

There is a very large class of software where user inputs are
unpredictable and/or where input data comes from an untrusted source.
In these cases run-time checks are going to be needed anyway so the
advantages of static type checking are greatly reduced - you end up
doing run-time checks anyway, precisely the thing you were trying to
avoid by doing static analysis. In software like this it isn't worth
satisfying a static type checker because you don't get much of the
benefit anyway and it means forgoing such advantages of dynamic typing
as being able to run and test portions of a program before other parts
are written (forward references to as yet nonexistent functions).

Ideally one wants a language with switchable typing - static where
possible and necessary, dynamic elsewhere. To a certain extent this is
what common lisp does but it requires programmer declarations. Some
implementations try to move beyond this by doing type inference and
alerting the programmer to potential static guarantees that the
programmer could make that would allow the compiler to do a better job.

In effect the argument comes down to which kind of typing one thinks
should be the default. Dynamic typing advocates think that static
typing is the wrong default. The notion that static typing can prove
program correctness is flawed - it can only prove that type constraints
are not violated but not necessarily that program logic is correct. It
seems to me that if we set aside that class of software where safety is
paramount - mostly embedded software such as aircraft and medical
devices - we are left mostly with efficiency concerns. The 80-20 rule
suggests that most code doesn't really need the efficiency provided by
static guarantees. So static typing should be invoked for that small
portion of a program where efficiency is really needed and that dynamic
typing should be the default elswhere. This is how common lisp works -
dynamic typing by default with static guarantees available where one
needs them.
Darren New - 16 Jun 2006 17:45 GMT
> Give a heterogenous list that would to too awkward to live in a
> statically-typed language.

Write a function that takes an arbitrary set of arguments and stores
them into a structure allocated on the heap.

> Give a case of calling nonexistent functions that's useful.

See the Tcl "unknown" proc, used for interactive command expansion,
dynamic loading of code on demand, etc.

Signature

  Darren New / San Diego, CA, USA (PST)
    My Bath Fu is strong, as I have
    studied under the Showerin' Monks.

Darren New - 16 Jun 2006 17:59 GMT
Joachim Durchholz wrote:
> Give a heterogenous list that would to too awkward to live in a
> statically-typed language.

Printf()?

Signature

  Darren New / San Diego, CA, USA (PST)
    My Bath Fu is strong, as I have
    studied under the Showerin' Monks.

Matthias Blume - 16 Jun 2006 19:10 GMT
> Joachim Durchholz wrote:
>> Give a heterogenous list that would to too awkward to live in a
>> statically-typed language.
>
> Printf()?

Very good statically typed versions of printf exist.  See, e.g.,
Danvy's unparsing combinators.
Darren New - 16 Jun 2006 20:06 GMT
> Very good statically typed versions of printf exist.  See, e.g.,
> Danvy's unparsing combinators.

That seems to ignore the fact that the pattern is a string, which means
that printf's first argument in Danvy's mechanism has to be a literal.
You can't read the printf format from a configuration file (for example)
to support separate languages. It doesn't look like the version of
printf that can print its arguments in an order different from the order
provided in the argument list is supported either; something like "%3$d"
or some such.

Second, what's the type of the argument that printf, sprintf, fprintf,
kprintf, etc all pass to the subroutine that actually does the
formatting? (Called vprintf, I think?)

Signature

  Darren New / San Diego, CA, USA (PST)
    My Bath Fu is strong, as I have
    studied under the Showerin' Monks.

Matthias Blume - 16 Jun 2006 21:45 GMT
>> Very good statically typed versions of printf exist.  See, e.g.,
>> Danvy's unparsing combinators.
>
> That seems to ignore the fact that the pattern is a string, which
> means that printf's first argument in Danvy's mechanism has to be a
> literal.

In Danvy's solution, the format argument is not a string.

> You can't read the printf format from a configuration file
> (for example) to support separate languages.

You don't need to do that if you want to support separate languages.
Moreover, reading the format string from external input is a good way
of opening your program to security attacks, since ill-formed data on
external media are then able to crash you program.

> It doesn't look like the
> version of printf that can print its arguments in an order different
> from the order provided in the argument list is supported either;
> something like "%3$d" or some such.

I am not familiar with the version of printf you are refering to, but
I am sure one could adapt Danvy's solution to support such a thing.

> Second, what's the type of the argument that printf, sprintf, fprintf,
> kprintf, etc all pass to the subroutine that actually does the
> formatting? (Called vprintf, I think?)

Obviously, a Danvy-style solution (see, e.g., the one in SML/NJ's
library) is not necessarily structured that way.  I don't see the
problem with typing, though.

Matthias
Darren New - 16 Jun 2006 22:10 GMT
> In Danvy's solution, the format argument is not a string.

That's what I said, yes.

>>You can't read the printf format from a configuration file
>>(for example) to support separate languages.

> You don't need to do that if you want to support separate languages.

That's kind of irrelevant to the discussion. We're talking about
collections of dynamically-typed objects, not the best mechanisms for
supporting I18N.

> Moreover, reading the format string from external input is a good way
> of opening your program to security attacks, since ill-formed data on
> external media are then able to crash you program.

Still irrelevant to the point.

> I am sure one could adapt Danvy's solution to support such a thing.

I'm not. It's consuming arguments as it goes, from what I understood of
the paper. It's translating, essentially, into a series of function
calls in argument order.

> Obviously, a Danvy-style solution (see, e.g., the one in SML/NJ's
> library) is not necessarily structured that way.  I don't see the
> problem with typing, though.

You asked for an example of a heterogenous list that would be awkward in
a statically strongly-typed language. The arguments to printf() count,
methinks. What would the second argument to apply be if the first
argument is printf (since I'm reading this in the LISP group)?

Signature

  Darren New / San Diego, CA, USA (PST)
    My Bath Fu is strong, as I have
    studied under the Showerin' Monks.

Joachim Durchholz - 16 Jun 2006 23:09 GMT
Darren New schrieb:
>> Give a heterogenous list that would to too awkward to live in a
>> statically-typed language.
>
> Write a function that takes an arbitrary set of arguments and stores
> them into a structure allocated on the heap.

If the set of arguments is really arbitrary, then the software can't do
anything with it. In that case, the type is simply "opaque data block",
and storing it in the heap requires nothing more specific than that of
"opaque data block".
There's more in this. If we see a function with a parameter type of
"opaque data block", and there's no function available except copying
that data and comparing it for equality, then from simply looking at the
function's signature, we'll know that it won't inspect the data. More
interestingly, we'll know that funny stuff in the data might trigger
bugs in the code - in the context of a security audit, that's actually a
pretty strong guarantee, since the analysis can stop at the function't
interface and doesn't have to dig into the function's implementation.

>> Give a case of calling nonexistent functions that's useful.
>
> See the Tcl "unknown" proc, used for interactive command expansion,
> dynamic loading of code on demand, etc.

Not related to dynamic typing, I fear - I can easily envision
alternatives to that in a statically-typed context.

Of course, you can't eliminate *all* run-time type checking. I already
mentioned unmarshalling data from an untyped source; another possibility
is run-time code compilation (highly dubious in a production system but
of value in a development system).

However, that's some very specialized applications, easily catered for
by doing a dynamic type check plus a thrown exception in case the types
don't match. I still don't see a convincing argument for making dynamic
typing the standard policy.

Regards,
Jo
Rob Thorpe - 14 Jun 2006 16:12 GMT
> On a similar note, is a statically typed langauge more or less
> expressive than a dynamically typed language?  Some would say less, as
[quoted text clipped - 4 lines]
> programmer to get the program working in the dynamically typed
> language.

>From the point of view purely of expressiveness I'd say it's rather
different.

If a language can express constraints of one kind that is an increase
in expressiveness.
If a language requires constraint to be in one particular way thats a
decrease in expressiveness.

So I would say languages that can be statically typed and can be
dynamically typed are the most expressive.  Languages that require
static typing or are dynamic but cannot express static typing are less
expressive.

This meets my experience of what useful in practice too, static typing
for everything is painful for writing simple code.  Pure dynamic typing
is painful when writing complex code because it makes impossible a
layer of error checking that could otherwise be useful.
Joachim Durchholz - 14 Jun 2006 20:09 GMT
Rob Thorpe schrieb:

> If a language can express constraints of one kind that is an increase
> in expressiveness.

Agreed.

> If a language requires constraint to be in one particular way thats a
> decrease in expressiveness.

Unless alternatives would be redundant.
Having redundant ways to express the same thing doesn't make a language
more or less expressive (but programs written in it become more
difficult to maintain).

> So I would say languages that can be statically typed and can be
> dynamically typed are the most expressive.  Languages that require
> static typing or are dynamic but cannot express static typing are less
> expressive.

Note that this is a different definition of expressiveness.
(The term is very diffuse...)

I think Felleisen's paper defines something that should be termed
"conciseness".
Whether there's a way to express constraints or other static properties
of the software is something different. I don't have a good word for it,
but "expressiveness" covers too much for my taste to really fit.

Regards,
Jo
Joachim Durchholz - 14 Jun 2006 19:55 GMT
Torben Ægidius Mogensen schrieb:
> For example,
> if you have to code everything as natural numbers, untyped pure lambda
> calculus or S-expressions, there is a good chance that you can get
> nonsense past the compiler.

Also past peer review and/or debugging runs. And, most importantly, past
your own mental review processes.

Regards,
Jo
Pascal Costanza - 14 Jun 2006 21:18 GMT
> On a similar note, is a statically typed langauge more or less
> expressive than a dynamically typed language?  Some would say less, as
> you can write programs in a dynamically typed language that you can't
> compile in a statically typed language (without a lot of encoding),
> whereas the converse isn't true.

It's important to get the levels right here: A programming language with
a rich static type system is more expressive at the type level, but less
expressive at the base level (for some useful notion of expressiveness ;).

> However, I think this is misleading,
> as it ignores the feedback issue: It takes longer for the average
> programmer to get the program working in the dynamically typed
> language.

This doesn't seem to capture what I hear from Haskell programmers who
say that it typically takes quite a while to convince the Haskell
compiler to accept their programs. (They perceive this to be worthwhile
because of some benefits wrt correctness they claim to get in return.)

Pascal

Signature

3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/

Torben Ægidius Mogensen - 16 Jun 2006 10:07 GMT
> > On a similar note, is a statically typed langauge more or less
> > expressive than a dynamically typed language?  Some would say less, as
[quoted text clipped - 17 lines]
> worthwhile because of some benefits wrt correctness they claim to get
> in return.)

That's the point: Bugs that in dynamically typed languages would
require testing to find are found by the compiler in a statically
typed language.  So whil eit may take onger to get a program thatgets
past the compiler, it takes less time to get a program that works.

       Torben
Pascal Costanza - 16 Jun 2006 10:59 GMT
>>> On a similar note, is a statically typed langauge more or less
>>> expressive than a dynamically typed language?  Some would say less, as
[quoted text clipped - 19 lines]
> require testing to find are found by the compiler in a statically
> typed language.

Yes. However, unfortunately statically typed languages also reject
programs that don't have such bugs. It's a tradeoff whether you want to
spend time to deal with them or not.

> So whil eit may take onger to get a program thatgets
> past the compiler, it takes less time to get a program that works.

That's incorrect. See http://haskell.org/papers/NSWC/jfp.ps - especially
Figure 3.

Pascal

Signature

3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/

Torben Ægidius Mogensen - 16 Jun 2006 12:38 GMT
> > So while it may take longer to get a program that gets
> > past the compiler, it takes less time to get a program that works.
>
> That's incorrect. See http://haskell.org/papers/NSWC/jfp.ps -
> especially Figure 3.

There are many other differences between these languages than static
vs. dynamic types, and some of these differences are likely to be more
significant.  What you need to test is langauges with similar features
and syntax, except one is statically typed and the other dynamically
typed.

And since these languages would be quite similar, you can use the same
test persons: First let one half solve a problem in the statically
typed language and the other half the same problem in the dynamically
typed language, then swap for the next problem.  If you let a dozen
persons each solve half a dozen problems, half in the statically typed
language and half in the dynamically typed language (using different
splits for each problem), you might get a useful figure.

       Torben
Pascal Costanza - 16 Jun 2006 15:48 GMT
>>> So while it may take longer to get a program that gets
>>> past the compiler, it takes less time to get a program that works.
[quoted text clipped - 14 lines]
> language and half in the dynamically typed language (using different
> splits for each problem), you might get a useful figure.

...and until then claims about the influence of static type systems on
the speed with which you can implement working programs are purely
guesswork. That's the only point I need to make to show that your
original unqualified statement, namely that it takes less time to get a
program that works, is incorrect.

Pascal

Signature

3rd European Lisp Workshop
July 3 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/

Rob Thorpe - 16 Jun 2006 11:40 GMT
> > > On a similar note, is a statically typed langauge more or less
> > > expressive than a dynamically typed language?  Some would say less, as
[quoted text clipped - 22 lines]
> typed language.  So whil eit may take onger to get a program thatgets
> past the compiler, it takes less time to get a program that works.

In my experience the opposite is true for many programs.
Having to actually know the precise type of every variable while
writing the program is not necessary, it's a detail often not relevant
to the core problem. The language should be able to take care of
itself.

In complex routines it can be useful for the programmer to give types
and for the compiler to issue errors when they are contradicted.  But
for most routines it's just an unnecessary chore that the compiler
forces on the programmer.
Torben Ægidius Mogensen - 16 Jun 2006 12:53 GMT
> > That's the point: Bugs that in dynamically typed languages would
> > require testing to find are found by the compiler in a statically
[quoted text clipped - 11 lines]
> for most routines it's just an unnecessary chore that the compiler
> forces on the programmer.

Indeed.  So use a language with type inference.

       Torben
Rob Thorpe - 19 Jun 2006 09:48 GMT
> > > That's the point: Bugs that in dynamically typed languages would
> > > require testing to find are found by the compiler in a statically
[quoted text clipped - 13 lines]
>
> Indeed.  So use a language with type inference.

Well, for most purposes that's the same as dynamic typing since the
compiler doesn't require you to label the type of your variables.  I
occasionally use CMUCL and SBCL which do type inference, which is
useful at improving generated code quality.  It also can warn the
programmer if they if they reuse a variable in a context implying that
it's a different type which is useful.

I see type inference as an optimization of dynamic typing rather than a
generalization of static typing.  But I suppose you can see it that way
around.
Torben Ægidius Mogensen - 19 Jun 2006 11:03 GMT
> > Indeed.  So use a language with type inference.
>
> Well, for most purposes that's the same as dynamic typing since the
> compiler doesn't require you to label the type of your variables.

That's not really the difference between static and dynamic typing.
Static typing means that there exist a typing at compile-time that
guarantess against run-time type violations.  Dynamic typing means
that such violations are detected at run-time.  This is orthogonal to
strong versus weak typing, which is about whether such violations are
detected at all.  The archetypal weakly typed language is machine code
-- you can happily load a floating point value from memory, add it to
a string pointer and jump to the resulting value.  ML and Scheme are
both strongly typed, but one is statically typed and the other
dynamically typed.

Anyway, type inference for statically typed langauges don't make them
any more dynamically typed.  It just moves the burden of assigning the
types from the programmer to the compiler.  And (for HM type systems)
the compiler doesn't "guess" at a type -- it finds the unique most
general type from which all other legal types (within the type system)
can be found by instantiation.

>  I
> occasionally use CMUCL and SBCL which do type inference, which is
[quoted text clipped - 5 lines]
> generalization of static typing.  But I suppose you can see it that way
> around.

Some compilers for dynamically typed languages will do a type analysis
similar to type inference, but they will happily compile a program
even if they can't guarantee static type safety.

Such "type inference" can be seen as an optimisation of dynamic
typing, as it allows the compiler to omit _some_ of the runtime type
checks.  I prefer the term "soft typing" for this, though, so as not
to confuse with static type inference.

Soft typing can give feedback similar to that of type inference in
terms of identifying potential problem spots, so in that respect it is
similar to static type inference, and you might get similar fast code
development.  You miss some of the other benefits of static typing,
though, such as a richer type system -- soft typing often lacks
features like polymorphism (it will find a set of monomorphic
instances rather than the most general type) and type classes.

       Torben
Chris Smith - 19 Jun 2006 16:20 GMT
> That's not really the difference between static and dynamic typing.
> Static typing means that there exist a typing at compile-time that
[quoted text clipped - 6 lines]
> both strongly typed, but one is statically typed and the other
> dynamically typed.

Knowing that it'll cause a lot of strenuous objection, I'll nevertheless
interject my plea not to abuse the word "type" with a phrase like
"dynamically typed".  If anyone considers "untyped" to be perjorative,
as some people apparently do, then I'll note that another common term is
"type-free," which is marketing-approved but doesn't carry the
misleading connotations of "dynamically typed."  We are quickly losing
any rational meaning whatsoever to the word "type," and that's quite a
shame.

By way of extending the point, let me mention that there is no such
thing as a universal class of things that are called "run-time type
violations".  At runtime, there is merely correct code and incorrect
code.  To the extent that anything is called a "type" at runtime, this
is a different usage of the word from the usage by which we may define
languages as being statically typed (which means just "typed").  In
typed OO languages, this runtime usage is often called the "class", for
example, to distinguish it from type.

This cleaner terminology eliminates a lot of confusion.  For example, it
clarifies that there is no binary division between strongly typed
languages and weakly typed languages, since the division between a "type
error" and any other kind of error is arbitrary, depending only on
whether the type system in a particular language happens to catch that
error.  For example, type systems have been defined to try to catch unit
errors in scientific programming, or to catch out-of-bounds array
indices... yet these are not commonly called "type errors" only because
such systems are not in common use.

This also leads us to define something like "language safety" to
encapsulate what we previously would have meant by the phrase "strongly
dynamically typed language".  This also is a more general concept than
we had before.  Language safety refers to a language having well-defined
behavior for as many operations as feasible, so that it's less likely
that someone will do something spectacularly bad.  Language safety may
be achieved either by a type system or by runtime checks.  Again, it's
not absolute... I'm aware of no language that is completely determinate,
at least if it supports any kind of concurrency.

This isn't just a matter of preference in terminology.  The definitions
above (which are, in my experience, used widely by most non-academic
language design discussions) actually limit our understanding of
language design by pretending that certain delicate trade-offs such as
the extent of the type system, or which language behavior is allowed to
be non-deterministic or undefined, are etched in stone.  This is simply
not so.  If types DON'T mean a compile-time method for proving the
absence of certain program behaviors, then they don't mean anything at
all.  Pretending that there's a distinction at runtime between "type
errors" and "other errors" serves only to confuse things and
artificially limit which problems we are willing to concieve as being
solvable by types.

> Anyway, type inference for statically typed langauges don't make them
> any more dynamically typed.

Indeed it does not.  Unless it weakens the ability of a compiler to
prove the absence of certain program behaviors (which type inference
does not), it doesn't move anything on the scale toward a type-free
language.

That being said, though, it is considered a feature of some programming
languages that the programmer is asked to repeat type information in a
few places.  The compiler may not need the information, but for
precisely the reason that the information is redundant, the compiler is
then able to check the consistency of the programmer in applying the
type.  I won't get into precisely how useful this is, but it is
nevertheless present as an advantage to outweigh the wordiness.

Signature

Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation

Rob Thorpe - 19 Jun 2006 16:44 GMT
> > That's not really the difference between static and dynamic typing.
> > Static typing means that there exist a typing at compile-time that
[quoted text clipped - 15 lines]
> any rational meaning whatsoever to the word "type," and that's quite a
> shame.

I don't think dynamic typing is that nebulous.  I remember this being
discussed elsewhere some time ago, I'll post the same reply I did then
..

A language is statically typed if a variable has a property - called
it's type - attached to it, and given it's type it can only represent
values defined by a certain class.

A language is latently typed if a value has a property - called it's
type - attached to it, and given it's type it can only represent values
defined by a certain class.

Some people use dynamic typing as a word for latent typing, others use
it to mean something slightly different.  But for most purposes the
definition above works for dynamic typing also.

Untyped and type-free mean something else: they mean no type checking
is done.
Chris Smith - 19 Jun 2006 17:31 GMT
> A language is latently typed if a value has a property - called it's
> type - attached to it, and given it's type it can only represent values
> defined by a certain class.

I'm assuming you mean "class" in the general sense, rather than in the
sense of a specific construct of some subset of OO programming
languages.

Now I define a class of values called "correct" values.  I define these
to be those values for which my program will produce acceptable results.  
Clearly there is a defined class of such values: (1) they are
immediately defined by the program's specification for those lines of
code that produce output; (2) if they are defined for the values that
result from any expression, then they are defined for the values that
are used by that expression; and (3) for any value for which correctness
is not defined by (1) or (2), we may define its "correct" values as the
class of all possible values.  Now, by your definition, any language
which provides checking of that property of correctness for values is
latently typed.  Of course, there are no languages that assign this
specific class of values; but ANY kind of correctness checking on values
that a language does (if it's useful at all) is a subset of the perfect
correctness checking system above.  Apparently, we should call all such
systems "latent type systems".  Can you point out a language that is not
latently typed?

I'm not trying to poke holes in your definition for fun.  I am proposing
that there is no fundamental distinction between the kinds of problems
that are "type problems" and those that are not.  Types are not a class
of problems; they are a class of solutions.  Languages that solve
problems in ways that don't assign types to variables are not typed
languages, even if those same problems may have been originally solved
by type systems.

> Untyped and type-free mean something else: they mean no type checking
> is done.

Hence, they don't exist, and the definitions being used here are rather
pointless.

Signature

Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation

Yet Another Dan - 19 Jun 2006 19:21 GMT
>> A language is latently typed if a value has a property - called it's
>> type - attached to it, and given it's type it can only represent
[quoted text clipped - 5 lines]
> are immediately defined by the program's specification for those lines
> of code that produce output; ...

> I'm not trying to poke holes in your definition for fun.  I am
> proposing that there is no fundamental distinction between the kinds
> of problems that are "type problems" and those that are not.

That sounds like a lot to demand of a type system. It almost sounds like
it's supposed to test and debug the whole program. In general, defining the
exact set of values for a given variable that generate acceptable output
from your program will require detailed knowledge of the program and all
its possible inputs. That goes beyond simple typing. It sounds more like
contracts. Requiring an array index to be an integer is considered a typing
problem because it can be checked based on only the variable itself,
whereas checking whether it's in bounds requires knowledge about the array.

Signature

YAD

Dimitri Maziuk - 19 Jun 2006 23:02 GMT
Yet Another Dan sez:

... Requiring an array index to be an integer is considered a typing
> problem because it can be checked based on only the variable itself,
> whereas checking whether it's in bounds requires knowledge about the array.

You mean like
subtype MyArrayIndexType is INTEGER 7 .. 11
type MyArrayType is array (MyArrayIndexType) of MyElementType

Dima
Signature

We're sysadmins. Sanity happens to other people.                  -- Chris King

George Neuner - 20 Jun 2006 18:08 GMT
>Yet Another Dan sez:
>
[quoted text clipped - 5 lines]
> subtype MyArrayIndexType is INTEGER 7 .. 11
> type MyArrayType is array (MyArrayIndexType) of MyElementType

If the index computation involves wider types it can still produce
illegal index values.  The runtime computation of an illegal index
value is not prevented by narrowing subtypes and cannot be statically
checked.

George
--
for email reply remove "/" from address
Dimitri Maziuk - 21 Jun 2006 17:12 GMT
George Neuner sez:

>>Yet Another Dan sez:
>>
[quoted text clipped - 10 lines]
> value is not prevented by narrowing subtypes and cannot be statically
> checked.

My vague recollection is that no, it won't unless _you_ explicitly code an
unchecked type conversion. But it's been a while.

HTH
Dima
Signature

I have not been able to think of any way of describing Perl to [person]
"Hello, blind man?  This is color."                                      -- DPM

George Neuner - 21 Jun 2006 21:55 GMT
>George Neuner sez:
>>
[quoted text clipped - 15 lines]
>My vague recollection is that no, it won't unless _you_ explicitly code an
>unchecked type conversion. But it's been a while.

You can't totally prevent it ... if the index computation involves
types having a wider range, frequently the solution is to compute a
wide index value and then narrow it.  But if the wider value is out of
range for the narrow type you have a problem.  

Using the illegal wide value in a checked narrowing conversion will
throw a CONSTRAINT_ERROR exception - it doesn't matter whether you
access the array directly using the wide value or try to assign the
value to a variable of the narrow index type.  Using the wide value
unchecked will access memory beyond the array which is not what you
wanted and may cause a crash.

The point is really that the checks that prevent these things must be
performed at runtime and can't be prevented by any practical type
analysis performed at compile time.  I'm not a type theorist but my
opinion is that a static type system that could, a priori, prevent the
problem is impossible.

George
--
for email reply remove "/" from address
Greg Buchholz - 21 Jun 2006 23:04 GMT
> You can't totally prevent it ... if the index computation involves
> types having a wider range, frequently the solution is to compute a
> wide index value and then narrow it.  But if the wider value is out of
> range for the narrow type you have a problem.

...snip...

> The point is really that the checks that prevent these things must be
> performed at runtime and can't be prevented by any practical type
> analysis performed at compile time.  I'm not a type theorist but my
> opinion is that a static type system that could, a priori, prevent the
> problem is impossible.

   I haven't been following this thread too closely, but I thought the
following article might be of interest...

Eliminating Array Bound Checking through Non-dependent types.
http://okmij.org/ftp/Haskell/types.html#branding

"There is a view that in order to gain static assurances such as an
array index being always in range or tail being applied to a non-empty
list, we must give up on something significant: on data structures such
as arrays (to be replaced with nested tuples), on general recursion, on
annotation-free programming, on clarity of code, on well-supported
programming languages. That does not have to be the case. The present
messages show non-trivial examples involving native Haskell arrays,
index computations, and general recursion. All arrays indexing
operations are statically guaranteed to be safe -- and so we can safely
use an efficient unsafeAt provided by GHC seemingly for that purpose.
The code is efficient; the static assurances cost us no run-time
overhead. The example uses only Haskell98 + higher-ranked types. No new
type classes are introduced. The safety is based on: Haskell type
system, quantified type variables, and a compact general-purpose
trusted kernel."
George Neuner - 22 Jun 2006 00:22 GMT
>    I haven't been following this thread too closely, but I thought the
>following article might be of interest...
>
>Eliminating Array Bound Checking through Non-dependent types.
>http://okmij.org/ftp/Haskell/types.html#branding

That was interesting, but the authors' method still involves runtime
checking of the array bounds.  IMO, all they really succeeded in doing
was turning the original recursion into CPS and making the code a
little bit clearer.

George
--
for email reply remove "/" from address
Greg Buchholz - 27 Jun 2006 22:59 GMT
> That was interesting, but the authors' method still involves runtime
> checking of the array bounds.  IMO, all they really succeeded in doing
> was turning the original recursion into CPS and making the code a
> little bit clearer.

   Hmm.  There is a comparison in both the DML and Haskell code, but
that's just there to make the binary search terminate correctly.  The
point of the exercise is the line in the DML code "val m = (hi + lo)
div 2", or the "bmiddle" function in the Haskell code.  If you change
that line to something like "val m = (hi + lo)" you'll get a compiler
error complaining about an unsolved constraint.  The point of the
Haskell code is to use the type system to ensure that array indices
have a know provenance.  They're derived from and statically associated
with each individual array, so you can't use an index from one array
with a different array.  You'll probably also enjoy the paper...

   "Eliminating Array Bound Checking Through Dependent Types"
   http://citeseer.ist.psu.edu/xi98eliminating.html

...and DML itself...

   http://www.cs.bu.edu/~hwxi/DML/DML.html

Greg Buchholz