[Top][All Lists]

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

Re: Octave coding standards

From: Rik
Subject: Re: Octave coding standards
Date: Fri, 05 Nov 2010 16:40:22 -0700

> I m just trying to make a package (the first one) and I have a question
> regarding standards (after reading the docs). Does the following
> function respect Octave coding standards? Any way to check it myself
> through a script or sth?


I took a look and I have some suggestions.  First, I know Texinfo and
documentation can be a bear to learn, but here are some things that I would

1) You need a line '@end deftypefn' at the end of the documentation section
to close the section for the parser.  This is mandatory.
2) Tex can choose to insert a page break at any time.  In order to hold
blocks of code together, such as your @example/@end example, you need to
use the construct @group/@end group around your code block and within the
@example block.
3) Texinfo uses the '@' character to call macros.  If you need a literal
'@' in the text, such as where you define an anonymous function handle,
then you must use the macro '@@'.  Thus, "f = @(x) ..." becomes "f = @@(x)
...".  This is mandatory.
4) Use @var{} for marking variables; To highlight code in the
documentation, which you have, use @code{}.
5) For bonus points, you can use the special macro @dots{} rather than
three literal dots "..."
6) According to the documentation guidelines, the first paragraph is
written in the active voice, present tense.  Later paragraphs usually sound
better in the passive voice.  What this means is that the first sentence
"Generates orbit of a ..." becomes "Generate orbit of a ...".  I know the
difference is only a single 's', but it makes a large difference to native
English speakers.

In the coding block, you define the function as "nestfun (fun, init,
iter)", but in the documentation string it was described as "nestfun (f,
init, n).  Octave has no problem if you document a function as f(x,y,z) and
then define it to be f(a,b,c).  But as a programmer I have to remember the
mapping from c->z, b->y, etc.  This is inconvenient and where possible I
use the same names for the Octave code as the documentation.

7) Change function declaration to: function x = nestfun (f, init, n)

Secondly, be very cautious about what inputs you accept and validate them.
 Many users, myself included, often don't read the documentation for a
function but simply call it with some arguments.  If the function
complains, I might *then* read the documentation to see why it didn't work
as expected.  In any case, you can expect to get a lot of garbage.  So my
next comments relate to input validation.

8) Be nice, and accept a string with a function name, as well as function
handles.  For example, nestfun("sin", 1, 10).  See the following code.
  # Convert function string name to a handle if necessary
  if (ischar (f))
    f = str2func (f, "global");

9) Validate the input N.  Imagine that this function is eventually
converted to C++ for efficiency.  Your for loop uses N as the terminus and
if someone enters 5.1 then the loop for (i=1; i++; i==n) is going to go on
forever.  N should really be an integer, and a positive one at that.  See
the following code.
  if (! (isscalar (n) && n == fix (n) && n > 0))
    error ("nestfun: N must be an integer greater than 0");

10) No need for extra spaces around components in vectors. "[ rows, cols ]
= ..." can just be "[rows, cols] = ...".

11) Use explicit end block naming.  Examples: if/endif, for/endfor,
while/endwhile.  In your case, the for loop needs to terminate with "endfor".

12) Use parentheses or other methods to disambiguate your for loop end
condition.  You have:
    for count = 1:iter - 1
which I can read as either 1:(iter-1) or as (1:iter) - 1 === 0:(iter-1).  I
know that Octave chooses the first interpretation, but there really
shouldn't be any reason for doubt.

13) Use (:) to return a column vector from function f.  By doing this you
don't need the logic which checks for the orientation of the return value
from f and possibly transposes it.

Finally, to really be able to drop a function into Octave it needs to be
self-testing.  Add some %!test or %!assert blocks.  Here are a few examples:

14) Add test code
%!assert(nestfun(@(x) 1, 1, 10), ones (1,10))
%!assert(nestfun(@(x) 0, -1, 10), [-1, zeros(1,9)])
%!assert(nestfun(@(x) 2*x, 1, 10), 2.^[0:9])

%% Test input validation
%!error nestfun()
%!error nestfun(1)
%!error nestfun(1,2)
%!error nestfun(1,2,3,4)
%!error nestfun(@sin, 1, ones(2,2))
%!error nestfun(@sin, 1, 10.1)
%!error nestfun(@sin, 1, -10)

I've attached a version of the file with my changes for your perusal.

Good luck coding,

Attachment: nestfun_edited.m
Description: Text Data

reply via email to

[Prev in Thread] Current Thread [Next in Thread]