About documentation

John Johnson johnatl at mac.com
Fri Aug 20 21:40:54 CEST 2004


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The documentation for Mozart/Oz is among the best I've seen. Right up 
there with the documentation for Java. A lot of people have spent a lot 
of time working on it, and I appreciate it. I hope that my  beginner's 
mind can perhaps further the proliferation of Mozart/Oz. Please don't 
take this as a flame, troll, or anything other than for what it is 
intended, constructive criticism.
All examples used are meant to be typical examples, and are not meant 
to pick on any particular author.

When I learn a new language, I like to 'type stuff in' and see it work. 
It gives me a feel for the syntax and structure of the language, and 
also teaches my fingers to type new words and sequences of letters. 
This helps offload the typing to my cerebellum, so I can think on 
higher levels than my typing. Most of the Mozart documentation I've 
seen so far uses a structure something like this:

+---------------------------------+
| Example output                  |
+---------------------------------+

This show the Example Output
lots more text
which is created by this:

<High level concept>
<Another high level concept>

Lots of text here.
Here is the definition for so and so:

<High level concept>=
	S = {Whatever 5}
	W = {SomethingElse argument: <Definition>}

this does so and so...
a lot more text

<Definition>=
	A = {SomethingHere 'test'}
	T = {Whatnot 87}

and so ...

<Another high level concept>=
	V = {Routine X 5}
	W = {Sub Y}
- --->%-----------------------------------------

Looking at this from a beginner's perspective, it would appear, since 
you've read how powerful Mozart is, that you could enter:
<High level concept>
<Another high level concept>
run it, and see the output. You quickly learn that, no, you have to 
define those, so you:
<High level concept>=
	S = {Whatever 5}
	W = {SomethingElse argument: <Definition>}
but it won't run because the definition references another definition 
which is defined later. So:
<Definition>=
	A = {SomethingHere 'test'}
	T = {Whatnot 87}
and it still doesn't run because you forgot that <Another high level 
concept> isn't defined, so:
<Another high level concept>=
	V = {Routine X 5}
	W = {Sub Y}
which is better, but it still doesn't run. If you're lucky, you might 
discover that adding
declare
at the very top of the file will get rid of some of the errors. Then 
you realize that the definitions that say:
<Something>=
	whatever
is not a definition at all, but the <Something>= just means to 
substitute what follows for the reference you saw earlier. You're then 
faced with the task of putting in }, ) and end's to fix the syntax.
Now it might possibly run. After all that, you're probably tired of 
Mozart, and ready for lunch.

It would seem to me to be much simpler just to give a free standing 
example and explain the operation afterwards. This way, the student is 
quite possibly looking at the output from the example they cut and 
pasted into the Mozart OPI. Comments can be added to the code, and, if 
need be, a number or letter added in comments on important lines so 
they can be called out in the explanatory text.
Here's a minimally commented example:
declare
% Widget Creation
Window = {New Tk.toplevel tkInit(title: 'Captialization')}
Entry = {New Tk.entry tkInit(parent: Window)}
Button = {New Tk.button tkInit(parent: Window
           text: 'Change Capitalization'
           % This is the action performed when the button is clicked.
           action: proc {$}
             String = {Entry tkReturn(get $)}
           in
             {Entry tk(delete 0 'end')}
             {Entry tk(insert 0
                 % the following fun definition is mapped to each 
character in the
                 % String, changing it's case.
                 {Map String fun {$ I}
                            case {Char.type I}
                            of lower then
                               {Char.toUpper I}
                            [] upper then
                               {Char.toLower I}
                            else I
                            end
                         end
                 }
                 )
             }
           end
          )
          }
% Geometry Management
{Tk.send pack(Entry Button fill:x padx:4 pady:4)}

I would like to see meaningful variable names used. As an example:
<Widget creation >=
W={New Tk.toplevel tkInit(title: 'Capitalization' )}
E={New Tk.entry    tkInit(parent:W)}
B={New Tk.button   tkInit(parent: W
                          text: 'Change Capitalization'  
                          action: <Action definition >)}
Not only are we learning a new language and it's syntax, but we're also 
dealing with cryptic variable names. Witness:
<Widget creation >=
Window = {New Tk.toplevel tkInit(title: 'Capitalization' )}
Entry = {New Tk.entry    tkInit(parent:Window)}
Button = {New Tk.button   tkInit(parent: Window
                          text: 'Change Capitalization'  
                          action: <Action definition >)}
Now the variables represent concepts already familiar to us. Later when 
we see:
{Tk.send pack(Entry Button fill:x padx:4 pady:4)}
rather than
{Tk.send pack(E B fill:x padx:4 pady:4)}
We don't have to figure out that E doesn't mean East or some other 
unknown, and B doesn't mean Bottom, or another unknown.

As far as marking up the documentation for online display, the current 
markup complicates cutting and pasting from the web page to Emacs. When 
examples are pasted, many times there are 0xCA characters pasted 
instead of spaces, and sometimes where there shouldn't be a space at 
all. In Emacs, these look like rectangles, which are remarkably similar 
to the [] used in case statements. Once you figure out the rectangles 
shouldn't be there, you wind up deleting all the 'rectangle' 
characters, which includes the empty brackets. Now the example code is 
broken.

As far as formatting source, there doesn't seem to be a universal style 
used by everyone. "Scrunching" seems to be pervasive. E.g.
local X in {CondSelect W key eeva X} {Browse X} end 
local X in {CondSelect T key eeva X} {Browse X} end

while compact, this isn't as intelligible as:
local X in 
      {CondSelect W key eeva X} 
      {Browse X} 
end 
local X in 
      {CondSelect T key eeva X} 
      {Browse X} 
end

Another example:
local Max X Y Z in 
   proc {Max X Y Z}
      if X >= Y then Z = X else Z = Y end 
   end 
   X = 5
   Y = 10
   {Max X Y Z} {Browse Z}
end

is hard to follow due to the if...end being all on one line, and there 
are also two statements on the  next to the last line.
And last:
% case for pattern matching
proc {Insert Key Value TreeIn ?TreeOut}
   case TreeIn
   of nil then TreeOut = tree(Key Value nil nil)
   [] tree(K1 V1 T1 T2) then 
      if Key == K1 then TreeOut = tree(Key Value T1 T2)
      elseif Key < K1 then T in 
        TreeOut = tree(K1 V1 T T2)
        {Insert Key Value T1 T}
      else T in 
        TreeOut = tree(K1 V1 T1 T)
        {Insert Key Value T2 T}
      end 
   end 
end

Is hard to follow because some statements follow then clauses on the 
same line, and some begin on new lines. At first glance, it looks like 
a 'wad of stuff'.

% case for pattern matching
proc {Insert Key Value TreeIn ?TreeOut}
   case TreeIn
   of nil then 
       TreeOut = tree(Key Value nil nil)
   [] tree(K1 V1 T1 T2) then 
      if Key == K1 then
         TreeOut = tree(Key Value T1 T2)
      elseif Key < K1 then T in 
        TreeOut = tree(K1 V1 T T2)
        {Insert Key Value T1 T}
      else T in 
        TreeOut = tree(K1 V1 T1 T)
        {Insert Key Value T2 T}
      end 
   end 
end
While a subtle difference, eliminates the confusion on the four lines 
beginning at 'of nil...'.

There seems to be a shyness about using spaces

X=Z*Z

is perfectly legible when standing alone on the line above, but mixed 
into a program, at first glance it appears to be a word beginning with 
X and ending with Z. As research has proven, ylu ckn clinte tpe mhggje 
lqwwkls and still read the words, since we see words as pictures, 
rather than individual letters. If the line above is changed to:
X = Z * Z
it is obvious at a glance that it is not a word, but an assignment 
statement. Blank lines also help break up a program into sections. I 
understand that C-M-x evaluates to the previous blank line, so it would 
be as nice to use a single % on a line to create the division.

And last, most of the code available isn't commented very much, if at 
all. A comment before or on every line usually isn't necessary, but one 
at the beginning of each function block would be very helpful, 
especially to the author in coming years :-)

Thanks for hearing my out. I hope I didn't ruffle to many feathers.

Regards,
   JJ

http://www.pragmaticprogrammer.com/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (Darwin)

iD8DBQFBJlPT56Q2CqQ+d1wRAmW7AJ9QdGPSg3GgRjoYyfMSjwTq3dAW8QCaAxmU
51Ic0/ZnL+uacAcNVKfsTZU=
=A769
-----END PGP SIGNATURE-----





More information about the mozart-users mailing list