digitalmars.dip.ideas - Default attribute blocks/modules
- Quirin Schroll (161/161) Jul 04 I already outlined it
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