>  Thanks, Dan. An example showing what *doesn't* work and explaining why
>  not is a huge aid to understanding it.

The simplest and most illustrative example of what doesn't work is:

           $: 0
        |stack error
        |       $:0
           
That is, in this case, $: refers only to itself, and so would recurse
forever, only J won't let you do that.  This finite recursion is in contrast
to your standard infinite loop, which J is happy to let you construct &
execute.   Now, of course, certain infinite loops will hit the physical
machine's limits (e.g. out of memory, precision of numeric values, etc) and
then J will halt.  But generally speaking these values are large enough so
that either you don't have to worry about them, or when you do you can
generally anticipate & work around the limits (e.g. reading in a 4GB file in
chunks).  

In contrast, the limit of recursion is finite and *small*: 

           $:@:>: :: ] 0   NB.  Increment & recurse until stack error;
report maximum stack depth
        6666
           
and it is not imposed by your physical hardware, but by the compiler options
used when your J binary was generated.  Essentially, you're hitting *C's*
stack depth.  Now, of course, many $: problems are logarithmic
(divide-and-conquer) and 2^6666x is a large number (and it gets better if
you can make more decisions at each branch).  So in many cases this depth
may be sufficient.  But I've hit cases where it isn't, and this constraint
forced me to change my statement of the problem to be solved (i.e. J code),
generally for the worse (additional complexity & maintenance).  And often
enough, at least in the early days of my J career, that now I'm wary of $:
altogether.  Since those days Roger has addressed this issue to a
considerable extent, but it still occasionally bites (e.g. search [1] for $:
).

Of course, the obvious response is that programming is defined by the
tension between "saying what you want" (expressing the problem "naturally")
and working with the resources you have (e.g. available stack).  And that
sometimes you have to compromise, as when I rewrite a $: verb to be a ^:
verb, or a hybrid.  My take on that is:

        1.  The stack limit feels very artificial, and the field has a
number of well studied methods to avoid it (e.g. skip C's stack and use the
heap).
        2.  Sometimes you can predict when $: is risky, but often you can't.


In light of (2), one oftens ends up rewriting $: as ^: or something
prophylactically; so why not just write it that way in the first place?
(And this tends to drive a feedback cycle where your expertise with $:
wanes, and as a consequence you're less comfortable with it, so you reach
for it less often .... )

>       foo=: 3 : 0
>               0 $: y
>       :
>               ...
>       )

Nope, that won't work.  Think of $: referring to the line it's in at the
very most (which line can be inside a explicit definition, e.g. foo could
call Fibonacci or Factorial).  In fact, that's how it's implemented [2].
You can use  0&$: : foo  instead.  Or something sillier:


        (N=:'foo')=: 3 : 0
                0 N~ y
        :
                ...
        )

-Dan


[1]  Outstanding bug list in J: 
     http://www.jsoftware.com/jwiki/System/Interpreter/Bugs
     Search for $: .   Not all bugs are related to stack size.

[2]  Implementation of  $:  :
     http://www.jsoftware.com/pipermail/general/2006-May/027079.html

[3]  Interesting note on the value of  $:  :
     http://www.jsoftware.com/pipermail/general/2006-May/027090.html



----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to