www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Default attribute blocks/modules

I already outlined it 
[here](https://forum.dlang.org/post/efluuipmcdcsknlwqyci forum.dlang.org). In
present-day D, for any module, the default function attributes are ` system`,
`throw`, [` gc`](https://forum.dlang.org/thread/ojjsplombwzzjhjymr
w forum.dlang.org), and impure. The idea is to allow changing the default for a
module or in a block of declarations.

**Note:** Changing the default only affects non-inferred types 
and declarations. Attribute inference for templates or `auto` and 
nested functions are unaffected.



For changing the module default, use this:
```d
default  safe
module m;
```

For changing the block default, use this:
```d
default  safe:
// or
default  safe { … }
```



There is a subtle difference between module defaults and block 
defaults:
Block defaults only affect declarations. Module defaults apply to 
anything lexically in the module which can carry the attribute, 
in particular, function pointer and delegate types.

That means that in a `default  safe` module, every function 
declaration and every function pointer or delegate type lexically 
in that module will be ` safe` unless marked ` system`. Blocks 
can override the module default for declarations.

```d
default  safe
module m;

// Note: module defaults apply to functions and function 
pointer/delegate types
// spelled out in the module: `callback` is implicitly ` safe`
int f(int function() callback) => callback();
static assert(is(typeof(&f) == int function(int function()  safe) 
 safe));


// Note: `g` is not inferred; default ( safe) applies
void g()
{
     int* p;
     int x;
     p = &x; // Error: address of variable `x` assigned to `p` 
with longer lifetime
}

// Note: `h` is inferred  system; defaults are irrelevant
auto h()
{
     int* p;
     int x;
     p = &x; // Okay, makes `h` a ` system` function
}
static assert(!is(typeof(&h) : void function()  safe));
```

Default blocks are similar to normal blocks, except they don’t 
directly affect inference:

```d
module m;

default  safe:

// Note: block defaults only apply to declarations (e.g. 
functions),
// but not function pointer/delegate types that are parameters or 
return types.
// For `callback`, the module default applies, which is unset, 
i.e. ` system`.
int f1(int function() callback); // => callback(); // Error
static assert(is(typeof(&f1) == int function(int function() 
 system)  safe));

// An alias is a declaration, so the block default applies,
// and `FP` is `int function()  safe`.
alias FP = int function();
int f2(FP callback) => callback();
static assert(is(typeof(&f2) == int function(int function() 
 safe)  safe));


// Note: `g` is not inferred; default ( safe) applies
// (same as above)
void g()
{
     int* p;
     int x;
     p = &x; // Error: address of variable `x` assigned to `p` 
with longer lifetime
}

// Note: `h` is inferred  system; defaults are irrelevant
// (same as above)
auto h()
{
     int* p;
     int x;
     p = &x; // Okay, makes `h` a ` system` function
}
static assert(!is(typeof(&h) : void function()  safe));
```

The behavior of block defaults is consistent with attribute 
blocks, which likewise affect only declarations, but not function 
parameters or return types of function pointer or delegate types.

```d
// Note: Not a default, this is current-day D semantics.

 safe:

int f1(int function() callback);
static assert(is(typeof(&f1) == int function(int function() 
 system)  safe));

alias FP = int function();
int f2(FP callback) => callback();
static assert(is(typeof(&f2) == int function(int function() 
 safe)  safe));
```



```diff
     ModuleDeclaration:
-       ModuleAttributes? module ModuleFullyQualifiedName ;
+       ModuleAttributes? ModuleDefaultAttributes? module 
ModuleFullyQualifiedName ;
+
+   ModuleDefaultAttributes:
+       default DefaultAttributeList

     ModuleAttributes:
         ModuleAttribute
         ModuleAttribute ModuleAttributes

     ModuleAttribute:
         DeprecatedAttribute
         UserDefinedAttribute
```

```diff
     DeclDef:
         AttributeSpecifier
+       DefaultAttributeSpecifier
         …

+   DefaultAttributeSpecifier:
+       default DefaultAttributeList :
+       default DefaultAttributeList { DeclDefs? }
+
+   DefaultAttributeList:
+       DefaultAttribute DefaultAttributeList?
+
+   DefaultAttribute:
+       pure
+       nothrow
+         safe
+         nogc

     Attribute:
         …
         const
+       default ( DefaultAttributeList )
         final
         …
```
This grammar allows `pure default  safe  nothrow static` 
(followed by `{…}` or `:`) and by maximum munch, would mean that 
`default` applies to ` safe` and ` nothrow`, but not `static`. 
The language should reject that and require
`pure default( safe nothrow) static`, or else
`pure{ default  safe nothrow: static: … }` or
`pure: default  safe nothrow: static:`, respectively.
That is, `default` without parentheses is only allowed with 
`default` in front and no trailing that can’t be a default.

The downside of `default( safe)` is that it somewhat suggests 
it’s an attribute of its own, but it would only be allowed for 
blocks and module declarations, but not on declarations directly, 
where it makes little sense:
* On non-inferred declarations, `default( safe)` is ` safe`.
* On inferred declarations, `default( safe)` means nothing.
Jul 04