[racket] in praise of if's mandatory else clause
Matthias Felleisen wrote at 05/30/2011 01:44 PM:
> On May 29, 2011, at 10:45 PM, Richard Cleis wrote:
>
>> Can you effectively forbid programming constructs in your programming group?
>>
>
> In the Racket world you can create a language for your project that programmers must use
This is a good idea, although a lot of the reasons for organization- and
project-specific "coding standards" we had in, say, C++ aren't relevant
in Racket, because Racket is so much safer, and the standards were often
there to avoid doing dangerous things that the language permitted yet
that could be distilled into simple rules. There are still some that
still sorta apply, like what exceptions you use, identifier naming
conventions, and whether "cond" and "case" always have "else". In the
earlier days of C++, we also had to have rules for things in the
language that didn't work for us, like "don't use exceptions or
templates because they are buggy or nonexistent on some of our platforms
compilers."
I guess there are also matters-of-preference, for consistency, that some
organizations might want to use their own project-specific "#lang". For
example, one organization might make people use internal "define" and
square brackets. Another might dislike internal "define" and insist on
always using the shorthand instead of "(define X (lambda ... ...))".
And indentation rules, if you want to tackle those with the reader.
I'd be much more interested in a "general good practices" tool, to
inform and educate abouts suboptimal things in code that it can detect.
This could be done a lot at a module level, but needs whole-program for
some things. I've been building up a mental list of some things I would
like this to do, including:
* Suggest to remove unused "require"s. Sometimes these are left because
of code changes, but some programmers just paste the nearest big list of
"require"s they can find, on the assumption it will have most things. A
complementary feature would be to suggest which "require"s are missing,
which hopefully would placate the copy&pasters.
* Suggest cleanups to awkward syntactic structures, like "This 'let' and
two 'let-values' can be turned into one 'let-values'. Shall I?" Just
make up a list of what patterns it looks for or wants to transform, and
maybe make sure its suggestions would converge, so that it can't
flip-flop every time you run it and apply its suggestions.
* Suggest performance fix to "(cond ((equal? (EXPENSIVE-EXPR) 42) ...)
((equal? (EXPENSIVE-EXPR) 69) ((equal? (EXPENSIVE-EXPR) 101) ...) ...)",
to only call "(EXPENSIVE-EXPR)" once (and perhaps use a "case"), if you
know if has no side-effects, or perhaps if it is missing an annotation
that says you really mean to . Similar with "(LOOPING-CONSTRUCT ...
(EXPENSIVE-EXPR) ...)". I see this a lot in code, and I have been
wondering whether it makes more sense to mathematicians. I could see it
from people coming from a pure-functional language where the interpreter
would normally optimize that, and somehow that programmer finds that
more readable.
* Do very expensive farming of system to detect places where programmers
did copy&paste reuse, when for maintainability (and perhaps code
footprint) we'd prefer that the code be generalized. I'm pretty sure
that there is a programming practice that involves the train of thought
"this problem A is similar to problem B that I have seen before, so I
will copy the code for A and modify it to do B", and some programmers do
this a lot more than others do. The funniest I've seen was a
construction, "(if BOOLEAN-VARIABLE HUGE-BLOCK-OF-CODE-1
HUGE-BLOCK-OF-CODE-2)", where ediff eventually showed that the two huge
blocks of code differed only a single Boolean constant, equal to
"BOOLEAN-VARIABLE". More commonly, this takes the form of a copy&pasted
procedure within the same module, multiple definitions from one module
pasted into another (which may not be modified), or an entire module
cloned as a starting point. A checking tool for this would also be
useful for identifying generalization opportunities throughout code that
wasn't copy&paste'd, such as two procedures that coincidentally turned
out almost the same, or a code pattern that is used widely and could be
a macro. I think there's a PhD in there, unless it's already been
mostly done. You'd want to make sure you had good corpora to work with
before you started, both open source and agreements to access
proprietary code. I'm guessing that the most applicability is to
proprietary code. If you could generate module repackagings and
generalizing procedures and macros, that would be even better, but even
suggestions and metrics would be useful.
No doubt there are more things a "general good practices" tool could
identify.
--
http://www.neilvandyke.org/