Extra DRY with Literate Programming
NOTE: The mobile version of this article doesn’t format code sections properly. Try the desktop version instead.
I like my code DRY (Don’t Repeat Yourself)—no boilerplate, no repetition. But there’s always a handful of things I can't clean up. Literate program helps me scrub out those last few stubborn repetitions. Because it's basically a pre-processor, Literate programming can DRY out things that no programming language can. Want to write your company's copyright notice once and reference it in all your source files? Want a project name variable that you can reference across your project? Literate programming is up to the challenge.
Here1, I reuse a copyright notice in several files. If I ever need to update it, I change it in one place and run ‘omd tangle’; it gets changed everywhere.
File: main.md
# My Example File
## Here is my copyright notice
```C {name=copyright}
/*
* Copyright (C) 2024 Adam Ard
*
* Permission is hereby granted to use, copy, modify, and distribute
* this code for any purpose, with or without attribution.
* This code is provided "as is", without warranty of any kind.
*/
```
## Files
Here are two C files with some mildly interesting example code. Notice how they both have a reference to my copyright in them.
```C {tangle=file1.c}
@<copyright@>
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
```
```C {tangle=file2.c}
@<copyright@>
int is_prime(int n) {
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
```
Now if I run ‘omd tangle,’ Organic Markdown spits out my files:
terminal output:
$ ls
main.md
$ omd tangle
$ ls
file1.c file2.c main.md
$ cat file1.c
/*
* Copyright (C) 2024 Adam Ard
*
* Permission is hereby granted to use, copy, modify, and distribute
* this code for any purpose, with or without attribution.
* This code is provided "as is", without warranty of any kind.
*/
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
$ cat file2.c
/*
* Copyright (C) 2024 Adam Ard
*
* Permission is hereby granted to use, copy, modify, and distribute
* this code for any purpose, with or without attribution.
* This code is provided "as is", without warranty of any kind.
*/
int is_prime(int n) {
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
To make life even easier, I add a ‘copyright-year’ variable to a yaml block at the top of the markdown file. Then I can reference it in my copyright code block:
main.md
---
constants:
copyright-year: 2024
---
# My Example File
## Here is my copyright notice
```C {name=copyright}
/*
* Copyright (C) @<copyright-year@> Adam Ard
*
* Permission is hereby granted to use, copy, modify, and distribute
* this code for any purpose, with or without attribution.
* This code is provided "as is", without warranty of any kind.
*/
```
When 2025 comes, I’ll simply change the year in the yaml header, and run ‘omd tangle’ again. All the files will get updated.
Something else I like to do is add the project name to the yaml header block. Then I can use it all over the project. Below, the filenames, executable name, code blocks and documentation all use the project-name variable defined in the yaml header block:
main.md
---
constants:
copyright-year: 2025
project-name: dry-example
---
# My Example File
## Here is my copyright notice
```C {name=copyright}
/*
* Copyright (C) @<copyright-year@> Adam Ard
*
* Permission is hereby granted to use, copy, modify, and distribute
* this code for any purpose, with or without attribution.
* This code is provided "as is", without warranty of any kind.
*/
```
## Files for the @<project-name@> project
Here are four C files with some mildly interesting example code I got
from ChatGPT. Notice how they all have a reference to my copyright in
them.
```C {tangle=@<project-name@>-1.c}
@<copyright@>
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
```
```C {tangle=@<project-name@>-2.c}
@<copyright@>
int is_prime(int n) {
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
```
```C {tangle=main.c}
@<copyright@>
#include <stdio.h>
int factorial(int n);
int is_prime(int n);
int main() {
printf("Running @<project-name@>\n\n");
printf("factorial of 5: %d\n", factorial(5));
printf("is_prime 29: %d\n", is_prime(29));
}
```
## Build the examples
```bash {name=build menu=true}
gcc @<project-name@>*.c main.c -o @<project-name@>
```
It all works as expected:
terminal output
$ ls
main.md
$ omd tangle
$ ls
dry-example-1.c dry-example-2.c main.c main.md
$ omd run build
$ ls
dry-example dry-example-1.c dry-example-2.c main.c main.md
$ ./dry-example
Running dry-example
factorial of 5: 120
is_prime 29: 1
Using executable code blocks, I can transform the project-name into an include guard2 and use it in a header file. When I add a ‘*’ to the name of a literate reference, the tangle command inserts the output of running the code block instead of inserting the code block itself, as it normally would:
main.md
## A code block to translate input text into `#include guard` format
```python {name=to-include-guard}
for c in "@<txt@>":
if c.isalnum():
print(c.upper(), end="")
else:
print("_", end="")
print("_H", end="")
```
## Header files
```C {name=include-guard}
@<to-include-guard*(txt="@<project-name@>-@<num@>")@>
```
```C {tangle=@<project-name@>-1.h}
#ifndef @<include-guard(num=1)@>
#define @<include-guard(num=1)@>
int factorial(int n);
#endif /* @<include-guard(num=1)@> */
```
```C {tangle=@<project-name@>-2.h}
#ifndef @<include-guard(num=2)@>
#define @<include-guard(num=2)@>
int is_prime(int n);
#endif /* @<include-guard(num=2)@> */
```
console output
$ omd tangle && omd run build
$ ls
dry-example dry-example-1.c dry-example-1.h dry-example-2.c dry-example-2.h main.c main.md
$ cat dry-example-1.h
#ifndef DRY_EXAMPLE_1_H
#define DRY_EXAMPLE_1_H
int factorial(int n);
#endif /* DRY_EXAMPLE_1_H */
$ cat dry-example-2.h
#ifndef DRY_EXAMPLE_2_H
#define DRY_EXAMPLE_2_H
int is_prime(int n);
#endif /* DRY_EXAMPLE_2_H */
Now that’s some DRY code! If you’d like to learn more about Organic Markdown, checkout the github project: https://github.com/adam-ard/organic-markdown. The main readme has more instructions and links to additional documentation.
Here is the full code listing for reference. Happy Literate Programming!
main.md
---
constants:
copyright-year: 2025
project-name: dry-example
---
# My Example File
## Here is my copyright notice
```C {name=copyright}
/*
* Copyright (C) @<copyright-year@> Adam Ard
*
* Permission is hereby granted to use, copy, modify, and distribute
* this code for any purpose, with or without attribution.
* This code is provided "as is", without warranty of any kind.
*/
```
## A code block to translate input text into `#include guard` format
```python {name=to-include-guard}
for c in "@<txt@>":
if c.isalnum():
print(c.upper(), end="")
else:
print("_", end="")
print("_H", end="")
```
## Header files
```C {name=include-guard}
@<to-include-guard*(txt="@<project-name@>-@<num@>")@>
```
```C {tangle=@<project-name@>-1.h}
#ifndef @<include-guard(num=1)@>
#define @<include-guard(num=1)@>
int factorial(int n);
#endif /* @<include-guard(num=1)@> */
```
```C {tangle=@<project-name@>-2.h}
#ifndef @<include-guard(num=2)@>
#define @<include-guard(num=2)@>
int is_prime(int n);
#endif /* @<include-guard(num=2)@> */
```
## Files for the @<project-name@> project
Here are four C files with some mildly interesting example code I got
from ChatGPT. Notice how they all have a reference to my copyright in
them.
```C {tangle=@<project-name@>-1.c}
@<copyright@>
#include "@<project-name@>-1.h"
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
```
```C {tangle=@<project-name@>-2.c}
@<copyright@>
#include "@<project-name@>-2.h"
int is_prime(int n) {
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
```
```C {tangle=main.c}
@<copyright@>
#include <stdio.h>
#include "@<project-name@>-1.h"
#include "@<project-name@>-2.h"
int main() {
printf("Running @<project-name@>\n\n");
printf("factorial of 5: %d\n", factorial(5));
printf("is_prime 29: %d\n", is_prime(29));
}
```
## Build the examples
```bash {name=build menu=true}
gcc @<project-name@>*.c main.c -o @<project-name@>
```
In this article, I use Organic Markdown: https://github.com/adam-ard/organic-markdown
https://en.wikipedia.org/wiki/Include_guard