[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: succinctness = power

On Tuesday, June 4, 2002, at 12:02 AM, Daniel Weinreb wrote:
> Executable comments are great when you can do them, but if you look at 
> the
> example commented code that I mailed out recently, I don't see any way 
> to
> make comments of that sort be executable.

The need for non-executable comments depends heavily on the language and
application you are using.
Machine language obviously requires a great deal of documentation.
Lightweight languages (being those languages which are easy to learn and 
while still retaining expressive power) require fewer comments, almost 
by definition.

For the example you mailed out recently (copied below) assumes a great 
deal of
domain specific knowledge (what is a PRN? a PFE? ...) This must appear 
in the documentation, but presumably not in the code.

The comments in your example are of several types:
  1. explaining what the procedure does ("...filling in the PRN if this 
is a new process")
  2. providing invariants (so that the sending process continues before 
    called process executes.
  3. explaining why choices were made ("as an optimization ....)

The first type of comment could be minimized by using lightweight 
and this would minimize the amount of work need to maintain the code 

The second type might be handled using some sort of assertion language
which can express notions of the states of processes.

The third type expresses programmer intent and would not be easily
replaced by assertions (unless some sort of performance assertion
were made, i.e. the qualitative optimization were made quantitatively

> I agree with Christopher Barber: programmers really, really have got to
> learn
> to maintain comments, just the same way they have to learn other good
> programming practices.

Agreed, but even better would be to minimize the need for comments
and thereby decrease the number of comments needed to be maintained.

Below is a translation of Dan's code from an earlier post
into Jscheme (jscheme.sourceforge.net) taking the liberty of assuming
that there is a LexToken constructor that can take a Procedure as an 
rather than needing to be inner-sub-classed.

Several of the explanatory comments have been embedded in
the procedure names. This code still leave much unexplained,
e.g. the APIs of all of the objects, the need to setCollaborationUse,

;; See http://.... for definitions of PRN, PFE, and events ...
(define (sendEventToPFE event)

    (define (get-and-cache-PRN event)
     (let ((pid (.getPID (.correlation (.to event))))
           (processname (.processToStart (.to event))))
       (if (equal? #null processname)
           (.getPRN pid)
         (let ((prn  (.getPRN resources_ processName)))
           (.setPRN pid prn)

   (define (generate-PID-and-send-to-PFE event)
     (if (== 0 (.getTick (.pid event))) ;; optimization -- only enqueue 
if needed
            (.pid event))

   (define (make-LexToken-action-Thunk prn event)
    (let ((pfe (PFEFactory.instance)))
      (if (and (.handlesPRN pfe prn)
               (not (.isPFE (.from event))))
          (let ((newPID (generate-PID-and-send-to-PFE)))
              (.handleEvent pfe event)
              (if newPID
                  (.setCollaborationUse (.correlation (.to event)) 
             (QueueMessage. event)))

      (make-LexToken-action-Thunk (get-and-cache-PRN event) event)

Here is Dan's original Java....

>    * Enqueue this message event to the node that has the PFE that 
> handles the
>    * PRN of this process, filling in the PRN if this is a new process.  
> If the
>    * PFE that handles this PRN is on this node, it will just do the work
>    * directly (as an optimization).  However, if it is also from the 
> PFE on
>    * this node, it will still enqueue it, so that the sending process 
> will be
>    * continued before the called process executes.
>    **/
>   private void sendEventToPFE(final MessageEvent event) {
>     String processName = event.to().processToStart();
>     final int prn;
>     if (processName != null) {
>       prn = resources_.getPRN(processName);
>       event.to().correlation().getPid().setPRN(prn);
>     } else {
>       prn = event.to().correlation().getPid().getPRN();
>     }
>     new LexTxn() { public Object action() {
>       PFE pfe = PFEFactory.instance();
>       if (pfe.handlesPRN(prn) && !event.from().isPFE()) {
>         boolean newPid = false;
>         if (event.pid().getTick() == 0) {
>           // Just use the queue manager to fill in the Pid, then send 
> to PFE.
>           QueueManagerFactory.instance().generatePid(event.pid());
>           newPid = true;
>         }
>         pfe.handleEvent(event);
>         if (newPid) {
>           // handleEvent filled in the collaboration use.  So that this
>           // case returns the same kinds of collaborations as the case
>           // where the message is enqueued, we null it out before 
> returning.
>           event.to().correlation().setCollaborationUse(null);
>         }
>       } else {
>         QueueManagerFactory.instance().enqueue(new QueueMessage(event));
>       }
>       return null;
>     }}.execute(log_);
>   }
> "event" and "prn" had to be declared "final", and the "return null" is
> because we don't happen to need to return anything to the caller in
> this case.  Annoyances, yes, but in practice pretty tolerable.

Alas, the context of this procedure is not clear from the code snippet
(what is a PRN, PFE, etc.) and clearly this is information that needs to 
documented somewhere, but perhaps not in the code itself.

In a higher level language the need for comments can be reduced by 
  confusing artifacts (like anonymous inner-classes) with the more 
notions (like  callbacks). A more Lispy approach would be to build a
domain-specific minilanguage and reimplement in that.

It seems that comments are necessary to the degree that the programming
language is unable to express what the