4

I have a hierarchy of functions, many functions are called by a single function.

There are three options:

  • Use defun: i.e. all functions are global even the ones that are only intended for internal use by a single function. Use a package to export the functions that clients should call.
  • Use labels so that the functions have lexical scope and are free to call any other function within the labels.
  • Use nested flet so that every function can access the functions it needs.

Is there a best way to do this? If so, what is it?
What are the considerations that I should think off?


NOTE: I'm learning , therefore I'm interested in the 'right way'™ and less in the perhaps more pragmatic just write it as you like and don't think too much about it.

sds
  • 729
  • 5
  • 12
Kasper van den Berg
  • 2,636
  • 1
  • 16
  • 32

1 Answers1

2

Generally Lisp is less dogmatic about programming style. Some programming style might not be desirable in hand-written code, but might be useful for generated code. Since generated code (-> macros) is popular and well-supported in Lisp, programs may generate quite complex code.

Development process with refactoring

Often writing code is an evolutionary process with some refactoring. One thing I've done sometimes is this:

  1. write a longish and complex function
  2. identify the need to document parts of the code
  3. instead of conventional documentation -> extract parts of the code into named local functions with arglists. The name makes the purpose clear and the arglist is the interface
  4. if these local function look generally useful and will be reused -> extract them into global functions -> document and/or export them

We can think of various arguments for certain styles:

(the following lists are very likely not complete)

Flat global functions in a package, where only the relevant are exported and the local/helper functions are probably not exported and/or specially named.

Negative

  • possibly many names in a package
  • possibly more complex argument lists to pass in everything necessary
  • need to keep them local in a package, possibly with special naming convention
  • structure of the code might be more difficult to recognize, since dependencies are not visible based on lexical scope

Positive

  • possibly more independent
  • testing individual functions may be easier
  • easy tracing / stepping of individual functions
  • possibly easier to document

Unclear

  • performance impact unclear

Global function with multiple local functions organized in some lexical scope

Positive

  • variables in scope can be shared -> leads to shorter arglists
  • dependencies better visible due to hierarchy of lexical scopes
  • local functions can't be used outside of their intended scope -> information hiding
  • functions may be easier to understand in context

Negative

  • code gets more hierarchical -> looks more complex -> chance for new errors
  • tools may not be able to trace or step local functions -> needs a Lisp with support for that when these tools might be necessary
  • global function can get long
  • maybe more difficult to test
  • disassembly gets long, when looking at the machine code
  • documentation makes the code even longer
  • deep(er) indentation levels
  • tool-based locating of the source code for a local function might be more difficult
Rainer Joswig
  • 2,190
  • 11
  • 17