From J Wiki
Jump to: navigation, search

Back to: Vocabulary

The T-block (T) and the if.-control

The control  if. commences a conditional construct. This takes one of the following forms

if. T do. B end.

if. T do. B1 else. B0 end.

if. T do. B elseif. T2 do. B2 end.

if. T do. B elseif. T2 do. B2 elseif. T3 do. B3 end.   NB. etc. etc.

Like all controls,  if. can only appear inside the body of an explicit definition

Note: You can't use else. after elseif.

if. T1 do. B1 elseif. T2 do. B2 else. B3 end.           NB. J signals 'control error'

If you want a catch-all condition, use the following

if. T1 do. B1 elseif. T2 do. B2 elseif. do. B3 end.     NB. J treats (absent) T3 as TRUE

The omitted T-block (elseif. do.) is better than elseif. 1 do. because lint understands it.

The placeholders B and T (plus their numbered fellows) do not stand exclusively for nouns (although as a special case they can be replaced by nouns). B and T follow the rules of individual sentences. They can also be replaced with multiple consecutive sentences (each on a separate line) called blocks.

In recognition of this capability, T is called a T-block whether or not it stands for an actual block -- or in the most general case

  • nothing at all
  • a single word, e.g.  0,  1,  2,  2.54 7.35
  • a single phrase, e.g.  0 = #y
  • a single sentence e.g.  yempty=. 0=#y
  • a single line, broken into multiple sentences by means of controls, e.g.  if. T do. if. T1 do. S1 else. S2. end. end.
  • a block of sentences, one per line (see example below).

And by analogy let's call B a B-block.

The T-block has these special properties:

  • If T is absent, it is formally TRUE (as in the empty elseif. above)
  • Executing T must create a noun value (call it c)
      • c can be of any type, even character or boxed, without J signalling an error
      • If c is an empty list then T is formally TRUE
      • If c is an atom then T is formally FALSE if  c-:0 otherwise in all other cases it is formally TRUE
      • If c is an array then c behaves like  {.@, c i.e. all atoms except the first are ignored.
  • If T is TRUE then J executes the B-block which follows do.
  • If T is FALSE then J executes the B-block which follows else. -- however if  else. is absent ...
      • if  elseif. is also absent, the result is: no-operation
      • if one or more  elseif. are present, J tests their T-blocks in turn, just as it does with if.

The reasoning behind the T-block having these properties is highly pragmatic

  • for runtime efficiency
  • to simplify the formulation of logical conditions
  • to avoid being over-demanding or unforgiving over the exact circumstances in which T is formally TRUE
      • in normal usage you'd arrange for T to give a Boolean atom, viz. either 0 or 1
      • but if T (accidentally) gives a list of more general type (especially a list of 1 Boolean atom), it is FALSE only if the first item is 0
  • to permit more readable/debuggable logical conditions, by letting you compute c (above) in stages.

Practical uses for a single-sentence T-block

1. A typical use for the simplest construct:  if. T do. B end. is to skip code if a newly computed array has no items:

if. # myarray =: makemyarray'' do.
  NB. This is block B.
  NB. Put code HERE to execute ONLY if myarray has items to process.

In this example, myarray is both built and tested for content by the sentence

# myarray =: buildmyarray''`

which constitutes the T-block (T), whole and entire.

One outcome of this sentence is to build  myarray . But as far as the T-block T is concerned, the only outcome that matters to its proper function is the result of  # array and whether it is zero or not.

  • If it is zero, then the B-block B is not executed.
  • Otherwise it is.

Practical uses for a multi-sentence T-block

1. When designing a digital circuit, arguably one of the easiest ways to merge several logic inputs, e.g. a, b, c, d, into one 0|1 output, especially if the truth-table is best expressed with several "don't-care" entries, is to express the overall Boolean function f in canonical form.

Strictly: one of several published canonical forms, e.g. WikiPedia:Algebraic normal form.

These canonical forms of f typically have the structure: f = f1  OR f2  OR f3  OR f4 ...

In J, an implementation of f might benefit from using a multi-sentence T-block, like this:

   NB. Boolean function f(a,b,c,d)
   f=: 3 : 0
or=. +.
  a=. 0{y
  b=. 1{y
  c=. 2{y
  d=. 3{y
  a or b or c or d
do. 'TRUE' else. 'FALSE' end.

2. J has no way of writing a single conditional that is only partly evaluated, as in (test1 AND test2) -- where if one test fails, the other test is not evaluated. If you write (phrase1 *. phrase2) then both phrases are always evaluated.

If you want to avoid evaluating part of your condition, use a nested if. inside your T-block.

Example: Suppose

  • filetest is a verb that crashes when called with an empty argument
  • filespec describes the files we want to look at (empty if we don't want to examine any)
if. 0=#filespec do.
  NB. dummy B block - do nothing if filespec is empty
  if. #filelist=. getfilelist filespec do.  NB. if there are files...
    *./ filetest filelist                   NB. test them
  else.                                     NB. If there are no files...
    1                                       NB. do the empty list anyway
  NB. At this point the last line executed gives the result of the T-block
  NB.  (but NOT the result of the verb itself.)
  NB. Put code HERE to execute if all files OK,
  NB. or (if there are no files) so long as filespec is nonempty

3. Oddity: after the T-block of an if. is executed, the "most recent result" is reset to i. 0 0.

t =: 3 : 0
  if. do.
  smoutput 'true!'  NB. Executed, even though the only sentence executed was `0`
   t 0
   t 1

The Result of a Verb

The result of an explicit verb is the result of the last sentence executed that is not in a T-block.

This means exactly what it says: it does not mean "the last sentence that was in a B-block".

Once a T-block starts, until it ends, embedded B-block sentences do not contribute to the verb's result.

b=: verb define
y   NB. The verb's result so far is (y). NOTE: NOT in a T-block.
  NB. Begin T-block...
  if. do.  NB. ensures the following B-block is always executed...
    NB. This is a B-block. BUT NOTE: - it's inside a T-block.
    NB. THEREFORE its result CANNOT become the result of the verb.
    12345  NB. ---here's the result of this B-block.
  NB. ...End T-block
  NB. (dummy B-block)
   b 987
   NB. ---NOT: 12345