#Dev

The Art of Not Programming in Dyalog APL: A Guide to Avoiding Common Pitfalls

Tech Essays Reporter
5 min read

A comprehensive guide to writing clean, maintainable Dyalog APL code by avoiding traditional functions, control structures, and other anti-patterns that lead to technical debt and unreadable code.

In the world of Dyalog APL programming, there exists a peculiar but enlightening document that serves as both a warning and a guide: "Don'ts Or how not to program in Dyalog APL." This comprehensive list of programming anti-patterns reads almost like a manifesto against certain practices that have become all too common in the APL community, and it offers valuable insights into writing cleaner, more maintainable code.

The first and perhaps most fundamental principle outlined in this guide is the emphatic rejection of traditional functions (tradfns) and control structures. The argument against tradfns is multifaceted and compelling. First, there's the cognitive burden of naming things – a task that even the most experienced programmers acknowledge as one of the hardest challenges in software development. Dyalog's dfns (direct functions) elegantly sidestep this issue by automatically naming arguments as ⍺ and ⍵, and by not requiring explicit naming of results. This seemingly small convenience eliminates three difficult decisions every time you write a function, decisions that have been refined through the collective wisdom of the APL community.

But the problems with traditional functions run deeper than just naming conventions. The real culprit, according to this guide, is the use of control structures like :If, :While, and :For statements. These structures, while familiar to programmers coming from other languages, introduce a dangerous temptation: the accumulation of technical debt. When faced with a bug or design issue, it becomes all too easy to simply wrap problematic code in a :If :Then :Else construct or, worse yet, trap the error with :Trap 0. This approach avoids the more difficult but ultimately more rewarding task of rethinking and refactoring the code.

The guide argues that control structures allow programmers to avoid the crucial step of naming new functions. Since naming is hard and programmers are inherently lazy (a trait that can be productive when properly channeled), control structures become a crutch that prevents the creation of well-defined, single-purpose functions. The result is often a sprawling function with embedded comments that attempt to explain what the code does, rather than letting well-named functions speak for themselves.

This philosophy extends to the structure of functions themselves. The guide advocates for functions that operate at a consistent level of abstraction, composed either primarily of primitive operations or calls to other functions. The goal is readability – functions should be understandable either in English or in APL, but not a confusing mix of both. This principle is violated when major functionality is dangled off the end of an :If clause, or when control structures are packed into single, diamondized lines that sacrifice clarity for brevity.

The guide takes a similarly hard line on several other APL-specific practices. Namespace scripts are dismissed as poorly understood constructs that introduce more problems than they solve. The ⎕CS system function is singled out for particular criticism, though the exact reasons for avoiding it are left somewhat mysterious – a deliberate choice that adds to the document's mystique.

Classes receive special attention, with the guide arguing that they should only be used when proper encapsulation is intended. The vast majority of classes written in Dyalog APL, it suggests, are little more than collections of public fields without proper getters and setters. Instead of traditional object-oriented approaches, the guide proposes using regular functions in named namespaces to act as methods, with unnamed namespaces serving as instances. This approach, while unconventional, aligns with APL's functional programming roots and avoids the complexity of full object-oriented systems.

The guide also addresses several practical concerns, such as the use of ⎕NEW for creating objects. While ⎕NEW is a powerful tool, the guide argues that it should be wrapped in static methods (conventionally named New) to ensure that all instances of a class are created in known locations. This practice makes it easier to manage dependencies and maintain code over time.

Error handling receives particular scrutiny, with the guide advocating for specific error trapping rather than the catch-all approach of trapping error 0. The argument is that broad error trapping obscures the true behavior of code and makes debugging nearly impossible. Instead, programmers should expect valid arguments and trap errors as high up the call stack as possible.

Perhaps the most controversial advice in the guide is the suggestion to avoid commenting lines of code altogether. Instead of inline comments, the guide recommends carefully choosing function names, arguments, and results to make the code self-documenting. A few well-placed comments at the top of a function describing its purpose and interface are deemed sufficient. This approach, while extreme, reflects a deep belief in the power of clear, expressive code to communicate its intent.

The guide concludes with advice on testing and GUI programming. Tests should exercise APIs and verify results, not expose internal architecture or data structures. GUI programming should avoid blocking calls like ⎕DQ in favor of callback-based approaches that enable automated testing. These recommendations reflect a broader philosophy of writing testable, maintainable code that can evolve over time without breaking existing functionality.

What makes this guide particularly valuable is not just its specific recommendations, but the underlying philosophy it embodies. It represents a vision of APL programming that embraces the language's functional nature, prioritizes clarity and maintainability over familiarity, and challenges programmers to think deeply about their design choices. While some of its recommendations may seem extreme or impractical in certain contexts, they serve as a valuable counterpoint to more conventional approaches and encourage programmers to question their assumptions about what good code looks like.

In the end, "Don'ts Or how not to program in Dyalog APL" is more than just a list of programming taboos. It's a call to elevate the practice of APL programming, to move beyond the comfortable but limiting patterns inherited from other languages, and to embrace the unique capabilities and idioms of APL. Whether one agrees with all of its prescriptions or not, engaging with its ideas can only lead to better, more thoughtful code and a deeper understanding of what makes APL special.

Comments

Loading comments...