From: jlg@cochiti.lanl.gov (Jim Giles)
Subject: Re: Types, arrays, generality, and notation (was: Fortran90 and Arrays)
Organization: Los Alamos National Laboratory
Date: Thu, 9 Apr 1992 19:24:21 GMT

In article <1992Apr9.042240.26041@socrates.umd.edu>, rockwell@socrates.umd.edu (Raul Deluth Miller-Rockwell) writes:
|> [...]
|>    Your J version of this operation was _very_ clumsy:
|>          A =: 2 # ((#A) $ 0 1) # A
|> 
|> On the other hand, the J version is, in essence, side effect free.

Place finger in mouth, pull it out rapidly making POP sound, point
finger straight up and wave in circular motion, say "woopeee".

If the natural way to think about what you're doing involves side-effects,
use the damn side-effects!  This notion of removing side-effects from
a language just for the esthetic "purity" of it has no appeal to me at
all.

|> [...]
|>    How would this have been different if I had used the example:
|>          A(0: :2) = B(1: :2)
|> 
|> I would have had to write a completely different expression which
|> expressed the merging of A and B.  Perhaps I should have written such
|> an expression for the expression in A, above?  [by the way, what's the
|> blank space for, in A(0: :2)?]

I have, by direct count, told you the rules for triples four times
in this discussion.  There is nothing complicated about them.  The
first element of the triple is the initial subscript value to use
which defaults to the lower bound if it is omitted.  The second
is the limit of the subscripts which defaults to the upper bound
if omitted (as in this case).  The third element is the stride 
to use which defaults to one if omitted (in which case it is 
usual to also omit the final colon).  I could, in the above, have
written the two colons side-by-side with no space but I wanted to
emphasize that the second element of the triple was omitted.

Note, the rule for triples is the same as the rule for DO loops.
In particular, if the stride is not one, the limit (the second
element of the triple) may not actually be used as a subscript.
For example, 1:11:3 goes from one to eleven by threes - that is,
it takes on values of 1, 4, 7, and 10.  The fact that it uses the
_same_ rule as DO loops makes it very intuitive for the target
users (experienced Fortran 77 users).

Now, would you care to actually answer the question I implied above?
How does J represent the assignment "A(0: :2) = B(1: :2)"?

|> [...]
|> Yes, A must appear on the right hand side of the assignment.  Whether
|> or not that means that A's storage can not be reused depends on
|> whether or not the prior value of A must be referenced after this
|> assignment.  [Remember, in J, the identifier is not the object.]

The identifier is not _the_ object in _any_ language.  The identifier is
_a_ syntactic object which _denotes_ something in the semantic domain(s)
of the language.  In this case, the identifier denotes an aggregate,
the size, shape, and base type of the aggregate are semantic properties
that the identifier denotes - as are the specific values within the
aggregate.  

What you appear to be saying is that in J _all_ these properties must 
be respecified when assigning - you can't independently alter the 
attributes denoted by the identifier (like ,say, _some_ of the values
in the array).  To simulate this, you may reference the prior definition 
of the identifier as part of the new description of it, but you must,
somehow, fully respecify all the attributes at every assignment.

This characteristic of J means that I can't enhance legibility and
reliability of the program by statically specifying _some_ of the
attributes I want associated with a given name and having the 
compiler statically enforce my desired constraints.

|> [... distinction between `type' and `value' in a typeless language ...]
|> 
|>    I have no use for the distinction.  Please post any specific
|>    example which you feel contradicts my opinion.  If you can't then
|>    it's clear that you don't have a use for the distinction either.
|> 
|> Sure, if I've an expression of the form:
|>    A + B
|> 
|> then both A and B must have some sort of numeric type.

This can be _statically_ determined?  That is, the compiler can _always_
tell at compile time that both A and B obey this constraint?  (Here
I'm assuming that `+' is _never_ overloaded for non-numeric data.)

|> [... doing static type checking on f x ...]
|> Eh?  But f's arguments are restricted in rank.
|> 
|> Maybe you're complaining that you want 'x' to be restricted so that it
|> can only be a vector?  If so, try
|> 
|>     f @only_vector:  x

You mean I have to explicitly say this in the code at the site of _USE_
of the function or variable?  Bletch.  Also, it looks to me that this
would usually be a run-time test unless I made such a constraint at
_every_ assignment to x and the compiler can actually determine that
I had done so.

|> [...]
|>    What I want is a way to state right up front that "every occurrence
|>    of x in this program is a one-d array" and that "every occurrence
|>    of f in this program is a function which takes one-d arguments" and
|>    have the compiler check every occurrence of these two identifiers
|>    to make sure they obey these constraints.
|> 
|> Well, if you're not going to change f, you could use
|> 
|> f:   =. f  @ only_vector:       fix
|> 
|> where
|> fix =. f.

As far as I can decipher, this does less than _half_ of what I asked
for.  It defines f in such a way that it carries its run-time test
on its argument wherever it goes.  It does not make the test work
at compile time and it does not prohibit assignments to x which
violate the constraint I wanted to put on it.

|> [...]
|> 
|> So far, you've only asserted that there is difficulty for someone who
|> knows the language.  Besides, if it were really obscure you could
|> always comment the code.

I used to know APL fairly well (in the seventies).  I always had trouble
understanding it.  Especially other people's code.  Moreso than I have
trouble understanding other people's C code (which is also hard because
of myriad non-mnemonic operators, way too many precedence levels, and
too densely packed expression notation).  I have less trouble undersatnding
other people's Fortran code and even less other people's Pascal code.
Pascal has numerous faults, but its legibility is first rate.

|> [...]
|>    No, most of them quickly admitted that the same program in Algol
|>    would have been fairly easy to grasp immediately.  Saving
|>    keystrokes is not an issue, saving programmer time is.
|> 
|> Hmm.. I don't think your experts knew APL very well.

I worked at the help desk at my university.  I interacted with most
of the APL users in the whole school as well as the _implementors_
of the local APL processor (I had to - if a problem arose which 
I could not answer).  All agreed that its syntax was opaque.

|> [...]                  However, Fortran's iron rule is better for
|>    reliability than J's lack of any discipline at all.
|> 
|> All I can say is you've not programmed in J to make a statement like
|> this.  J can be pretty picky about error conditions.

Well, if it's that picky there should be a simple answer to the
question I keep asking: how do I declare that identifier X must 
_never_ be assigned anything which is not of a particular type
while still permitting the value of X to vary?

|> [...]
|>          REDUCE (FUN, ARRAY, DIM, DIR)
|> [...]
|> 
|> Also, this looks more like a conjunction (which derives a function
|> from several pieces of information) than an adverb (which derives a
|> variant of the function without further information).

I'll have to take your word for it.  You seem to have a better handle
on how to apply words which describe _natural_ languages to different
properties of artificial languages.

|> [...]
|> Note that the user of J can define a REDUCE word with exactly these
|> semantics.  [...]

Oh?  I thought you said originally that J couldn't specify whether
something was to be reduced left-to-right, right-to-left, or in 
any order.  Whether the function FUN is to be regarded as left-
or right-associative or just associative makes a considerable
difference numerically as well as (in some cases) making a difference
in speed.

|> [...]        Though, not the same syntax -- a function in J, be it
|> declared via an adverb or conjunction or other technique, always
|> follows the same syntactic rules.

So?  Fortran functions always follow the same syntactic rules too.
More legible ones (with the arguments enclosed in parenthesis and
separated by commas - so you can easily tell at a glance _that_ it's
a function reference and you can easily see what sub-part of the
expression corresponds to each argument to the function).

|> [...]
|>    |> Remember, identifiers in J have no more significance than braces
|>    |> or parenthesis do in other languages.  [...]
|> 
|>    A property of the language I find _very_ bad and I can't imagine
|>    why you think it useful.
|> 
|> I find it conceptually simpler than systems where I must pre-declare
|> assignments.  If, as is usually the case, I do not re-declare any
|> names, the entire definition for the name is in one spot, [...]

You mean _one_ of the entire definitions of the name is in one spot.
If you're working on a large code in a team, of if you're importing
code from another site to be integrated into your own code (like
getting a professionally written graphics package) this is dangerous.
Suppose both you and the other programmer define a global called X.
Very probably the two definitions are very different.  Yet the compiler
will accept _both_ definitions and, at any point in the program, will
use whichever was defined most recently.  With conventional languages,
the type mismatch could be found before run-time (though whether at
compile or load time depends on how you integrate components).

Notice, I mention this as two people working together.  The same 
problem exists on large one-person codes when development is spread
out over time.

|> [...]                                                     which means
|> I don't have to go hunting around through source code to find the rest
|> of the definition.

But, you do!  That's exactly the problem I see for J.  In conventional
languages, there is no hunting: you go to the beginning of the current 
scope (of which there are few, since the concept of scope is independent
of the concept of assignment) and the declarations of most things are 
right there!  In J the scope of a given identifier is apparently from
wherever it is defined - wherever that is.  There is no common place to 
go look.  It could be anywhere.

Further, you must hunt _sequentially_ *backwards* to find the most
recent definition since just finding _a_ definition is not adequate.

There are further problems.  Suppose you define FUN2 as a function which
is defined terms of FUN1 - another function.  Subsequently, you redefine
FUN1 (you claim that this is something you like to do while developing
code).  But now FUN2 is still defined in terms of an obsolete version
of FUN1 (if I understand your rules correctly).  This means that every
time you redefine one thing, you must redefine _all_ the things that
depend upon it!

|> 
|>    |> The only real difference between an explicit identifier and some
|>    |> intermediate result is that of persistence.
|> 
|>    There is another difference (more important in my view): the type
|>    of the identifier cannot be locally and statically determined like
|>    the type of an expression (all of whose operand types are known).
|> 
|> The type of an identifier can be determined from the expression used
|> to declare it.  [...]

Which is _not_ locally visible at the site of the use of the identifier,
nor is it in some cannonical place (like the beginning of the present
module or procedure).  It can be _anywhere_!

|> [...]
|>    To be sure it is _sometimes_ desireable for the attributes normally
|>    used as types to be allowed to vary instead.  In this case, you
|>    should have to say explicitly that you're doing so.  Even then,
|>    it's useful to be able to restrict the attributes in some way - you
|>    might want X to be allowed to be integer, floating-point, or double
|>    precision but never complex or character, for example.
|> 
|> In which case, the user can define a word which requires this
|> condition and use it wherever appropriate.

Exactly.  The `word' I want to define is the identifier itself.  This
way I can't forget to use the limitation `word' when I use the identifier.
The way you appear to be suggesting is like that thing you mentioned 
before:

      f @only_vector: x

Which only applies the limitation when you remember to explicitly 
state the `@only_vector' part on every use of f.  And, so far as
you've presented, there is no way to make such limitations on
assignments.  For example, how do I define X or some `word'
associated with X that prohibits X from being assigned anything
but integers?

J. Giles
Newsgroups: comp.lang.misc