# Conditional Compilation Conditional compilation lets you include source code when running from Objo Studio while leaving it completely out of built and published apps. ```objo @If DebugBuild Then Print("Extra development diagnostics") @Else Print("Normal application output") @EndIf ``` This is different from an ordinary `If` statement. An ordinary `If` is compiled into the app and makes a decision at runtime. Conditional compilation selects source before Objo parses, checks, analyses, or compiles the program. Inactive source is not emitted as bytecode. ## Syntax ```objo @If condition Then # Source selected when condition is True @ElseIf anotherCondition Then # Optional; any number of ElseIf branches may be used @Else # Optional; selected if no earlier branch was selected @EndIf ``` You may nest conditional blocks: ```objo @If DebugBuild Then @If True Then Print("Nested debug source") @EndIf @EndIf ``` Directive names and conditions are case-insensitive, just like the rest of Objo. The formatter uses `@If`, `@ElseIf`, `@Else`, `@EndIf`, and `DebugBuild` as the canonical spelling. The `@` must be the first non-whitespace content on its physical line. You may indent a directive and add a trailing `#` comment: ```objo @If DebugBuild Then # This comment is allowed WriteDiagnostics() @EndIf ``` Each conditional block must begin and end in the same source file. A block cannot start in one file and finish in another. ## The DebugBuild Symbol `DebugBuild` is the compiler-defined conditional-compilation symbol. For application source, it is `True` for: - live analysis in Objo Studio - Run, Debug, and Profile from Objo Studio - remote Run, Debug, and Profile sessions It is `False` for: - Build and Publish from Objo Studio - `objo build` and `objo publish` - `objo check` Code compiled directly through the engine also uses release behaviour unless the embedding application explicitly requests a debug compilation. `DebugBuild` exists only while compiling directives. It is not a normal variable or property, so you cannot use it in ordinary Objo code: ```objo @If DebugBuild Then # Valid Print("Development") @EndIf Print(DebugBuild) # Compile error ``` ## Permitted Conditions A condition is evaluated while the project is being compiled. Its final value must be `Boolean`. As well as `DebugBuild`, conditions can use ordinary Objo constants whose values are known at compile time: ```objo Module BuildFlags Const FEATURE_ENABLED As Boolean = True Const API_LEVEL As Integer = 3 Const CHANNEL As String = "beta" End Module @If BuildFlags.FEATURE_ENABLED Then Print("Feature source is included") @EndIf @If BuildFlags.API_LEVEL >= 3 And BuildFlags.CHANNEL = "BETA" Then Print("Version and channel checks are also allowed") @EndIf ``` Constants of type `Boolean`, `Integer`, `Double`, and `String` can participate in compile-time expressions. Their initializers may use literals, parentheses, other compile-time constants, and these operators: - unary `-` and `Not` - arithmetic `^`, `*`, `/`, `\`, `Mod`, `+`, and `-` - comparisons `<`, `>`, `<=`, `>=`, `=`, and `<>` - Boolean `And`, `Xor`, and `Or` The compiler uses the same case-insensitive names and normal constant visibility rules as Objo code: ```objo Class Feature Private Const INTERNAL_BUILD As Boolean = True Sub Run() @If INTERNAL_BUILD Then # Visible inside Feature Print("Internal") @EndIf End Sub End Class ``` Class and module constants may be referenced before their declaration and from another source file. Qualify them with their class or module name where needed. A local constant is available only after its declaration and only inside its lexical block: ```objo Sub Run() Const FLAG As Boolean = True @If FLAG Then Print("Included") @EndIf End Sub ``` A constant declared in a selected conditional branch can be used by a later directive. A constant in an inactive branch does not exist: ```objo @If DebugBuild Then Const INCLUDE_DIAGNOSTICS As Boolean = True @EndIf @If INCLUDE_DIAGNOSTICS Then Print("Included only in a debug compilation") @EndIf ``` In this example, the second directive is valid in a debug compilation. In a release compilation, `INCLUDE_DIAGNOSTICS` is unavailable, so the compiler reports an unknown conditional-compilation symbol. Defining a constant in source whose inclusion depends circularly on that same constant is also an error. Only expressions that can be evaluated without running application code are allowed. Runtime variables and properties, method or function calls, object construction, collections, and interpolated strings are rejected with a compile-time diagnostic: ```objo @If System.IsDebuggerAttached Then # Invalid: runtime property @EndIf @If GetMode() = "debug" Then # Invalid: function call @EndIf ``` ### Operator Precedence Operators are evaluated in this order, from highest to lowest precedence: 1. unary `-` and `Not` 2. `^` (right-associative) 3. `*`, `/`, `\`, and `Mod` 4. `+` and `-` 5. `<`, `>`, `<=`, and `>=` 6. `=` and `<>` 7. `And` 8. `Xor` 9. `Or` All other binary operators are evaluated from left to right. Use parentheses whenever they make the intended grouping clearer. ## What Is Excluded? Only the first branch whose condition is `True` is selected. The `@Else` branch is selected only if no earlier branch was selected. The compiler removes all directive lines and inactive source while preserving line and column positions for diagnostics. Inactive source: - is not parsed or type checked - does not contribute classes or other type metadata - does not add pragmas or analyser warnings - does not emit functions, string constants, type references, or other bytecode content This means a debug helper and its diagnostic strings can be absent from a published app: ```objo @If DebugBuild Then Class DebugReporter Shared Sub DumpState() Print("Internal diagnostic details") End Sub End Class @EndIf ``` Any selected branch must form valid Objo source after the other branches have been removed. The directive structure and every directive condition must also be valid. Text such as `@If` inside a valid plain or interpolated multiline string remains part of the string and is not treated as a directive. ## DebugBuild vs System.IsDebuggerAttached Use `DebugBuild` when source must be absent from built and published apps: ```objo @If DebugBuild Then DebugReporter.DumpState() @EndIf ``` Use [`System.IsDebuggerAttached`](stdlib/system.md#systemisdebuggerattached) when the code should remain in the app but run only while a debugger is currently attached: ```objo If System.IsDebuggerAttached Then Print("A debugger is attached right now") End If ``` The two checks answer different questions. `DebugBuild` is decided once, while compiling. `System.IsDebuggerAttached` is evaluated at runtime and can change as the app's debugging state changes. ## Editor Styling Objo Studio highlights conditional-compilation directives separately from ordinary language keywords. In **Settings > Appearance**, the **Compiler Directives** syntax component has its own colour, bold, italic, and underline settings for both light and dark themes. The defaults use a dark brown in the light theme and a lighter warm brown in the dark theme.