[racket] in praise of if's mandatory else clause

From: Neil Van Dyke (neil at neilvandyke.org)
Date: Mon May 30 16:58:00 EDT 2011

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/


Posted on the users mailing list.