The use of tacit in this case is to allow access to global x and y which is
not a normal type of problem in an application. This one is unusual in that
it is actually a mixture of an explicit part within a tacit part. The
reference to locally defined x is long after the list of global names
defined was found tacitly.

Tacit definitions can get difficult to read, particularly if they are very
long. Conversely it is normal for simple tacit expressions to be used
extensively in explicit definitions. What is important, as in any
programming language, is to document well. There are fewer clues in a tacit
definition than in an explicit definition as no names are given other than
the definition name.

Tacit definitions are one liners.This can make them even more difficult to
read. One way to make tacit definitions easier to document well and to break
it into manageable pieces. Take a recent problem posed grouping lines based
on a given word:

NB.*group v Group lines (]) starting with a line containing keyword ([)
tomatrix=. ,;._2      NB. Separate lines into rows of a matrix
findstring=. [:+./E.  NB. Check if line (]) contains the keyword ([)
selectlines=.<;.1     NB. Group lines starting with keyword
group=:((findstring"1 selectlines ]) tomatrix) f. NB. Put it together

Granted, it is a little overboard on the documentation as the definition
would not be that hard to follow as a one liner, but by breaking the
definition into pieces one can test the pieces more easily before putting it
altogether. And each part can be commented as can be done in explicit
definitions.

But most definitions I make are explicit. Tacit definitions I do make are
usually small and relatively simple. And usually I make them tacit as a fun
challenge.

Sometimes I will enclose an explicit definition within a tacit part like
adding a specification of rank to the definition. But that really messes up
the debugger. So even though it makes the definition clearer, it seldom
works well.

But what makes all the difference in maintaining an application after having
not touched it for a year or so is being able to read the programming
language, whatever it is. Books and classes teach one how to write a
programming language. Unfortunately, they seldom teach one how to read the
language.


On Mon, Sep 26, 2011 at 6:38 PM, Christopher McIntosh
<[email protected]>wrote:

> (Despite the conversations that have brought us to this point -- and
> ignoring that scenario altogether)  I have a hypothesis that for the
> long-term, a team equipped in a J-focused environment needs to have a very
> detailed design-time road map to avoid a possible scenario in its project
> whereby re-designing one aspect has a negative and significant impact on
> unrelated aspects of the project.   For our team, we had become interested
> in J because of highly regarded recommendations about its fit into an XP
> environment.  At the same time, it appears that folks are suggesting that
> design decisions are required to be made earlier (moreso comparable to the
> waterfall paradigm).  And this is important to the long-term
> maintainability
> (in terms of cost and time) of the project.
>
> For example, when considering a function (or function group) and choosing
> the tacit implementation, I have been advised from 2 (seemingly?)
> incompatible perspectives.
>
> One one hand, it is my understanding that one of the primary advantages to
> a
> tacit design is the ability to abstract a dependency on names.  On the
> other
> hand, I understand that, in an ambivalent function, such is not the case.
>  That, unfortunately, this won't work for the dyadic half, since it could
> not distinguish between local x and global x, as x is defined locally in
> both the verb and the adverb.
>
> And when I look at some implementations, I see that this appears to be the
> case.
>
> NB.*nl v selective namelist
> NB. Form: [mp] nl sel
>
> NB.
> NB.   sel:  one or more integer name classes, or a name list.
> NB.         if empty use: 0 1 2 3.
> NB.   mp:   optional matching pattern. If mp contains '*', list names
> NB.         containing mp, otherwise list names starting mp. If mp
> NB.         contains '~', list names that do not match.
> NB.
> NB.  e.g. 'f' nl 3      - list verbs that begin with 'f'
> NB.       '*com nl ''   - list names containing 'com'
> nl1=.(([:4!:1])&(]`(0 1 2 3"_)@.(0=#))) :: cutopen_*z*_
> nlz=:(nl1 : ((4 : 0)nl1)) f.
> if. 0 e. #y do. y return. end.
>
> if. #t=. x -. ' ' do.
>  'n s'=. '~*' e. t
>  t=. t -. '~*'
>  b=. t&E. &> y
>  if. s do. b=. +./"1 b
>  else. b=. {."1 b end.
>  y=. y #~ n ~: b
> end.
> )
>
> I see that (on the dyad side of the picture) there is still reference to
> local x. But, this should not be an issue, should it? Since we could go
> ahead and reference x__anotherlocale. In my prima facie testing, I don't
> notice the issue. Tests which had failed in previous tests, pass with this
> example.
>
> I realize that the road ahead is a long one to become proficient at
> recognizing some of the subtleties that, presently, have us perplexed.
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
>
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to