From: stephen@estragon.uchicago.edu (Stephen P Spackman)
Newsgroups: comp.lang.misc
Subject: Re: Types, arrays, generality, and notation (was: Fortran90 and Arrays)
Date: 11 Apr 92 09:38:02 GMT
	<STEPHEN.92Apr10055926@estragon.uchicago.edu>
	<1992Apr10.184017.10041@newshost.lanl.gov>
Organization: University of Chicago CILS

In article <1992Apr10.184017.10041@newshost.lanl.gov> jlg@cochiti.lanl.gov (Jim Giles) writes:
|In article <STEPHEN.92Apr10055926@estragon.uchicago.edu>, stephen@estragon.uchicago.edu (Stephen P Spackman) writes:
||> [... static type tests ...]
||> Look at SELF. Hell, look at the internals of a competent FORTRAN
||> compiler. You're thinking in the stone age! :-)
|
|But Fortran requires declarations!  If you haven't got declarations
|AND you've got I/O, separate compilation, and the ability to assign
|objects of _any_ type to _any_ identifier, you can't expect the 
|compiler to be able to do compile-time type checking very well.
|It means that you must infer constraints about objects which 
|inherently aren't known until run-time.

So delay compilation until runtime. The distinction is artificial,
anyway: the cleanest and most portable description of an executable
image is that it is a long-term-suspended process that is cloned and
restarted....

||> [...]
||> It's not a question of if they could according to the language spec,
||> it's a question of whether they could according to the programme text
||> as interpreted under that language spec, and those are poles apart.
|
|Agreed.  There is much that _can_ be done even without declared variables.
|But, that is not as much as is _easily_ done if you have declarations.
|If you have declarations AND sophisticated techniques, you can do 
|better than if you have to go without one or the other.  And, as
|I've repeatedly pointed out, declarations make the code more legible
|to _humans_.

I agree with the comment; I'd like to see *much* stricter typing rules
than fortran provides (the idea of being able to assign a distance to
a pressure gives me the hab-dabs) for reasons of security, efficiency
and self-documentation. But I still think a really good compiler will
get more of its information by analysis than by declaration. And if I
had to design an intermediate code I'd rather go typeless than use (at
least older) FORTRAN models. Doing it right is better still.

|Separate compilation and optimization are not _that_ incompatible if
|it's possible for most of the optimization to be carried out on the 
|basis of declared attributes.  The loader can include checks to make 
|sure the actual uses match the declarations.

Register allocation, type representation selection, calling
conventions, inlining, space/speed generation choices, argument format
checking, exception handling, and code placement. That's probably only
a quarter of the list of things that you can't get right on a
module-at-a-time basis. You really are straightjacketting yourself by
INSISTING on separate compilation.

||> [...]                                                 - in fact,
||> optimisation without prior execution is undesriable, too, so a decent
||> system with good performance is going to look a bit interpretive....
|
|The explicit declarations available to a language _could_ include
|usage statistics from test runs or preceeding versions.

But self-modifying source is a worse disaster than self-modifying
object. (Of course, there's a clean, standard solution in the form of
compiled, automatically-derived interface files).

||> Have you considered distributing the intermediate code instead?

|That's what relocatable files _are_ (like C dot-oh files).

Ha ha. Try dumping one some day. Thre MAY be a few compilers that get
this right (in fact Mark Rain's Mary2 was supposed to, ten years gone
by), but they're not what you'd call common....

Here's the acid test: can you take your relocatable file and use it on
a machine with a different architecture? I thought not....

||> ...reaches for asbestos-type trousers...
||> 
||> What, you think I'm defending J, just because I don't like FORTRAN?
||> They're practically dialects of each other anyway, with their
||> array-o-centrism, type-o-phobia, line-oriented syntax, proliferation
||> of system-reserved mechanisms, encouragement of semantically
||> inexplicable floating-point arithmetic and general inattention to
||> actually solving the problem....

|"Array-o-centrism" is an important feature for a large set of 
|important applications.  I don't know what you mean by "type-o-phobia".

No it is not. SUPPORT for arrays is important - surely important
enough to justify that arrays be ONE of the type-construction methods
directly supported by the standard library. But giving it a
distinguished syntax is perhaps going too far - and giving it 90% of
the operator namespace (as in J) is criminal.

And by "type-o-phobia" I intended to suggest an attitude that types
are a "magic" mechanism which the user can't be allowed to use on hir
OWN behalf, to solve actual problems....

|To be sure, Fortran hasn't got a complete set of type construction
|tools (Fortran 90 makes this worse by introducing explicit pointers
|as the only mechanism for recursive data structures, etc.).  I don't
|know what you mean by "line-oriented syntax" either, but human factors
|experiments have shown that people intuitively use lines in certain
|ways and languages which don't conform to these ways induce larger
|numbers of errors.  What's a "system-reserved mechanism"?  Come up

System-reserved mechanisms: fortran has keywords and weird syntaxes
for this and that. J reserves all the little squigglies for its own
use.  Neither of them lets you introduce a new class of literals (even
one so simple as, say, frequencies).... It's not always attainable,
but if there are TWO of a kind of thing (any kind of thing) in a
language, you have to ask yourself why the programmer can't decalare
more....

|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.
Von Neumann pointed this out, and I concur: there aren't enough
things in nature with a dynamic range in excess of 2^64 to justify
giving hardware support to floating point; what it's actually USED for
is to avoid thinking about dynamic range at all, and that leads to
bugs.

In principle we could have 128-bit integers that are significantly
faster than IEEE floating point - and a lot more useful - and I think
it's really stupid that the FORTRAN community has such a stranglehold
on hardware architecture that people don't wake up and start demanding
good support for integers.

And if you really *need* fp, for that one case in a million, software
emulation isn't so bad: given an extra 64 guard bits you can probably
forestall normalisation for a LOOONG time. (Cogent comments welcome,
flames not. Bin having this argument for too long to want a fist fight
over it anymore...).

|As for "actually solving the problem", most of the other things you
|mentioned are required in order to make "solving the problem" possible.
|The problem is to run large scientific/numerical calculations on existing
|hardware with existing software technology.  The existing hardware is
|too slow, has too little memory, and the existing software technology
|is inadequate at automatically making best use of the existing speed
|and space based on a purely abstract problem definition.  

Am I arguing? I just think that getting locked in worse is stupid.

||> |[...]
||> |Ok.  This could be defined as the operation of REDUCE.  You'd have
||> |to add a way of passing the identity element (and a way of stating
||> |that there isn't one).
||> 
||> Gotta be one, if you're going to go the directional route. But you can
||> always use the end element of the array if you are SURE that's what
||> you want.
|
|I thought the identity element was returned for _empty_ arrays.  The
|end element of an array doesn't exist in this case.  What you want is
|to give the _user_ the option of stating whether this should be considered
|an error or not.  So, you pass an identity element as an additional 
|optional argument to reduce and if it is omitted you treat empty arrays 
|as errors.  

Nono, you missed the point. Some operations (like "+") make SENSE for
empty arrays, and there you supply the appropriate value (0). Others
(like "min") only make sense on an empty array in an extended domain
(for present purposes: don't make sense) and so you REQUIRE at least
one element, pass THAT as the identity, and then reduce the REMAINDER
of the array (which will now be length 0 if the original was length
1).

The tree is like this:

	 /\
	x /\
	 y /\
	  z  i

with i, the "identity", in the end position, which is syntactically
and semantically disitinguished - as I pointed out, it can even have a
different type. That's one of the other things that's different about
the "random tree" version, incidentally: it HAS to be symmetric.

|I don't question the possibility of such a thing, but what would anyone
|use it for?  As I said, I'll take you word for it that it _may_ be
|useful, but I think I'd rather have the default version of `scan' not
|allow it - such a rarely needed feature, if accidentally used, is almost certainly just an error.  Can you givean example of an algorithm which
|can make sensible use of unordered scan results?

Yes. You are searching in a tree, and you want to use the natural tree
structure and not get it flattened to a vector. I *don't* know of a
language with a type structure in which this very practical problem
can be made to drop out notationally though - but wait another five or
ten years, and you'll see it cropping up. It'll look like an alternate
interface that makes an automatic coercion (an interface inheritance,
actually) unnecessary.

|For example: let's scan addition across an list of integers (1,3,5,7,9).
|What happens if the result is (16,8,5,15,25) [I summed from the middle 
|element out, alternating left and right]?  Is this meaningful to any
|algorithm you know?

You need to use "cons" instead of "+" to see how it might be
interesting - "+" has the wrong algebraic properties for this
operation, and that ought (in principle) to be a static type error.

|Haskell doesn't have these functions extended to directly handle
|multi-rank arrays, much less arbitrary directions through them.
|Such capability can only be handled by mapping the array into a 
|list of sub-arrays (along the desired axis) and defining the 
|function `f' on those sub-arrays.

Which is fine. Doesn't involve any runtime overhead if it's done right
(ha ha).

|By the way, at this point I've spent about the same amount of time
|studying Haskell as J - cumulatively about five hours each.  I find
|Haskell much more legible and easy to use (which isn't saying much).
|Given that Haskell is a strict functional language and J isn't, if
|the argument is that there is an advantage to functional programming,
|then Haskell must be better according to that measure.

It's still a dog, but it's a friendly dog. I'm with you on that.
----------------------------------------------------------------------
stephen p spackman         Center for Information and Language Studies
stephen@estragon.uchicago.edu                    University of Chicago
----------------------------------------------------------------------