Proposal Details

Proposal: Add support for conditional compilation directives (similar to #define / #ifdef) in Go

Introduction

Go currently does not support preprocessor directives like #define or #ifdef, which are widely used in C/C++ projects. This was an intentional design choice to keep the language clean and readable. However, for developers working on low-level, high-performance systems such as databases, file engines, or embedded runtimes, this limitation imposes significant friction.

Motivation

In C/C++, conditional compilation enables:

  • Switching algorithms or implementations at build time.
  • Stripping debug or logging code from production builds.
  • Including architecture-specific optimizations.
  • Maintaining a single source file with multiple code paths for different configurations.

In Go, we must simulate this with multiple files and //go:build constraints, which fragments the logic and harms maintainability.

As a real-world example: I'm building a database engine in Go using a B+Tree structure with persistent storage, range scanning, and concurrency support. To extract maximum performance, I often need to:

  • Enable or disable optimizations like async flush, page caching, or internal tracing;
  • Use CPU-specific instructions or branching logic (e.g., arm64 vs amd64);
  • Inject stress-testing behaviors or debug assertions conditionally.

Today, achieving that requires creating multiple build-tagged files with duplicated code, which scales poorly and adds maintenance overhead.

Proposal

Introduce a minimal, safe, and explicit form of conditional compilation to Go. Not necessarily with #define or #ifdef syntax, but something equivalent in functionality.

Example (hypothetical):

#if DEBUG
    fmt.Println("debug info:", node)
#endif


**Comment From: randall77**

What's wrong with

const debug = false

if debug { fmt.Println("debug info:", node) } ```

In particular, the constant declarations can be in small //go:build-guarded files, and then the constants can be used in standard files as compile-time constants.

Comment From: seankhliao

see above.

Comment From: Yoseph-code

When building performance-critical systems like databases in Go, developers often need to toggle features such as memory caches, WAL persistence strategies, journaling levels, or branch-predicted operations — depending on the target architecture, environment, or performance needs.

Today, achieving this kind of conditional behavior in Go requires splitting logic across multiple files using //go:build constraints. While functional, this approach leads to fragmented code, duplication, and higher maintenance costs — especially in large codebases.

A minimal and safe form of conditional compilation, similar to C's #ifdef, would allow developers to toggle features directly within the same source file. This would increase productivity, reduce bugs, and unlock more aggressive performance strategies — all without sacrificing Go’s readability and simplicity.

To illustrate, here’s a common pattern from C used in systems programming:

define ENABLE_CACHE

ifdef ENABLE_CACHE

if (pageCache[id]) return pageCache[id];

endif

Page* page = readPageFromDisk(id);

ifdef ENABLE_CACHE

pageCache[id] = page;

endif

This pattern avoids runtime branching, strips the logic entirely from the binary if not needed, and keeps the code clean.

My proposal is to support something similar in Go. For example:

define ENABLE_CACHE

type Page struct { ID int Data []byte }

var pageCache map[int]*Page

func init() { #ifdef ENABLE_CACHE pageCache = make(map[int]*Page) #endif }

func LoadPage(id int) *Page { #ifdef ENABLE_CACHE if page, ok := pageCache[id]; ok { return page } #endif

page := readFromDisk(id)

#ifdef ENABLE_CACHE
pageCache[id] = page
#endif

return page

}

This kind of structure would allow us to keep the logic unified, without separating it into multiple build-tagged files for every feature flag or performance toggle.

I believe this could significantly help developers building high-performance, low-level systems in Go — particularly databases, file engines, and embedded systems — while respecting the language’s philosophy of simplicity.

Thank you for your time and consideration!