Why use a DFA instead of DIP1000?

Richard (Rikki) Andrew Cattermole richard at cattermole.co.nz
Sun Sep 14 04:27:18 UTC 2025


On 14/09/2025 3:20 PM, Walter Bright wrote:
> Requiring the language to remove all dead code before checking for 
> errors means the entire program must be subjected to DFA. The result is 
> compilation will slow down dramatically. It means separate compilation 
> is no longer possible.
> 
> As a pragmatic choice, D is designed to not require DFA. It is a 
> deliberate architectural choice, not a bug.

It seems we have a miscommunication on this.

The requirements of D say its a feature, the PL literature says its a bug.

It can be both!

And yes, I agree the choice D went with is a good one for the C family. 
Very pragmatic.

Where DFA and CFG analysis is implemented (such as limited VRP and 
blockexit.d) are very impressive, I enjoyed seeing it.

However, these algorithms when in use, are not applied consistently.

https://github.com/dlang/dmd/issues/21859

It passes nothrow, but not -betterC:

```d
void func() nothrow {
     if (0) {
      	 throw new Exception("");  // Error: cannot use `throw` 
statements with -betterC
     }
}
```

> That said, an optional DFA can be quite useful in detecting otherwise 
> hidden programming errors. But I'm not convinced it's a good idea to 
> require it in order to successfully compile code, as your opening 
> example suggests.

DFA is a rather large body is literature, we have to split it up before 
going eww no on any of it.

There is:

- Single forward pass: fast DFA, DIP1000, limited VRP/CFG analysis in 
frontend.
- Work list algorithm: @live, slow DFA if I ever build it.

Also:

- In the type system: i.e. storage classes, dictates what templates 
instantiate.
- Lint level: does not effect mangling, only limits what code is 
considered valid, no mutation of type system.

Considerations on the type system we can basically go no on, simply 
because dmd isn't architectured to handle it. Which is a good choice as 
I said elsewhere for the C family, but not all languages are like that 
and they do get benefits from doing so.

Work list algorithm is great but it has to be opt-in, not everyone is 
going to benefit from the slow down.

That kinda leaves us with single forward pass and lint level for 
anything on by default. Which unfortunately DIP1000 is not (due to it 
messing with storage classes, not that I'm arguing that was a wrong 
choice when it was implemented).

You can do an absolute load of stuff at lint level with a single forward 
pass engine. Which I'm finding out as I learn that my fast DFA engine is 
probably close to bleeding edge oops. Worthy of some serious pride as I
am reevaluating other language options lol.

This isn't a situation where we only have the worst set of options 
available to us. Each has their strengths and weaknesses. Its possible 
to have multiple opinions based upon how you are categorizing things for 
this particular subject.



More information about the Digitalmars-d mailing list