From: jlg@cochiti.lanl.gov (Jim Giles)
Subject: Re: Types, arrays, generality, and notation (was: Fortran90 and Arrays)
Organization: Los Alamos National Laboratory
Date: Wed, 15 Apr 1992 20:14:53 GMT

In article <STEPHEN.92Apr14171919@estragon.uchicago.edu>, stephen@estragon.uchicago.edu (Stephen P Spackman) writes:
|> In article <1992Apr13.194947.17250@newshost.lanl.gov> jlg@cochiti.lanl.gov (Jim Giles) writes:
|> [...]
|> |   I) Intrinsic data types.  These should be chosen as appropriate for
|> |	 the intended problem domain(s) of the language.  Are you saying
|> |	 that there should be no distinguished syntax for, say, integer 
|> |	 literals?
|> 
|> A language should not be restricted to a particular problem domain or
|> domains. A good language is _necessarily_ a general purpose language.

Now we _really_ disagree.  I think that the `one size fits all' language
is impossible with the present technology and probably always will be.
High-level languages _must_ decide on a target user group and design 
for that problem domain or they will not be high-level.

|> [...]
|> The other 7 type species you list are:
|> 	enumerated, records, unions, arrays, sets, sequences
|> 	(streams), and all recursive types lumped together.
|> 
|> |These are the eight data types all general programming languages should 
|> |support.  By allowing them to be used orthogonally (like: an array of
|> |sequences, or a linked list of records, etc.) you can build any data type
|> |I've ever come across.  Are there any Hoare left out?  In any case, it 
|> |seems perfectly appropriate - even desirable - for each of these to have 
|> |a distinguished syntax to improve legibility of the code.
|> 
|> What about:
|> 	the many variant numeric types, like
|> 		fixeds, bignums, constructive reals, prime power
|> 		product integers, rationals, rationals in irrational
|> 		base, ... not all of which (I can guarantee) are going
|> 		to be "intrinsic" to an implementation

But, given a flexible set of intrinsics, these can be built using 
records, unions, and/or arrays of those intrinsics.  That, with strict
type checking and operator overloading permit all of those.

|> 	numbers with units, like 9.8 m/s2

Units are an enumerated data type.  Numbers with units are a record
type consisting of a magnitude (possible in some union of numeric
types), a list of numerator units, and a list of denominator units.
Arithmetic operators on this record are easily defined (like: plus 
checks to make sure the units are the same and then adds the magnitudes;
multiply merges the numerator and denominator lists of its operands,
removes any that appear in both lists, and takes the product of the 
magnitude; etc.).

|> 	functions

Yes, that's the one I thought of after I already sent the last article.
If you wish functions to be first class objects, you need to be able to
declare function valued variables and have the operations curry and
compose defined on them.  Other operations on functions may be desirable.

And, there is another type structuring tool I left out, it might be 
desirable to define a type with certain things left unspecified and
allow declarations to contain parameters to finally specify such 
things.  Such parameterized data types were considered by the Fortran
committee and were eliminated before public review.

|> 	dependent products
|> 	dependent functions

Describe what you mean here.

|> 	type itself

Recent research has shown this to be a bad idea.  What do you propose to
do with it?  If you can show reason that it's vitally important, then 
it should be included in those language designs which are targeted for
the problem domain in which they are important.

|> [...]
|> 	continuations

With the addition of functions to my original list, these are all
capable of being constructed from the tools I gave.  Once constructed,
the user can give them names and treat them as if they were built-in 
for the rest of the program - just like any other user defined type.

Why would one want to explicitly construct continuations?  In functional
programming languages they are irrelevant and in procedural languages
they are implicit in the semantics of the language.  I suppose very
naive conversion programs from procedural to functional languages could
use them.

|> 	processes

Depends on what you mean here.  In a functional language, processes 
are not relevant.  Order of execution is not specified (or specifiable,
except implicitly) in a functional language, so any parallel operation 
(or lack thereof) is implicit.  In a procedural language, processes 
aren't a data type but a flow control mechanism.

|> 	files

The structure and content of files are easily defined by the tools
I listed before.  I/O properties of files are an inherently system
supplied set of operations.  Preferably, most of these system supplied
operations obey some system independent specification for the programming
language.

|> 	times

You mean like 8:00 AM?  What are the properties of this data type?

|> 	terminals
|> 	people

Physical objects, I admit, cannot be constructed of software.

|> [...etc. etc. ...]

The bottom line is that if you can design a language which supports a
given data type, then I can construct such that data type using the tools
I have listed.  Or, are you claiming that you've designed a language
that's beyong Turing equivalent capabilities?

|> [...]
|> THEN HOW DO I INTRODUCE A NEW KEYWORD? I tell you, it's a reserved
|> mechanism. How am I failing to communicate this idea? If I can't make
|> one, but the language implementor does, it's reserved.

Oh.  I see.  You're one of those people who see no value in a standardized
notation.  Changing the keywords and other basic characteristics of a
programming language is like changing the grammar of English - it's
great as long as you only talk to yourself.  Languages which allow
the user to define such things tend to be mutually incomprehensible
even among strong supporters of those languages.  Language design is
a compromise (on several points simultaneously).  In this case, the
compromise is between flexibility and standardization of syntax.

There are some aspects of the syntax of a language which I think should
be beyond the ability of the user to change.  This promotes better 
understanding _between_ programmers.  If you never work with other 
people or you never read other people's code this may be irrelevant
to you.  It's not to me.

|> [... Fortran 90 operator overloading rules and our proposed extension ...]
|> 
|> Sure took long enough! But hoorah. Can the overloads be resolved off
|> opaque types, or do they see the implementations?

What do you mean by `opaque' types?  Also, what do you mean by "Sure
took long enough"?  This thread has been going (now under several names)
for months now.  My second or third article mentioned these operator
overloading rules and our proposed extensions to them.

|> 
|> ||> 
|> ||> |with an efficient method of calculating without floating-point and
|> ||> |I suspect Fortran (even J) would be quickly extended to support it.
|> ||> 
|> ||> Fixed point with the compiler tracking the scaling factor, of course.
|> |
|> |It's considerably slower than floating-point.  Also, it's not 
|> |more accurate than floating-point, it just has _different_ error 
|> |characteristics (unless you scale on _every_ operation, in which
|> |case it _IS_ floating-point, just inefficiently simulated in
|> |software).
|> 
|> Integer arithmetic slower than floating point? You're kidding!  [...]

Yes.  Integer multiplies require the whole product to be formed, for
example.  Many Floating-point implementations do not (though not doing
so increases round-off error a bit - such implementations are not IEEE
conforming).  An integer multiply on the Cray would probably take twice 
as long as the float product for the same number of significant bits.
Integer adds and subtracts are a little faster (_very_ little) than 
floating-point ones.  Integer divides are worse (floating-point
implementations often use a Newtons's iteration - which would not
be accurate enough for fixed-point).  Once again, this trade-off is
between relative error in a calculation for floating-point vs. 
absolute error in fixed-point.  Relative error tends to be more
important more often.

|> [...]                                                          And
|> accuracy trades against speed. I can get more accuracy by using a
|> wider word, if I want to, and leave the tradeoffs to the compiler,
|> where they belong.

A wider word doesn't help if the problem is caused by the fact that 
your algorithm required good _relative_ error characteristics on a
wide variety of magnitudes rather than good absolute error characteristics
on the narrow range of magnitudes that fixed-point provides.  Or, do 
you recommend that _every_ data object has a separate fixed-point
type with a specially tuned scale factor (in which case, every 
operation will be recomputing the scale factors - that is, simulating
float in software).

|> [... reduce can't automatically select identity for all operators ...]
|> That was my point. Identity is part of the programmer-provided
|> semantics, and you mustn't go locking people into a default that is
|> actually meaningless half the time.... This is one you MUST be able to
|> specify, because the compiler DOESN'T know. Or are you suggesting that
|> reduction should only be.... Never mind.

The notation you gave in your earlier post implied that the compiler was
_automagically_ deciding what the identity for various operators was. 
You gave `+' and `min' as examples if I recall correctly.  You had the 
syntax of the two done identically and claimed the compiler would select 
zero as the identity for plus and would require a non-empty array for 
reducing `min'.  How does the compiler _know_?  How does the user intervene 
if he wants something else?  Your example gave no indication at all about
these issues.  My counterexample made it clear that the user had specific
control at the site of the reduce.

If you intended that your method allow the user control over what the
identity element for user defined functions was, you should have shown 
_how_ the user exercises that control.  Your examples _implied_ that
the compiler somehow automatically `knew' what to do.

J. Giles