debug a reserved keyword (even for enums?)

Quirin Schroll qs.il.paperinik at gmail.com
Mon Apr 13 10:58:50 UTC 2026


On Saturday, 11 April 2026 at 09:33:34 UTC, libxmoc wrote:
> On Saturday, 11 April 2026 at 01:38:30 UTC, Jonathan M Davis 
> wrote:
>> On Friday, April 10, 2026 4:37:54 PM Mountain Daylight Time 
>> Katastic via Digitalmars-d wrote:
>>> Hello all, it's been awhile. I have a question. Does it make 
>>> 'sense' that debug is a reserved keyword even when its inside 
>>> an enum?
>>>
>>> ```D
>>> enum loggingLevel {
>>>   none = 0,
>>>   debug, // Error: found `debug` when expecting `identifier`
>>>   info,
>>>   warning,
>>>   error
>>> }
>>> ```
>>>
>>> Is there anywhere where that would actually clash?
>>> ```D
>>> void myFunction(loggingLevel l);
>>> myFunction(loggingLevel.debug);
>>>
>>> with(loggingLevel){
>>> myFunction(debug);
>>> }
>>> ```
>>>
>>> Is `debug` used anywhere outside of `version()` statements? 
>>> Would
>>> it explode templates or something?
>>
>> As a general rule, keywords in D are keywords no matter where 
>> they are. They are not contextual. As such, you cannot use 
>> them anywhere other than where the language uses that word. 
>> There are of course downsides to that approach, but it's 
>> simpler to process than contextual keywords, and it tends to 
>> work better with stuff like error messages (since the keyword 
>> then is essentially an anchor point in the grammar instead of 
>> the compiler needing to figure which context you're trying to 
>> use the keyword in when the context isn't well-formed due to 
>> typos or whatnot).
>>
>> Obviously, that's annoying when you have a situation where a 
>> keyword is the best identfier, but you can't use it, because 
>> it's a keyword. However, the solution that's generally used in 
>> D (and given in the official style guide) is that when you 
>> need to use a keyword as an identifier, you apppend an 
>> underscore to it:
>>
>> https://dlang.org/dstyle.html#naming_keywords
>>
>> So, you'd have `LoggingLevel.debug_` rather than 
>> `LoggingLevel.debug`.
>>
>> A prime example of where this comes up in the standard library 
>> is with `std.traits.FunctionAttribute`:
>>
>> https://dlang.org/phobos/std_traits.html#.FunctionAttribute
>>
>> The enum literally needs to list a bunch of keywords as its 
>> values, and that's not legal, so trailing underscores have 
>> been added to those keywords.
>
> This is exactly the kind of friction that D editions should 
> address.
>
> I've been bitten by this twice recently: once designing a UI 
> system where `Align align;` was illegal, and again a few months 
> ago with SemVer version. Both times, the trailing underscore 
> workaround felt like unnecessary concessions for perfectly 
> unambiguous code.
>
> The fundamental issue isn't whether non-contextual keywords are 
> easier to parse, it's that D already has a mechanism to 
> disambiguate: the dot operator. `loggingLevel.debug`, 
> `Align.align`, and `SemVer.version` are all unambiguous to both 
> the parser and the reader. The token following a dot is already 
> in a different lexical context.
>
> There's precedent for this in other languages. Rust allows 
> `self.as` and `match.as` because keywords after `.` are 
> unambiguous. Even C#—hardly a radical language—has contextual 
> keywords in specific positions.

That is quite an understatement. I’d go as far and say *most* 
keywords in C# are contextual these days. Linq has many keywords 
and they’re all contextual.

> The "trailing underscore" convention is a concession that keeps 
> accumulating.

On the other hand, C# has a way to mark keywords as identifiers 
when they’d otherwise lead to errors: `@keyword`. Maybe D can use 
a `#` suffix or something. While `#` is reserved for things like 
`#line`, those need to be the first non-whitespace character in 
their line, which cannot clash with a suffix. If you need such a 
variable, use `debug#`. There are countless other options, such 
as `debug$`.

> debug_, version_, align_, function_, immutable_... at what 
> point do we acknowledge that the cure (universal keyword 
> reservation) is worse than the disease (contextual parsing 
> complexity)?
>
> Editions exist precisely to make breaking improvements like 
> this possible without fragmenting the ecosystem.
>
> Let's do it.

The way to do this, IMO, is going over the list of keywords and 
identifying those that are both
* common English words, especially nouns, and
* rarely used.

For each:

1. Figure out if a common keyword would do. Rare cases may hit 
this, e.g. `body` → `do` is such a success story.

2. The remaining ones would be replaced by `__keyword`.

Here’s my take:

Obvious candidates
```
abstract    →  @abstract
align       →  __align and kill `align` without parentheses
debug       →  __debug
deprecated  →  __deprecated
final       →  @final
invariant   →  __invariant
pure        →  @pure
version     →  __version
```

Those are English words that are used as keywords that are used 
in very specific contexts.
The most obvious candidates are `align`, `debug`, `export`, and 
`version`. `debug` especially warrants `__` because it breaks 
attributes. The average programmer very rarely uses `align` or 
`deprecated` and your code won’t become that more ugly when those 
need underscores. And while `version` is more common, it’s 
possibly also more common as a desired identifier. Similar is 
maybe `invariant`. You don’t use it that often that `__` would be 
too annoying, but in certain domains, having `invariant` as an 
identifier might be nice.

`abstract` and `final` simply don’t need to be keywords. Moving 
them to compiler-recognized UDAs allows them as identifiers and 
isn’t a big change.

I’m torn on:
```
export      →  __export
macro       →  remove it
package     →  __package
```

I’m not sure if `macro` is a highly desired identifier. `package` 
and `export` might be, but they’re visibility attributes and if 
we’re not targeting `private` and `public` maybe we should let 
them be, especially `package` because it takes an optional a 
parameter.


More information about the Digitalmars-d mailing list