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/
_________________________________________________
 For list-related administrative tasks:
 http://lists.racket-lang.org/listinfo/users

Reply via email to