While developing a Claude Agent Skill for library(debug), I discovered antipatterns only through testing Claude’s actual suggestions. During this process, I found that some hallucinated patterns were either incorrect or, worse, produced the opposite of the intended effect—failing to optimize debug/3 when the topic was disabled, e.g.
Calls to debug/3 and assertion/1 are removed when the code is compiled for optimization unless the Prolog flag optimise_debug is set to
true.
This raises a question: Could the compiler or runtime warn when debug/1 is used incorrectly?
Below are the antipatterns I’ve identified so far.
Problem: Conditional Enable at Entry Points
Anti-pattern:
main(Argv) :-
( member('--debug-parser', Argv)
-> debug(parser)
; true
),
run(Argv).
Why wrong: The conditional remains in compiled code permanently. debug/1 calls are not optimized away (they’re control predicates, not trace calls). This adds overhead on every invocation.
Problem: Runtime Enablement of Debug Topics
Anti-pattern:
enable_compiler_debug :-
debug(lexer),
debug(parser),
debug(semantic).
main(_) :-
enable_compiler_debug,
run_compiler.
Why wrong: Debug/3 calls are optimized away at compile time. By the time enable_compiler_debug runs, the debug/3 calls may already be gone. This only works if you explicitly set optimise_debug=false, which makes code slower.
Problem: Using plunit Setup/Cleanup to Enable Debug Topics
Anti-pattern:
setup_debug :-
debug(parser),
debug(lexer).
cleanup_debug :-
nodebug(parser),
nodebug(lexer).
:- begin_tests(parser, [
setup(setup_debug),
cleanup(cleanup_debug)
]).
test(example) :-
debug(parser, 'Debug message', []), % This won't show
parse('input', AST),
assertion(AST = expr('input')).
:- end_tests(parser).
Why wrong: Setup/cleanup hooks run during test execution, but test predicates are compiled earlier. If debug topics aren’t enabled during compilation, debug/3 calls are optimized away and won’t produce output even if setup enables the topic later.