Fifth Draft: Primary Type Syntax

Quirin Schroll qs.il.paperinik at gmail.com
Mon Dec 23 02:47:32 UTC 2024


The obligatory 
[permalink](https://github.com/Bolpat/DIPs/blob/e9ab3c3c92e23931c8fcb47f8e55f60864d9196f/DIPs/DIP-2NNN-QFS.md#maximal-munch-exceptions) and [latest draft](https://github.com/Bolpat/DIPs/blob/PrimaryTypeSyntax/DIPs/DIP-2NNN-QFS.md).

Sorry for the inactivity, I had very little spare time in the 
last months and D is not my top priority.

---

The new section is [§ Scope 
guards](https://github.com/Bolpat/DIPs/blob/PrimaryTypeSyntax/DIPs/DIP-2NNN-QFS.md#scope-guards). In the monthly meeting I participated in, Walter made me aware that scope guards were designed to be extensible in the future, i.e. between the parentheses, arbitrary tokens should be allowed and nothing else should infringe on this design.

The newly proposed changes incorporate this design decision, 
requiring scope guards with hypothetical multi-token arguments 
(think `scope(failure, FormatException e)` for example) to have 
braced statements. This is so that
```d
scope (ref int delegate()) dg = &obj.f;
```
works as expected and isn’t parsed as a scope guard. I’m somewhat 
adamant to the idea that this just works.

I updated the implementation so it incorporates the compromise 
and is up-to-date with DMD’s master.

---

I was asked to include a section about other ambiguities, in 
particular, `align` and `extern`. Notably, those are fine using 
Maximum Munch. No “Bad Things” happen, only Annoying Things.

For example, in an `align(n)` context, one can add 
default-aligned declarations using no-argument `align`, but with 
primary types, one possibly wants to write `align (ref int 
function()) fp;`, but `align` greedily takes the type as its 
argument. The easiest solution is to add `align(default)` as an 
elaborate synonym for no-argument `align`. This addition has 
merit irrespective of the DIP and [the PR for 
it](https://github.com/dlang/dmd/pull/20589) is already up.

Likewise, `extern` takes anything in parentheses after it as its 
argument. Here, a similar fix is possible: Any `extern` 
declaration has a linkage, and repeating the default or currently 
applying linkage fixes the problem:
```d
extern (ref int function()) fp; // error
// `ref int function()` considered a linkage

extern extern(D) (ref int function()) fp; // good
```

Also, those issues are only relevant in statement scope, where 
both `align` and `extern` are rare. In declaration scope, one can 
just use braces:
```d
align { (ref int function()) fp1; } // good
extern { (ref int function()) fp2; } // good
```

I’m unsure if this little discussion really needs to be part of 
the DIP.

---

About function types (not to be confused with function pointer 
types), I haven’t thought much about them, but several people 
have asked me about them. Practically speaking, there’s much less 
need to express them. If you need to pass a function type to a 
template as an argument, assuming `FP` expresses the 
corresponding function pointer type (which the DIP enables for 
all function pointer types), one can use `typeof(*FP.init)`:

```d
void main()
{
     // works currently:
     static assert(typeof(*void function(int) @safe.init).stringof 
== "@safe void(int)");

     // the DIP enables also:
     static assert(typeof(*ref int function() @safe.init).stringof 
== "ref @safe int()");
}
```

I have no idea why function types even exist. They’re an annoying 
corner case. Even the spec explicitly says that they’re outside 
the official grammar.


More information about the dip.development mailing list