- Suggestion: Preprocessor Directives: #elif missing (#1370)
- Approved in principle
- Implementation: PR #19045
- Discussion
Add #elif to F# conditional compilation so multiple mutually exclusive branches can be written linearly (#if ... #elif ... #elif ... #else ... #endif) instead of nesting or repeating #if blocks. Aligns F# with C# and other languages; improves readability.
Without #elif, developers either:
- Nest
#ifinside#else(deep indentation, harder to scan), or - Write separate
#ifblocks plus a final negated catch-all (#if !A && !B && !C), which is verbose and error-prone. - C# parity
#elif removes redundancy, reduces logical mistakes, and eases cross-language sharing.
Grammar change:
#if <cond>
group
#elif <cond>
group
... (0+ more #elif)
#else
group
#endifFirst matching condition’s group is included; at most one group is compiled. #elif must follow an #if and precede an optional #else. No change to symbol definition semantics.
#if WIN64
let path = "/library/x64/runtime.dll"
#elif WIN86
let path = "/library/x86/runtime.dll"
#elif MAC
let path = "/library/iOS/runtime-osx.dll"
#else
let path = "/library/unix/runtime.dll"
#endifmodule test =
// Should evaluate to x = 3
let x =
#if false
1
#elif false
2
#elif (true || false)
3
#elif true
4
#else
5
#endifUpdate conditional compilation section to:
- Add
{ #elif pp-expression group }to grammar. - Document ordering and “first true wins” semantics.
- State errors:
#elifafter#else,#elifwithout#if, missing condition.
Small parser/editor updates (fantomas, etc); possibility of long chains (already possible).
Keep nesting; use multiple guarded blocks; introduce more complex compile-time constructs (unnecessary).
VB.NET, C/C++, C#, Swift, Objective-C all support #elif (or equivalent). Aligns F# with ecosystem norms.
Non-breaking. Older compilers will error on #elif. No IL or FSharp.Core changes.
Errors for:
#elifwithout preceding#if#elifafter#else- Missing condition
- Unbalanced directives
Add keyword highlighting (or darken un-used branch), folding across entire block, completion for #elif. No runtime tooling differences.
Tools like Fantomas must update their logic that evaluates the #if conditions to handle #elif.
Negligible; linear evaluation of conditions. No impact on generated code beyond selected branch.
Typical branch count ≤ 8; acceptable upper bound ≈ 50; linear processing.
Before:
#if A
let mode = 1
#else
#if B
let mode = 2
#else
let mode = 3
#endif
#endifAfter:
#if A
let mode = 1
#elif B
let mode = 2
#else
let mode = 3
#endif