From: rockwell@socrates.umd.edu (Raul Deluth Miller-Rockwell)
Subject: Re: Fortran90 and Arrays
Organization: Traveller
	<ROCKWELL.92Apr8001532@socrates.umd.edu>
	<1992Apr8.180420.9294@newshost.lanl.gov>
Date: Wed, 8 Apr 1992 21:45:02 GMT

Jim Giles:
   My example didn't copy _any_ elements `in place'.  The destination
   locations were completely disjoint from the source locations.

What does completely disjoint mean?  It's my understanding that you
were modifying storage in the very array you used as an argument.

   The word `type' means any static attribute which is associated with
   an identifier in such a way that _every_ occurrence of the
   identifier in a given scope has that attribute.

Why is type a property of an identifier, and not a property of either
a function or of data?  You're saying that Fortran is typeless except
for identifiers?

   The word `type' has no meaning at all if all attributes are
   dynamically alterable.  In this case you _may_ decide to apply the
   word `type' to certain properties of _values_, but such a
   distinction is not useful.

Why is this distinction not useful?

   You have been juggling semantics rather creatively to claim that
   every assignment actually introduces a new scope.  If this is true,
   then it saps the meaning of the word `scope' to nothing.

Well, I have been using 'scope' in two different ways.  Mostly this is
because I don't know what other word to use to describe these
concepts.  Perhaps 'lifetime of a binding' and 'visibility of a
binding'?

   |> [...]
   |> >  |> The advantage of this rule is 'rank' has a consistent and easily
   |> >  |> understandable definition which is usable with any operation in
   |> >  |> the language.  No exceptions are needed.
   |> 
   |> >  I still don't understand what it does.  Does it apply to the vector
   |> >  or to the array?
   |> 
   |> Well, neither.  It applies to the operation.  The derived operation
   |> then applies to the vector or to the array.

   Well, I can see that this "easily understandable" definition is too
   complex for you to describe in a news article.  I'll just have to
   get used to the fact that the quote symbol is used by J to do
   something arcane and hidden (which appears to has something to do
   with transposition, but I can't be sure).

I've described it a number of times.  But I can describe it again:

J has a metafunction, denoted with a double quote, which specifies the
rank of a function.  If you have an expression of the form:
        function " integer
then 'function' can only process arrays with the rank indicated by
'integer'.  If you have an expression of the form:
        function " (left_integer, right_integer)
then 'function' then 'left_integer' denotes the maximum rank of the
left argument and 'right_integer' denotes the maximum rank of the
right argument.

For example,
     f"1 x
means that f applies to the vectors in x, and any additional
dimensions are processed "in parallel" [with a unique instance of f
applied to each vector].

For example,
    x g"1 2  y
means that g applies to the vectors in x, and the matrices in y.
Again, any additional dimensions are processed "in parallel".  Also,
note that these extra dimensions must conform [same sort of rules as
scalar extention].

Finally,
   h"_1
indicates that h does not get to see the first dimension of its
argument(s).  In other words, h is applied, "in parallel" across this
dimension.  Needless to say, where h is used dyadically, the leading
dimensions of the left and right arguments must conform.

This may seem like an advanced concept, but getting it right once
makes the definition of the rest of the language quite a bit simpler.

   Terseness in and of itself does not achieve clarity, and can hinder
   insight into the problem.

A terse language can be used in a verbose fashion.  A verbose language
can not be used in a terse fashion.  Beyond that, insight is required
to express a concept in a concise fashion.

   The trade-off between being terse and being verbose is the effort
   to find the thin balance being succinct.  The problem actually has
   two dimensions.  There is the spectrum from densely packed
   information to loosely packed information.  And there is the
   spectrum running from underspecification to overspecification.

Yes.

   APL and J both make the mistake of assuming that density is
   desirable.  Lots of small operators densely packed together
   inhibits legibility.  Especially if these operators have no
   mnemonic value or are composed of the same symbols as other
   operators with different meaning.  For example, I'm told that the J
   operator for the Boolean `and' function is `*.' and that `+.' is
   the `or' operator.  The thing is that `+.*' is the inner product,
   and who knows how many other operations use dot with plus or
   asterisk (and other symbols) to mean completely different things.

What sort of metric are you using for legibility?  One that reflects
length of code, or one that reflects the underlying semantics?

Also, J has departed from APL in the definition of inner product.
Instead of '+.x' (the APL notation), J uses '+/ .*' (note that
summation must now be stated more explicitly, and that an asterisk is
used to denote multiplication).

J uses '.' and ':' as inflection marks, which modify the token
immediately preceeding them on the line.  It's not very hard to
remember to use <<space dot>> where before you just used <<dot>>.  Or,
to be more accurate, you must now use <<slash space dot>> where before
you used <<dot>>.

But I think the thing you're really objecting to is that J doesn't
impose any reserved words on the user.  Since you also object to the
fact that J allows the user to define keywords, I'm not sure I
understand what it is that you dislike -- except that "J is not
Fortran".

   I've seen APL experts spend 30-40 minutes studying a _single_ line
   of APL before they thought they understood what it did - in fact,
   this was common.

Well, it's pretty simple to trace through an operation to see how it
works.  I don't think I've spent that long studying a single line
since the year I learned the language.

And, once you've recognized an expression, you don't need to repeat
the effort to recognize it the next time around.

Finally, that single line might accomplish the equivalent of several
pages of code in some other language.  If so, your experts might have
taken even longer to figure out what was happening in this other
language.

   In fact, the _less_ densely packed the language's notation is, the
   better (within reason).  Certainly, operators, function names, and
   other syntactic objects should have mnemonic value (and they need
   to be large enough tokens that this mnemonic property is visible).
   The most common operations can be small - but conventional notation
   already has such operators defined.  Less common operations need
   larger names.

So you're saying more verbose than J (as in, FORTRAN), but less
verbose than COBOL (as in, FORTRAN)?  You can follow this
specification if you like -- but I see no reason to consider it a
universal law.

On the other hand, it did take centuries for mathematicians to stop
denoting multiplication with the word 'TYMES' and to start using the
'x' symbol.  So maybe you're onto something deep here...

   The other aspect of this question is the degree of specificity that
   the language requires/allows.  Here the _user_ must be allowed to
   decide what degree of specification is needed.  Conventional
   Fortran _requires_ all arrays to be of known base type and fixed
   rank.

I thought you just said that the user must be allowed to make the
decision about whether this is needed?

   For the overwhelming majority of uses, this is an appropriate
   constraint.

How did you determine this?

From what I understand: primarily, by examining code written in a
language where there was no choice in the matter?

   Our extension provides mechanisms for declaring variables whose
   rank and/or base type is part of the _value_ of the data.  Since
   this is actually an unusual need, we require explicit declarations
   of the fact that rank or base type are variable.  As far as I can
   tell, in J the rank, base type, or even whether the thing is an
   array at all cannot be declared statically.

The present mechanisms have been adequate so far.

   To be sure, Fortran requires you to be overspecific.  It seems to
   me that J doesn't allow adequate specificity.  Further, there is a
   balance point at which most programs exist.  Additional specificity
   beyond this balance point should require explicit declaration.
   LESS specificity than the balance should _ALSO_ require explicit
   declaration.

Could be.

But I think it's easier to add special cases to a language than it is
to add generality to a language.

   |> [...]  Further, the example was stated as requiring a function
   |> >  to handle arrays of rank 4 through 7 - without an run-time
   |> >  test, how does your J code insure that arrays of rank greater
   |> >  than 7 aren't incorrectly passed?

   |> Well, since no actual operation has been specified, it's rather
   |> difficult to provide code for it.  However, if the operation was
   |> called 'operation', I could use: operation"7 to make sure that
   |> arrays of rank greater than 7 aren't incorrectly passed.

   And this is not a run-time test?  How is it applied?  Is this the
   form of the declaration of `operation' or is it how I must
   reference `operation' if I want the test applied?  If J were less
   dense, I probably would have been able to answer some of these
   questions from the example itself.

This declaration affects that particular instance of 'operation'.  It
does not affect the identifier 'operation', but affects that
particular instance of its use.  If you wanted this declaration to
apply to each use of 'operation' you could use:
   operation=:  definition_of_operation"7

Remember, identifiers in J have no more significance than braces or
parenthesis do in other languages.  The only real difference between
an explicit identifier and some intermediate result is that of
persistence.

Also, note that all identifiers rely on either constants or i/o
routines for their values.  Constants are known, and i/o has known
properties.

Compilation is the act of partial evaluation, to take advantage of
constant results and invariants (which are often, in essence,
constants).

-- 
Raul Deluth Miller-Rockwell                   <rockwell@socrates.umd.edu>
Newsgroups: comp.lang.misc