├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── DIPs ├── 1NNN-RAC.md ├── DIP1048.md ├── DIP1049.md ├── DIP1051.md ├── README.md ├── accepted │ ├── DIP1003.md │ ├── DIP1007.md │ ├── DIP1009.md │ ├── DIP1010.md │ ├── DIP1013.md │ ├── DIP1014.md │ ├── DIP1018.md │ ├── DIP1021.md │ ├── DIP1024.md │ ├── DIP1029.md │ ├── DIP1030.md │ ├── DIP1034.md │ ├── DIP1035.md │ ├── DIP1038.md │ ├── DIP1043.md │ └── DIP1046.md ├── archive │ ├── DIP20.md │ ├── DIP22.md │ ├── DIP25.md │ ├── DIP37.md │ ├── DIP42.md │ ├── DIP43.md │ ├── DIP45.md │ ├── DIP56.md │ ├── DIP60.md │ ├── DIP61.md │ ├── DIP75.md │ └── README.md ├── other │ ├── DIP1000.md │ ├── DIP1004.md │ ├── DIP1005-countlines.zsh │ ├── DIP1005-time.zsh │ ├── DIP1005.md │ ├── DIP1006.md │ ├── DIP1008.md │ ├── DIP1011.md │ ├── DIP1012.md │ ├── DIP1019.md │ ├── DIP1020.md │ ├── DIP1022.md │ ├── DIP1023.md │ ├── DIP1025.md │ ├── DIP1026.md │ ├── DIP1031.md │ ├── DIP1032.md │ ├── DIP1033.md │ ├── DIP1036.md │ ├── DIP1037.md │ ├── DIP1039.md │ ├── DIP1040.md │ ├── DIP1041.md │ ├── DIP1042.md │ └── DIP1045.md └── rejected │ ├── DIP1001.md │ ├── DIP1002.md │ ├── DIP1015.md │ ├── DIP1016.md │ ├── DIP1017.md │ ├── DIP1027.md │ ├── DIP1028.md │ ├── DIP1044.md │ └── DIP1047.md ├── GUIDELINES.md ├── LICENSE.txt ├── PROCEDURE.md ├── README.md ├── Template.md ├── docs ├── guidelines-authors.md ├── guidelines-forums.md └── process-authoring.md └── tools ├── dwikiquery ├── dub.sdl └── source │ └── app.d └── genoverview ├── dub.sdl └── source ├── app.d └── metadata.d /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/en/articles/displaying-a-sponsor-button-in-your-repository 2 | 3 | open_collective: dlang 4 | custom: https://dlang.org/foundation/donate.html 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | dub.selections.json 3 | tools/dwikiquery/dwikiquery 4 | tools/genoverview/genoverview 5 | __test__library__ 6 | -------------------------------------------------------------------------------- /DIPs/DIP1048.md: -------------------------------------------------------------------------------- 1 | # Callbacks For Matching Types 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1048 | 6 | | Author: | Richard (Rikki) Andrew Cattermole | 7 | | Implementation: | | 8 | | Status: | Formal Assessment | 9 | 10 | ## Abstract 11 | 12 | Callbacks for matching types is a quality-of-life feature that enables safer access and mutation of tagged union-like data representations. It adds syntax sugar on top of a switch statement to give convenient access to the union members without sacrificing safety. 13 | 14 | ## Contents 15 | * [Rationale](#rationale) 16 | * [Prior Work](#prior-work) 17 | * [Description](#description) 18 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 19 | * [Reference](#reference) 20 | * [Copyright & License](#copyright--license) 21 | * [Reviews](#reviews) 22 | 23 | ## Rationale 24 | 25 | As a feature, pattern matching goes hand in hand with sum types. Although D has sum types in its standard library, the desire to have them in the language requires a way to express matching upon types. This proposal offers a solution that works with existing library types. 26 | 27 | ## Prior Work 28 | 29 | This proposal aims to allow callbacks for types using pattern matching. It does not introduce full-featured pattern matching. In other languages, such as those in the ML family, pattern synonyms, pattern guards, values and literals, and nested type matching are all possible. 30 | 31 | By limiting this proposal to what is currently in use in the ecosystem via less desirable means, this proposal is simplified to only what has proven to be needed today. 32 | 33 | In the D ecosystem, pattern matching can be seen in some library tagged union types such as `std.sumtype`'s `match` function. This offers multiple dispatch and uses lambdas as callbacks. 34 | 35 | ## Description 36 | 37 | A matching type is any type that includes the members `__tag`, `__tagTypes`, and a templated function `__tagValue`, which takes in the type. 38 | 39 | A `__tag` member must evaluate to an integer that may not be sequential, although it may take the form of an `enum` or pointer. 40 | 41 | A `__tag`'s range of values is determined by its evaluated type. If it is an `enum`, its members provide the range of possible results. Otherwise, it is provided by a fourth member, `__tagValues`. 42 | 43 | When the compiler sees a match, it will map the match type to a set of tags that match it. If no type is provided, it will match all possible values and will act as the default. If a type is provided, it should be matched against overload resolution rules and an attempt made to find an exact match, otherwise it should use (the single) implicit conversion. 44 | 45 | Each match contains multiple patterns. Only one pattern may be inferred per matching type using means similar to lambda parameter type inference. However, instead of inferring, each possible type that has not had a pattern will be instantiated as a fallback. 46 | 47 | If a tag type is `void`, the parameter will be considered unreachable and cannot be loaded or stored into, but may be named. 48 | 49 | It is an expression rather than a statement to enable future work of returning values. 50 | 51 | ```diff 52 | PostfixExpression: 53 | + PostfixExpression '.' "match" DeclarationBlock 54 | 55 | DeclDef: 56 | + MatchPattern ';' 57 | + MatchPatterns MatchPattern ';' 58 | 59 | + MatchPattern: 60 | + Identifier FunctionLiteralBody 61 | + ParameterWithAttributes FunctionLiteralBody 62 | ``` 63 | 64 | Inside of a match `DeclarationBlock`, only the rules `MatchPattern`, `ConditionalDeclaration`, `DebugSpecification`, `VersionSpecification`, `MixinDeclaration`, `AttributeSpecifier`, `ImportDeclaration`, `StaticForeachDeclaration`, and `StaticAssert` are valid. Outside of a match, the rule `MatchPattern` is not valid. 65 | 66 | Visibility and safety are ignored for the `__tag` and `__tagValue` members. The members `__tagValues` and `__tagTypes` must be accessible. 67 | 68 | When decomposed, a pattern match is syntax sugar surrounding a switch statement, and the callbacks are expected to be inlined. Decomposing to a switch statement enables existing optimizations for switch statements to enable faster execution without the need for a new class of optimizations. 69 | 70 | ```d 71 | switch(tag) { 72 | case Context.__tagValues[2]: 73 | Callback(); 74 | break; 75 | default: 76 | FallbackCallback(); 77 | break; 78 | } 79 | ``` 80 | 81 | Not all types may be matched. Tuples, for example, will need to employ a multiple-level dispatch strategy. One way to do this is by using nested switch statements to evaluate each level of the possible patterns. If a fallback pattern is applied as part of the nested patterns, only one given the nesting level may be a fallback. 82 | 83 | ```d 84 | switch(tag[0]) { 85 | case Context1.__tagValues[2]: 86 | switch(tag[1]) { 87 | case Context2.__tagValues[9]: 88 | Callback(); 89 | break; 90 | default: 91 | FallbackCallback1(); 92 | break; 93 | } 94 | break; 95 | default: 96 | switch(tag[1]) { 97 | default: 98 | FallbackCallback2(); 99 | break; 100 | } 101 | break; 102 | } 103 | ``` 104 | 105 | With syntax: 106 | 107 | ```d 108 | tuple(first, second).match { 109 | (Type1 v1, Type2 v2) { 110 | }; 111 | 112 | (Type1 v1, v2) { 113 | }; 114 | 115 | (v1, v2) { 116 | }; 117 | } 118 | ``` 119 | 120 | ## Example: Tagged Unions 121 | 122 | Given a tag union type: 123 | 124 | ```d 125 | import std.conv : text; 126 | 127 | struct MyTaggedUnion(Types...) { 128 | alias __tagTypes = Types; 129 | 130 | private { 131 | size_t __tag; 132 | 133 | union { 134 | static foreach(i; 0 .. Types.length) { 135 | mixin("Types[i] " ~ i.text ~ ";"); 136 | } 137 | } 138 | 139 | ref Type __tagValue(Type)() { 140 | return *cast(Type*)&this; 141 | } 142 | } 143 | } 144 | ``` 145 | 146 | It can be used like this: 147 | 148 | ```d 149 | alias MTU = MyTaggedUnion!(int, float, string); 150 | 151 | MTU mtu1 = MTU(1.5); 152 | MTU mtu2 = MTU("Rikki"); 153 | 154 | mtu1.match { 155 | (float v) => writeln("a float! ", v); 156 | v => writeln("catch all! ", v); 157 | }; 158 | 159 | mtu2.match { 160 | (string name) => writeln("Who is awesome? ", name); 161 | _ => assert(0); 162 | }; 163 | ``` 164 | 165 | It is an error not to have a handler for all possible types. Either provide a catch-all pattern or handle all possible types. 166 | 167 | ```d 168 | mtu1.match { 169 | (float v) => writeln("a float! ", v); 170 | }; // Error: Pattern matching must handle all types `int`, `string`, were not handled. 171 | ``` 172 | 173 | ## Example: Tagged Union AST 174 | 175 | Abstract Syntax Trees can be represented by tagged unions with many benefits, and some compiler authors prefer them over classes coupled with the visitor pattern. 176 | 177 | These are a different variant of tagged unions as they have a fixed set of possible values. 178 | 179 | ```d 180 | import std.meta : AliasSeq; 181 | 182 | struct Expression { 183 | alias __tagTypes = AliasSeq!(void, BinaryExpression, UnaryExpression); 184 | alias __tagValues = Type; 185 | 186 | private { 187 | Type type; 188 | alias __tag = type; 189 | 190 | ref BinaryExpression __tagValue(Type:BinaryExpression)() => binary; 191 | ref UnaryExpression __tagValue(Type:UnaryExpression)() => unary; 192 | 193 | union { 194 | BinaryExpression binary; 195 | UnaryExpression unary; 196 | } 197 | 198 | enum Type { 199 | Error, 200 | Binary, 201 | Unary 202 | } 203 | } 204 | } 205 | 206 | struct BinaryExpression { 207 | } 208 | 209 | struct UnaryExpression { 210 | } 211 | ``` 212 | 213 | Its usage: 214 | 215 | ```d 216 | Expression expr = ...; 217 | expr.match { 218 | (ref BinaryExpression be) { 219 | }; 220 | 221 | (ref UnaryExpression ue) { 222 | }; 223 | 224 | _ => assert(0); 225 | }; 226 | ``` 227 | 228 | ## Breaking Changes and Deprecations 229 | 230 | Existing members of a type may be called `match`. Unfortunately, this results in the possible breakage. However, this doesn't have to be the case. 231 | 232 | Using a lookahead of one token, if `match` is followed by `{` then it is this feature, otherwise it should be treated as currently. 233 | 234 | ## Reference 235 | 236 | An overview of all the different pattern-matching capabilities that mainstream languages offer can be found on [Wikipedia].(https://en.wikipedia.org/wiki/Pattern_matching) 237 | 238 | Haskell's pattern synonyms: [link](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/pattern_synonyms.html). 239 | 240 | ## Copyright & License 241 | Copyright (c) 2024 by the D Language Foundation 242 | 243 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 244 | 245 | ## History 246 | This DIP underwent one round of community feedback in the DIP Ideas forum: 247 | https://forum.dlang.org/post/chzxzjiwsxmvnkthbdyy@forum.dlang.org 248 | 249 | This DIP underwent one round of community feedback in the DIP Development forum: 250 | https://forum.dlang.org/post/gyiwqxompgwmvztlkcuk@forum.dlang.org 251 | -------------------------------------------------------------------------------- /DIPs/README.md: -------------------------------------------------------------------------------- 1 | # DIP Status 2 | 3 | ## DIPs in review 4 | | ID| Title| 5 | |--------------------|-----------------------------------------------| 6 | |[1051](./DIP1051.md)| Add Bitfields to D| 7 | |[1049](./DIP1049.md)| Primary Type Syntax| 8 | |[1048](./DIP1048.md)| Callbacks For Matching Types| 9 | 10 | ## Accepted DIPs 11 | | ID| Title| DMD version | 12 | |-----------------------------|--------------------------------------|--------------| 13 | |[1003](./accepted/DIP1003.md)| Remove `body` as a Keyword| 2.075.0 | 14 | |[1007](./accepted/DIP1007.md)| "future symbol" Compiler Concept| 2.076.0 | 15 | |[1009](./accepted/DIP1009.md)| Add Expression-Based Contract Syntax| 2.081.0 | 16 | |[1010](./accepted/DIP1010.md)| Static foreach| 2.076.0 | 17 | |[1013](./accepted/DIP1013.md)| The Deprecation Process| — | 18 | |[1014](./accepted/DIP1014.md)| Hooking D's struct move semantics| — | 19 | |[1018](./accepted/DIP1018.md)| The Copy Constructor| 2.086.0 | 20 | |[1021](./accepted/DIP1021.md)| Argument Ownership and Function Calls| 2.092.0 | 21 | |[1024](./accepted/DIP1024.md)| Shared Atomics| 2.080.1 | 22 | |[1029](./accepted/DIP1029.md)| Add `throw` as Function Attribute| | 23 | |[1030](./accepted/DIP1030.md)| Named Arguments| 2.103.0 | 24 | |[1034](./accepted/DIP1034.md)| Add a Bottom Type (reboot)| 2.096.1 | 25 | |[1035](./accepted/DIP1035.md)| `@system` Variables| 2.102.0* | 26 | |[1038](./accepted/DIP1038.md)| @mustuse| | 27 | |[1043](./accepted/DIP1043.md)| Shortened Method Syntax| 2.100.0 | 28 | |[1046](./accepted/DIP1046.md)| `ref` For Variable Declarations| 2.111.0 | 29 | 30 | (* The feature is not enabled by default, but can be enabled by a preview switch.) 31 | 32 | ## Rejected DIPs 33 | | ID| Title| 34 | |-----------------------------|--------------------------------------| 35 | |[1001](./rejected/DIP1001.md)| DoExpression| 36 | |[1002](./rejected/DIP1002.md)| TryElseExpression| 37 | |[1015](./rejected/DIP1015.md)| Deprecation and removal of implicit conversion from integer and character literals to `bool` | 38 | |[1016](./rejected/DIP1016.md)| `ref T` accepts r-values| 39 | |[1017](./rejected/DIP1017.md)| Add Bottom Type| 40 | |[1027](./rejected/DIP1027.md)| String Interpolation| 41 | |[1028](./rejected/DIP1028.md)| Make @safe the Default| 42 | |[1044](./rejected/DIP1044.md)| Enum Type Inference| 43 | |[1047](./rejected/DIP1047.md)| Add `@gc` as a Function Attribute| 44 | 45 | ## Postponed DIPs 46 | | ID| Title| 47 | |-----------------------------|--------------------------------------| 48 | |[1008](./other/DIP1008.md) | Exceptions and @nogc| 49 | |[1022](./other/DIP1022.md) | foreach auto ref| 50 | |[1023](./other/DIP1023.md) |Resolution of Template Alias Formal Parameters in Template Functions| 51 | |[1033](./other/DIP1033.md) |Implicit Conversion of Expressions to Delegates| 52 | |[1041](./other/DIP1041.md) | Attributes for Higher-Order Functions| 53 | |[1045](./other/DIP1045.md) | Symbol Representation| 54 | 55 | ## Superseded DIPs 56 | | ID| Title| 57 | |-----------------------------|--------------------------------------| 58 | |[1000](./other/DIP1000.md) | Scoped Pointers| 59 | |[1006](./other/DIP1006.md) |Providing More Selective Control Over Contracts| 60 | |[1019](./other/DIP1019.md) | Named Arguments Lite| 61 | |[1020](./other/DIP1020.md) | Named Parameters| 62 | |[1040](./other/DIP1040.md) | Copying, Moving, and Forwarding| 63 | 64 | ## Abandoned DIPS 65 | | ID| Title| 66 | |-----------------------------|--------------------------------------| 67 | |[1004](./other/DIP1004.md) | Inherited Constructors| 68 | |[1011](./other/DIP1011.md) | extern(delegate)| 69 | |[1012](./other/DIP1012.md) | Attributes| 70 | |[1037](./other/DIP1037.md) | Add Unary Operator `...`| 71 | 72 | ## Withdrawn DIPS 73 | | ID| Title| 74 | |-----------------------------|--------------------------------------| 75 | |[1005](./other/DIP1005.md) | Dependency-Carrying Declarations| 76 | |[1025](./other/DIP1025.md) |Dynamic Arrays Only Shrink, Never Grow| 77 | |[1026](./other/DIP1026.md) |Deprecate Context-Sensitive String Literals| 78 | |[1031](./other/DIP1031.md) |Deprecate Brace-Style Struct Initializers| 79 | |[1032](./other/DIP1032.md) |Function Pointer and Delegate Parameters Inherit Attributes from Function| 80 | |[1036](./other/DIP1036.md) | String Interpolation Tuple Literals| 81 | |[1039](./other/DIP1039.md) | Static Arrays with Inferred Length| 82 | |[1042](./other/DIP1042.md) | ProtoObject| 83 | -------------------------------------------------------------------------------- /DIPs/accepted/DIP1003.md: -------------------------------------------------------------------------------- 1 | # Remove `body` as a Keyword 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1003 | 6 | | Author: | Jared Hanson | 7 | | Review Count: | 3 [Most Recent] | 8 | | Implementation: | [PR 6855] | 9 | | Status: | Accepted | 10 | 11 | [Most Recent]: https://github.com/dlang/DIPs/blob/492bfa45905158e7bef5a8b2baf3e9da92d82662/DIPs/DIP1003.md 12 | [PR 6855]: https://github.com/dlang/dmd/pull/6855 13 | 14 | 15 | ## Abstract 16 | 17 | The word `body` is used in many day-to-day contexts that makes working around 18 | the fact that it is a keyword in D tedious. Furthermore, this removal is very 19 | often requested by various well known and lesser known D programmers. This DIP 20 | proposes that the `body` keyword be removed and the word "body" be made 21 | available for use as the name of a symbol. Various methods are put forward for 22 | either replacing or entirely removing the role `body` currently serves in D's 23 | contract programming syntax. 24 | 25 | This proposal assumes basic knowledge of the terms "keyword" and "symbol" in 26 | relation to D. 27 | 28 | ### Links 29 | 30 | #### From the Spec 31 | - [List of Keywords in D](http://dlang.org/spec/lex.html#Keyword) 32 | - [Usage of the Body Keyword](http://dlang.org/spec/function.html#BodyStatement) 33 | - [Usage of the Function Keyword](https://dlang.org/spec/expression.html#FunctionLiteral) 34 | 35 | #### Forum Discussion 36 | - [From 2011, on removing the body keyword](http://forum.dlang.org/thread/imdro4$286k$1@digitalmars.com) 37 | - [From 2016, on the usage of body in user code](http://forum.dlang.org/thread/nyrosepldsxabewksehb@forum.dlang.org) 38 | - [From 2016, anecdote of the word body used in an external C library ported to D](http://forum.dlang.org/post/lxdsvhygsaesjmkmavqp@forum.dlang.org) 39 | 40 | #### Walter Bright on Contextual Keywords 41 | - [From 2016, Walter Bright on why he opposes contextual keywords in D](http://forum.dlang.org/post/npsp8a$mv4$1@digitalmars.com) 42 | 43 | ## Description 44 | 45 | The proposed changes to D are very simple, and are as follows: 46 | 47 | 1. Add `do` as an alternative keyword in place of `body`. 48 | 2. Temporarily make `body` a contextual keyword that is only a keyword when marking the body of a function. In all other conexts `body` may be used as a symbol name. 49 | 3. Schedule the `body` keyword for deprecation. 50 | 4. Once the deprecation period has ended, remove `body` as a keyword and only allow `do`. 51 | 52 | These changes have a very simple migration path for user code while also allowing `body` to immediately be used as a symbol name. Making `body` a contextual keyword and deprecating it, while also allowing `do`, affords users plenty of time for code to be updated to use `do`. It also ensures that user code will not immediately be broken. Finally, it avoids any potential long-term problems with keeping body as a contextual keyword. 53 | 54 | It is possible that using `do` to mark the function body may cause some confusion as to when `do` is referring to a function body or when it is referring to a loop body. However, the author does not believe that this is a concern; there are multiple keywords that risk causing similar confusion and yet, in practice, D users do not have trouble distinguishing which usage is intended within the surrounding context. One such example is the `if` template constraint syntax that looks identical to the regular `if`-statement syntax, save for the fact that it is only present after a template declaration. 55 | 56 | The grammar will change as follows while either `body` or `do` are allowed: 57 | ``` 58 | # This 59 | BodyStatement: 60 | body BlockStatement 61 | 62 | # Becomes this 63 | BodyStatement: 64 | body BlockStatement 65 | do BlockStatement 66 | ``` 67 | 68 | After `body` is deprecated and removed, the grammar will change as follows: 69 | ``` 70 | # This 71 | BodyStatement: 72 | body BlockStatement 73 | do BlockStatement 74 | 75 | # Becomes this 76 | BodyStatement: 77 | do BlockStatement 78 | ``` 79 | 80 | Using the `do` keyword was suggested by [David Gileadi](http://forum.dlang.org/post/off8ag$3t5$1@digitalmars.com) and [Random D user](http://forum.dlang.org/post/rhuxwyotfctdfzxguatv@forum.dlang.org). 81 | 82 | ### Rationale 83 | 84 | Many D programmers [complain](#forum-discussion) about `body` being a keyword in D. It is a commonly used word in many different fields and as such, a programmer working in these fields will regularly come into contact with the fact that it is a keyword (much to their annoyance). 85 | 86 | Furthermore, D's contract programming features are rarely used compared to how 87 | useful and desirable it is to be able to name a symbol "body". In the whole of 88 | Phobos, there are fewer than 300 uses of the `body` keyword, which is very small compared to the library's total line count. However, even if D's contract 89 | programming features _were_ heavily used, it would not compensate for the 90 | inconvenience caused by `body` being a keyword. 91 | 92 | One of the reasons for this is 93 | that there is only **one** context in which body is used, compared to the many 94 | different contexts in user code in which the word "body" may be used as a symbol name. Therefore, this keyword does not "pull its weight" syntactically. This makes it very disruptive and annoying 95 | when encountering such an issue in one's code. 96 | 97 | A partial list of the contexts in which the word `body` might be used as a symbol name: 98 | 99 | - In web programming where "body" is a required tag in any valid HTML document 100 | - It is a name commonly used for XML tags and/or attributes 101 | - Physics simulations as well in astronomical contexts ("planetary bodies", etc.) 102 | - Video games, such as referring to the player character's body 103 | - Working with HTTP requests and responses, which have a body 104 | - Working programmatically with emails, which have a body 105 | - Many external C and C++ libraries make use of "body" as a symbol name, making 106 | porting these to D and creating bindings for them more difficult 107 | - Writing compilers and parsers (functions, loops, etc. all have bodies) 108 | - Scripting interfaces and wrappers 109 | 110 | Examples of game physics library code ported to D that use body as a symbol: 111 | 112 | - [Example 1: dchip](https://github.com/d-gamedev-team/dchip/blob/55f43e5f0cf67c8bc190711b69eb16230fa6188e/src/dchip/cpBody.d#L184) 113 | - [Example 2: dbox](https://github.com/d-gamedev-team/dbox/blob/6f81fe065abec1e7def44fc777c5d8e9da936104/examples/demo/tests/bodytypes.d#L103) 114 | - [Example 3: chipmunkd](https://github.com/rcorre/chipmunkd/commit/d6bde5b649c70a53f4295f522e660fae3c1e740f) 115 | 116 | ### Breaking changes / deprecation process 117 | 118 | As previously discussed, user code will not immediately broken, save for if the user compiles their code with the `-de` copmiler flag. There will be some breakage once the deprecation period ends and `body` is removed entirely; the intent is to allow a deprecation period that is long enough that most users will be able to update their code to use `do`. This process could be accelerated by encouraging users to employ [dfix](https://github.com/dlang-community/dfix) to update their code. 119 | 120 | ### Examples 121 | 122 | #### How "body" might be used as a variable name in DOM-based code 123 | ```D 124 | document.body.addEventListener("click"), (Event ev) { //Error, body is a keyword 125 | ev.target.appendText("got click!"); 126 | ev.preventDefault(); 127 | }); 128 | ``` 129 | 130 | #### How "body" Is Currently Used in Physics Simulation Code 131 | ```D 132 | void cpBodyActivateStatic(cpBody* body_, cpShape* filter) 133 | { 134 | cpAssertHard(cpBodyIsStatic(body_), "cpBodyActivateStatic() called on a non-static body_."); 135 | 136 | mixin(CP_BODY_FOREACH_ARBITER!("body_", "arb", q{ 137 | if (!filter || filter == arb.a || filter == arb.b) 138 | { 139 | cpBodyActivate(arb.body_a == body_ ? arb.body_b : arb.body_a); 140 | } 141 | })); 142 | } 143 | ``` 144 | 145 | #### Examples of How Code Will Change with This Proposal 146 | 147 | ```D 148 | int div(int a, int b) 149 | in { assert(b != 0); } 150 | do 151 | { 152 | return a / b; 153 | } 154 | 155 | auto div = function(int a, int b) in { assert(b != 0); } do { return a / b; }; 156 | 157 | long fact(int n) 158 | in { assert(n >= 0); } 159 | do 160 | { 161 | long factHelper(int count, long acc) 162 | out(result) { assert(result >= acc); } 163 | do 164 | { 165 | if (count == 0) 166 | return acc; 167 | else 168 | return factHelper(count - 1, count * acc); 169 | } 170 | 171 | return factHelper(n, 1); 172 | } 173 | ``` 174 | 175 | ## Copyright & License 176 | 177 | Copyright (c) 2017 by the D Language Foundation 178 | 179 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 180 | 181 | ### Reviews 182 | 183 | This DIP was accepted by the language authors. They agree with the rationale put forth as justification 184 | for the change and that using an existing keyword, specifically `do`, in place of `body` is a 185 | reasonable solution. Although opposed to contextual keywords as a permanent part of the language, they 186 | felt it acceptable to allow `body` to become a contextual keyword *temporarily* as the DIP 187 | recommends. This will, upon implementation, allow the immediate usage of `body` for symbol names in 188 | user code. `body` will be deprecated at the same time it is made contextual and, once the deprecation 189 | cycle is complete, will be removed from the language. 190 | 191 | See the [previous version](rclink) of this DIP for other implementation options that were proposed, 192 | but rejected. 193 | 194 | [Formal review feedback](http://forum.dlang.org/thread/wcqebjzdjxldeywlxjcd@forum.dlang.org) 195 | 196 | [Preliminary NG discussion](http://forum.dlang.org/thread/qgxvrbxrvkxtimzvnetu@forum.dlang.org) 197 | -------------------------------------------------------------------------------- /DIPs/accepted/DIP1021.md: -------------------------------------------------------------------------------- 1 | # Argument Ownership and Function Calls 2 | 3 | 4 | | Field | Value | 5 | |-----------------|-----------------------------------------------------------------| 6 | | DIP: | 1021 | 7 | | Review Count: | 2 | 8 | | Author: | Walter Bright | 9 | | Implementation: | https://github.com/dlang/dmd/pull/10249 | 10 | | Status: | Accepted | 11 | 12 | 13 | ## Abstract 14 | 15 | The language features proposed in DIP 25 and DIP 1000 greatly improved the memory safety of passing 16 | references and pointers to functions by detecting if those 17 | pointers escape a function's scope. Subsequently, a container 18 | can safely pass an internal reference to a function if that 19 | function doesn't allow the reference to escape. 20 | 21 | But if a function is passed more than one reference to the same container, 22 | one reference can render invalid the data referred to by the other reference(s). 23 | This DIP aims to correct that problem. It's a natural progression after 24 | DIP 25 and DIP 1000 which is needed to safely implement Reference Counting. This 25 | proposal is one step toward a larger goal outlined in the blog post 26 | ['Ownership and Borrowing in D'](https://dlang.org/blog/2019/07/15/ownership-and-borrowing-in-d/). 27 | 28 | ## Contents 29 | * [Rationale](#rationale) 30 | * [Prior Work](#prior-work) 31 | * [Description](#description) 32 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 33 | * [Reference](#reference) 34 | * [Copyright & License](#copyright--license) 35 | * [Reviews](#reviews) 36 | 37 | ## Rationale 38 | 39 | Containers cannot be memory-safe if they cannot control memory-safe 40 | access to their payloads. Containers cannot be efficient if they cannot 41 | make available direct references to their payloads. Entreating the user 42 | not to do certain things is unreliable and does not scale. 43 | 44 | The simplest illustration of the problem: 45 | 46 | ```d 47 | struct S { 48 | byte* ptr; 49 | ref byte get() { return *ptr; } 50 | } 51 | 52 | void foo(ref S t, ref byte b) { 53 | free(t.ptr); // frees memory referred to by b 54 | b = 4; // corrupt memory access 55 | } 56 | 57 | void test() { 58 | S s; 59 | s.ptr = cast(byte*)malloc(1); 60 | foo(s, s.get()); // (*) 61 | } 62 | ``` 63 | The same problem using scope pointers: 64 | ```d 65 | struct S { 66 | byte* ptr; 67 | byte* get() { return ptr; } 68 | } 69 | 70 | void foo(scope S* t, scope byte* pb) { 71 | free(t.ptr); // frees memory referred to by pb 72 | *pb = 4; // corrupt memory access 73 | } 74 | 75 | void test() { 76 | S s; 77 | s.ptr = cast(byte*)malloc(1); 78 | foo(&s, s.get()); // (*) 79 | } 80 | ``` 81 | 82 | D currently has no defense against this problem, rendering checkably memory-safe 83 | reference counting impossible. (Timon Gehr first pointed this out.) 84 | 85 | ## Prior Work 86 | 87 | Rust avoids this problem with the following rule: 88 | 89 | ``` 90 | First, any borrow must last for a scope no greater than that of the owner. 91 | Second, you may have one or the other of these two kinds of borrows, but not 92 | both at the same time: 93 | 94 | 1. one or more references (&T) to a resource, 95 | 2. exactly one mutable reference (&mut T). 96 | ``` 97 | https://doc.rust-lang.org/1.8.0/book/references-and-borrowing.html#the-rules 98 | 99 | ## Description 100 | 101 | The solution hinges on the recognition that, in the example, two mutable references 102 | to the same data are passed to the function `foo()`. Generalizing, whenever there are 103 | multiple references to the same data and one of them is mutable, the mutable reference 104 | can be used to invalidate the data the other references refer to, whether they are 105 | `const` or not. Therefore, if more than one reference to the same data is passed to 106 | a function, they must all be `const`. 107 | 108 | This builds on the foundation established and tested by DIP 25 and DIP 1000, which track lifetimes 109 | through function calls and their returns, by adding an additional check on data 110 | already collected by the compiler semantics. The checks would only be enforced for `@safe` code. 111 | 112 | ### Syntax 113 | 114 | This DIP proposes no syntax changes. It adds additional semantic checks on existing 115 | constructs. 116 | 117 | ### Limitations 118 | 119 | The proposed feature only checks expressions that are function calls. It does not perform interstatement 120 | checking. It does not check non-scope pointers. It is not a complete borrowing/ownership 121 | scheme, although it is an important step in that direction. For example, the checking 122 | of scoped pointers can be defeated by using a temporary: 123 | 124 | ```d 125 | void test() { 126 | S s; 127 | s.ptr = cast(byte*)malloc(1); 128 | auto ps = &s; 129 | foo(ps, s.get()); // (*) 130 | } 131 | ``` 132 | The only way to resolve this is by using [Reaching Definitions](#reference) data flow analysis, which 133 | would be a fairly significant addition to the compiler. References, on the other hand, don't 134 | need Reaching Definitions because they can only be initialized once and that is always 135 | in scope. 136 | 137 | 138 | ## Breaking Changes and Deprecations 139 | 140 | This will break existing code that passes to a function multiple mutable references to the same object. 141 | It is unknown how prevalent a pattern this is. Breakage can be fixed either by 142 | finding another way to pass the arguments or by marking the code as `@trusted` 143 | or `@system`. 144 | 145 | 146 | ## Reference 147 | Reaching Definitions: https://en.wikipedia.org/wiki/Reaching_definition 148 | 149 | Ownership and Borrowing in D: https://dlang.org/blog/2019/07/15/ownership-and-borrowing-in-d/ 150 | 151 | 152 | ## Copyright & License 153 | 154 | Copyright (c) 2019 by the D Language Foundation 155 | 156 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 157 | 158 | ## Reviews 159 | 160 | ### Community Review Round 1 161 | 162 | [Reviewed Version](https://github.com/dlang/DIPs/blob/793f83911fdc8c88c6ef34e6a36b5e11e3e574e5/DIPs/DIP1021.md) 163 | 164 | [Discussion](https://forum.dlang.org/post/voxipsuzjjmuffwlwofp@forum.dlang.org) 165 | 166 | Some reviewers complained that the DIP lacks detail and that that the examples 167 | provided to illustrate the problem solved by the DIP were not sufficient. 168 | Particularly, examples to illustrate the problem using `@safe` code were 169 | requested since the DIP states that the checks it proposes be executed only in 170 | `@safe` code. The DIP author responded that extra information is included in 171 | the "Prior Work" section and the provided examples are sufficient to illustrate 172 | the problem. Much of the review discussion revolved around this disagreement. 173 | 174 | ### Final Review 175 | 176 | [Reviewed Version](https://github.com/dlang/DIPs/blob/1d78cdf1613911439848a49e9053a7bbf5a9de46/DIPs/DIP1021.md) 177 | 178 | [Discussion](https://forum.dlang.org/post/udqmnxucjsnuswdasylq@forum.dlang.org) 179 | 180 | Some of the criticisms from the Community Review regarding lack of detail were 181 | repeated, with some protest that no revisions were made in response to that 182 | feedback. Questions were raised about the "big picture" plans (as the author 183 | outlined [in this blog post](http://dlang.org/blog/2019/07/15/ownership-and-borrowing-in-d/)) 184 | and how this proposal fits into them. There was significant discussion regarding 185 | the implementation of ownership and borrowing in Rust and whether such is a good 186 | fit for D. 187 | 188 | ### Formal Assessment 189 | 190 | [Reviewed Version](https://github.com/dlang/DIPs/blob/1d78cdf1613911439848a49e9053a7bbf5a9de46/DIPs/DIP1021.md) 191 | 192 | This proposal was formally accepted by the language maintainers with minor revision 193 | to indicate that this proposal is part of a larger plan to bring ownership and 194 | borrowing to D. -------------------------------------------------------------------------------- /DIPs/accepted/DIP1024.md: -------------------------------------------------------------------------------- 1 | # Shared Atomics 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1024 | 6 | | Review Count: | 3 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | https://github.com/dlang/dmd/pull/10209 | 9 | | Status: | Accepted | 10 | 11 | ## Abstract 12 | 13 | Reads and writes to data typed as `shared` are not supported by operators 14 | in the core language. They are only accessible via function calls from 15 | the library. 16 | 17 | ## Contents 18 | * [Rationale](#rationale) 19 | * [Description](#description) 20 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 21 | * [Reference](#reference) 22 | * [Copyright & License](#copyright--license) 23 | * [Reviews](#reviews) 24 | 25 | ## Rationale 26 | 27 | Making shared types a first class type in D was an effective innovation. The ability 28 | to distinguish between shared and unshared data is critical for developing robust multi-threaded 29 | applications. But D stopped short of altering the semantics of access to shared data, 30 | making the default behavior subject to data races both obvious and hidden as the result of code 31 | motion by optimizing compilers. 32 | 33 | By prohibiting direct access to shared data, the user will be required to use `core.atomic` 34 | and to consider the correctness of their code. 35 | 36 | ## Description 37 | 38 | Programmers will now be required to use `core.atomic`, or equivalent functions, to read and write 39 | to shared memory objects. The compiler will report an error when any attempt is made to directly read 40 | or write to a shared memory object. This will prevent unintended, inadvertent non-use of atomic access. 41 | 42 | Initialization of shared data is permitted. 43 | 44 | There are no syntactical changes. 45 | 46 | Examples: 47 | 48 | ``` 49 | shared int x; // ok, initialization to 0 50 | ++x; // error, read and write of shared x 51 | shared int* p = &x; // ok, initialization of shared p 52 | shared int* q = p; // error, read of shared p 53 | shared(int)* r = &x; // ok 54 | shared(int)* s = r; // ok 55 | *s = 3; // error, write to shared *s 56 | int y = *s; // error, read from shared *s 57 | ``` 58 | 59 | ### Limitations 60 | 61 | This proposal does not guarantee code will be deadlock-free, nor does it obviate the need 62 | for locks for transaction-race-free behavior. (A transaction is a sequence of operations 63 | that must occur without another thread altering the shared data before the transaction is completed.) 64 | 65 | It does not prohibit casting shared data to unshared data, and then operating on it via 66 | the core language operators, although such would only be allowed in `@system` and `@trusted` 67 | code. 68 | 69 | ### Alternatives 70 | 71 | Provide limited support for locked operations with operators where the CPU supports it. 72 | C++ provides such. This is controversial, as some believe it encourages incorrect coding 73 | practices. 74 | 75 | ## Breaking Changes and Deprecations 76 | 77 | All code that accesses shared memory objects will break. 78 | This means there will be a long deprecation cycle. 79 | 80 | Code that uses `core.atomic` should continue to work correctly. 81 | 82 | Code that is protected by locks will need to 'strip' `shared` off of the head 83 | of the type so that normal code generation can be performed. 84 | This is achieved via `cast()expression` or `cast(const)expression`. 85 | Users will have to be careful not to let any references to those head-unshared memory 86 | locations escape the locked code region, but that was true anyway prior to this change. 87 | 88 | 89 | ## Reference 90 | 91 | [1] [Sequential Consistency](https://en.wikipedia.org/wiki/Sequential_consistency) 92 | 93 | [2] [Data race](https://en.wikipedia.org/wiki/Race_condition#Software) 94 | 95 | ## Copyright & License 96 | 97 | Copyright (c) 2019 by the D Language Foundation 98 | 99 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 100 | 101 | ## Reviews 102 | 103 | ### Community Review Round 1 104 | 105 | [Reviewed Version](https://github.com/dlang/DIPs/blob/0b892dd99aba74b9631572ad3a53000f5975b7c2/DIPs/DIP1024.md) 106 | 107 | [Discussion](https://forum.dlang.org/post/wcoboszbrdgxcsidwndd@forum.dlang.org) 108 | 109 | A major, repeated complaint focused on contradictory portions of the text which caused confusion among reviewers. 110 | The DIP author explained this was an error that occurred during editing and that it will be corrected in the next revision. 111 | Aside from a request that the author include references to other languages, the remainder of the discussion was on 112 | related topics (e.g. the current and intended behavior of shared). 113 | 114 | ### Community Review Round 2 115 | 116 | [Reviewed Version](https://github.com/dlang/DIPs/blob/0093abce72fa803b9e4067db500171c634daa4a9/DIPs/DIP1024.md) 117 | 118 | [Discussion](https://forum.dlang.org/post/jetqewtibsnrsdpcydph@forum.dlang.org) 119 | 120 | Only two items of actionable feedback were provided during this round of review: perhaps examples of the sort of code this change will break could be added; and the sentence beginning "Atomic reads perform an acquire operation..." is irrelevant to the proposal and should probably be removed. The DIP author revised the DIP accordingly. 121 | 122 | ### Final Review 123 | 124 | [Reviewed Version](https://github.com/dlang/DIPs/blob/78a5bc098fa00c44f11d1819919eb78b8d263254/DIPs/DIP1024.md) 125 | 126 | [Discussion](https://forum.dlang.org/post/ippdfqxnxbhxwzfdotcm@forum.dlang.org) 127 | 128 | A request was made for a reference on the claim that "support for locked operators where the CPU supports it" is controversial. It was rejected by the DIP author on the grounds that it was based on a conversation with Herb Sutter, so there is no source to reference. 129 | 130 | A suggestion to include a statement that this proposal "makes shared unusable in betterC code" led to discussion about `shared` and BetterC, which concluded that `shared` can still be used with BetterC. 131 | 132 | ### Formal Assessment 133 | 134 | [Reviewed Version](https://github.com/dlang/DIPs/blob/71a7a0d22385b7429ee54d4db6f64958c433f1a8/DIPs/DIP1024.md) 135 | 136 | The language maintainers accepted the proposal without comment. 137 | -------------------------------------------------------------------------------- /DIPs/accepted/DIP1029.md: -------------------------------------------------------------------------------- 1 | # Add `throw` as Function Attribute 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1029 | 6 | | Review Count: | 2 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | https://github.com/dlang/dmd/pull/12934 | 9 | | Status: | Accepted | 10 | 11 | ## Abstract 12 | Add the `throw` attribute as the inverse of the `nothrow` attribute. 13 | 14 | ## Contents 15 | * [Rationale](#rationale) 16 | * [Prior Work](#prior-work) 17 | * [Description](#description) 18 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 19 | * [Reference](#reference) 20 | * [Copyright & License](#copyright--license) 21 | * [Reviews](#reviews) 22 | 23 | ## Rationale 24 | Currently, functions are by default allowed to throw exceptions. This behavior can be changed 25 | by applying the `nothrow` attribute to a function. But once `nothrow` is used at module scope 26 | or in a block, all functions in its scope are affected; there is no escape. 27 | 28 | This is why aggregates do not "inherit" the `nothrow` attribute from the outer scope. 29 | If the entire module needs to be `nothrow`, the attribute must be applied not only at module 30 | scope but inside the definition of each aggregate: 31 | 32 | ```d 33 | void bar(); // may throw 34 | 35 | struct S1 { 36 | nothrow void foo() { bar(); } // error, bar() throws 37 | } 38 | 39 | nothrow { 40 | struct S2 { 41 | void foo() { bar(); } // no error, as the nothrow block does not apply 42 | } 43 | } 44 | ``` 45 | 46 | The problem is that exceptions are not cost-free, even in code that never throws. Exceptions 47 | should therefore be opt-in, not opt-out. Although this DIP does not propose making exceptions 48 | opt-in, the `throw` attribute is a key requirement for it. The attribute also serves 49 | well as documentation that yes, a function indeed can throw. 50 | 51 | ## Prior Work 52 | The `@safe`, `@trusted`, and `@system` attributes can override each other. 53 | 54 | ## Description 55 | Add `throw` to [Attribute](https://dlang.org/spec/attribute.html#Attribute). 56 | Add `throw` to [FunctionAttribute](https://dlang.org/spec/function.html#FunctionAttribute). 57 | This produces an ambiguity with the start of a 58 | [ThrowStatement](https://dlang.org/spec/statement.html#throw-statement) 59 | but can be disambiguated by looking ahead to see if an `Expression`follows or a `Declaration`. 60 | 61 | The attribute applies only to function and delegate types. For other types, it is ignored. 62 | Its presence in a function declaration indicates that the function may throw an `Exception`. 63 | 64 | ```d 65 | void bar() throw; 66 | 67 | struct S1 { 68 | nothrow void foo() { bar(); } // error, bar() throws 69 | } 70 | 71 | struct S2 { 72 | void foo() { bar(); } // no error 73 | } 74 | ``` 75 | 76 | `throw` and `nothrow` cannot be combined, but can override one another in an enclosing scope: 77 | 78 | ```d 79 | void abc() throw throw; // Error 80 | void bar() throw nothrow; // Error 81 | 82 | nothrow: 83 | void foo() throw; // Ok 84 | 85 | throw: 86 | void def() nothrow; // Ok 87 | ``` 88 | 89 | ### Grammar Changes 90 | `throw` is added to `FunctionAttribute:`. 91 | 92 | ```diff 93 | FunctionAttribute: 94 | + throw 95 | nothrow 96 | pure 97 | Property 98 | ``` 99 | 100 | `throw` is added to `StorageClass:`. 101 | 102 | ```diff 103 | StorageClass: 104 | LinkageAttribute 105 | AlignAttribute 106 | deprecated 107 | enum 108 | static 109 | extern 110 | abstract 111 | final 112 | override 113 | synchronized 114 | auto 115 | scope 116 | const 117 | immutable 118 | inout 119 | shared 120 | __gshared 121 | Property 122 | + throw 123 | nothrow 124 | pure 125 | ref 126 | ``` 127 | 128 | ## Breaking Changes and Deprecations 129 | None 130 | 131 | ## Reference 132 | Herb Sutter notes in 133 | [De-fragmenting C++: Making exceptions more affordable and usable](https://www.youtube.com/watch?v=os7cqJ5qlzo) 134 | that half of C++ users either prohibit exceptions wholly or partially in their C++ code. 135 | 136 | ## Copyright & License 137 | Copyright (c) 2019 by the D Language Foundation 138 | 139 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 140 | 141 | ## Reviews 142 | 143 | ### Community Review Round 1 144 | 145 | [Reviewed Version](https://github.com/dlang/DIPs/blob/8c48c98a0495f73db9a2d5c4aef502b9febe9673/DIPs/DIP1029.md) 146 | 147 | [Discussion](https://forum.dlang.org/post/sbdrybtyfkxfhxxjgqco@forum.dlang.org) 148 | 149 | The following specific points were raised in the review thread: 150 | * Use `@throws` and change `nothrow` to `@nothrow`. The DIP author said that `throw` is already a keyword, adding `throws` would be excessive, and `@` is unnecessary. 151 | * Provide a rationale for not using the `@` symbol. 152 | * The DIP could provide some search strategies for differentiating between the `throw` attribute and the `throw` statement. 153 | * What about the inverse of other attributes that do not have one? The DIP author said that since `throw` is already a keyword and it complements `nothrow`, using it as an inverse attribute makes sense. 154 | * If `throw` is a "key requirement" for opt-in exceptions, why not include both in one DIP? The DIP author responded that this proposal makes sense on its own and does not distract from a separate proposal for `nothrow` by default. 155 | 156 | ### Final Review 157 | 158 | [Reviewed Version](https://github.com/dlang/DIPs/blob/9db80ddadcf5a220958ddcfec14b9c71cdb43d1c/DIPs/DIP1029.md) 159 | 160 | [Discussion](https://forum.dlang.org/post/lyerouocavjvspqwvrmb@forum.dlang.org) 161 | 162 | [Feedback](https://forum.dlang.org/post/qhtqeavhyzjfamhgcjjl@forum.dlang.org) 163 | 164 | There were two specific points of feedback in the review thread: 165 | * `throw!bool` would be preferable. The DIP author disagreed, saying that this implies the function is throwing a `bool`. 166 | * `throw` should be added to `StorageClass` to avoid inconsistency with `nothrow`. The DIP author agreed. 167 | 168 | ### Formal Assessment 169 | 170 | [Reviewed Version](https://github.com/dlang/DIPs/blob/26e3ce642dc4e615e605ff740f663284fee69472/DIPs/DIP1029.md) 171 | 172 | This DIP was accepted with no request for revision. 173 | 174 | The Language Maintainers felt that arguments suggesting alternative syntax, such as `@throw` or `throw!bool`, are not persuasive. The motivation behind `@` in attribute names is to provide an alternative to the introduction of new keywords. However, `throw` is already a keyword, and adding `@throw` would introduce an incongruity with `nothrow`. Leaving them both as-is is the simplest approach. `throw!bool` would render `nothrow` redundant and is inconsistent with the existing set of built-in attributes. 175 | 176 | Also, there were no strong objections to the proposal itself. Although some objections were raised to the introduction of a counter to `nothrow` alone as opposed to a broader proposal encompassing all similar attributes, the Language Maintainers see no problem. This DIP is focused solely on the obvious application of the existing `throw` keyword to its new role. Any larger changes to attribute syntax are beyond its scope. -------------------------------------------------------------------------------- /DIPs/accepted/DIP1043.md: -------------------------------------------------------------------------------- 1 | # Shortened Method Syntax 2 | 3 | | Field | Value | 4 | |-----------------|----------------------------------------------------------------| 5 | | DIP: | 1043 | 6 | | Review Count: | 2 | 7 | | Author: | Max Haughton, Adam D. Ruppe | 8 | | Implementation: | https://github.com/dlang/dmd/pull/11833 | 9 | | Status: | Approved | 10 | 11 | ## Abstract 12 | This DIP proposes a shortened syntax for function definitions. 13 | The new syntax makes use of `=>` to separate the function header and function body in place of opening and closing braces: 14 | 15 | ```D 16 | int add(int x, int y) pure => x + y; 17 | ``` 18 | 19 | The feature is already implemented in the D programming language as a preview. 20 | 21 | ## Contents 22 | * [Rationale](#rationale) 23 | * [Prior Work](#prior-work) 24 | * [Description](#description) 25 | * [Reference](#reference) 26 | * [Copyright & License](#copyright--license) 27 | * [Reviews](#reviews) 28 | 29 | ## Rationale 30 | ### Consistency 31 | A shortened syntax for function literals is already supported in the D programming language. For example: 32 | 33 | ```D 34 | const succ = (int x) => x + 1; 35 | ``` 36 | 37 | is equivalent to 38 | 39 | ```D 40 | const succ = function(int x) { return x + 1; }; 41 | ``` 42 | 43 | Via a trivial change to the language, a similar syntax can be implemented for function definitions, 44 | making function literals and function definitions more uniform. 45 | 46 | ### Brevity 47 | Consider a simple `InputRange` which produces a range of `T`s that excludes one end (`[from, to)`). 48 | An implementation in D without the proposed syntax is 14 lines: 49 | 50 | ```d 51 | struct LongerExclusiveRange(T) 52 | { 53 | T from, to; 54 | invariant(from <= to); 55 | bool empty() { 56 | return from == to; 57 | } 58 | void popFront() { 59 | ++from; 60 | } 61 | T front() { 62 | return from; 63 | } 64 | } 65 | ``` 66 | 67 | An implementation utilizing the proposed feature is only 8 lines: 68 | 69 | ```d 70 | struct ExclusiveRange(T) 71 | { 72 | T from, to; 73 | invariant(from <= to); 74 | bool empty() => from == to; 75 | auto popFront() => ++from; 76 | T front() => from; 77 | } 78 | ``` 79 | Note that some style guides may permit both braces of a function on the same line. In this case, the use of this feature may not result in a saving of lines, but there will be fewer keystrokes by virtue of there being no braces. 80 | 81 | More fundamentally than mere line or even character counting, however, use of this syntax reduces a function to the essence of its action. In short, the tokens remaining are the ones [that do work](https://en.wikipedia.org/wiki/Work_(physics)). A function that does not require the use of braces (a block statement) or even a statement at all may simply avoid their use entirely. This is a small step towards reducing obstreperous visual noise that can plague virtually any program. 82 | 83 | For example, take this arbitrary yet representative composition of ranges: 84 | 85 | ```d 86 | auto doesWork() 87 | => iota(1, 100) 88 | .map!(x => x + 1) 89 | .filter!(x => x > 4) 90 | .each!writeln; 91 | ``` 92 | 93 | With the shortened methods syntax, this function terminates syntactically in the same place it does semantically. 94 | The call to `each` is where the function's work ends. With the proposed syntax. this is also where it ends lexically (barring the semi-colon). 95 | 96 | ## Prior Work 97 | This DIP has the potential to result in a post-facto blessing of a preview feature already supported by the compiler. 98 | [The existing implementation](https://github.com/dlang/dmd/pull/11833) was written by Adam D. Ruppe. 99 | 100 | The proposed feature is present in the C# programming language, where instances of its use are referred to as 101 | [expression-bodied members](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members). 102 | 103 | The C# documentation demonstrates an idiomatic example of the proposed feature, reproduced here: 104 | 105 | ```c# 106 | public class Location 107 | { 108 | private string locationName; 109 | 110 | public Location(string name) 111 | { 112 | locationName = name; 113 | } 114 | 115 | public string Name => locationName; 116 | } 117 | ``` 118 | 119 | Note that the `Name` function is a simple one-liner that returns the `locationName` member. Such one-liners are common in C#, 120 | where programmers are encouraged to provide access to member variables via member functions. 121 | 122 | ## Description 123 | 124 | ### Semantics 125 | The proposed semantics are a simple example of what is referred to in the theory of programming language implementation as lowering: 126 | 127 | ```d 128 | FunctionDeclarator => AssignExpression; 129 | ``` 130 | 131 | shall be rewritten to 132 | 133 | ```d 134 | FunctionDeclarator 135 | { 136 | return AssignExpression; 137 | } 138 | ``` 139 | 140 | Given that constructors and destructors cannot have return values, the implementation should reject any attempt to implement a constructor or destructor using the shortened method syntax and provide a meaningful error message. 141 | 142 | #### Contract programming 143 | It has been noted (see below) that the preview implementation allows the use of 144 | function contracts with this syntax. Contract programming is not available in the use of [shortened function literals](https://dlang.org/spec/expression.html#function_literals) (i.e. `x => x * 2`), so this DIP does not allow them. Since this DIP aims to make expressions and declarations consistent, use of contact programming is not proposed on the shortened form. 145 | 146 | ### Grammar 147 | The proposed feature requires the following grammar changes: 148 | ```diff 149 | FunctionBody: 150 | SpecifiedFunctionBody 151 | MissingFunctionBody 152 | + ShortenedFunctionBody 153 | ... 154 | 155 | +ShortenedFunctionBody: 156 | + => AssignExpression ; 157 | ``` 158 | 159 | 160 | ## Reference 161 | * Initially https://github.com/dlang/dlang.org/pull/3059 and finally https://github.com/dlang/dlang.org/pull/3198 are two PRs that document theacceptance of contracts on the shortened function syntax. 162 | 163 | ### Trivia 164 | * [The syntax was mentioned on the D Bugzilla in 2011](https://issues.dlang.org/show_bug.cgi?id=7176). The dialectics in this thread can be considered a pre-review. 165 | * [Shortened Methods are documented in the specification](https://github.com/dlang/dlang.org/pull/2956) 166 | Note the validity of contract programming, which is not exactly compliant with this DIP. 167 | * [A dmd changelog entry was added](https://github.com/dlang/dmd/pull/12241) on the 28th of February 2021 168 | 169 | ## Copyright & License 170 | Copyright (c) 2022 by the D Language Foundation 171 | 172 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 173 | 174 | ## Reviews 175 | 176 | ### Community Review Round 1 177 | [Reviewed Version](https://github.com/dlang/DIPs/blob/2e6d428f42b879c0220ae6adb675164e3ce3803c/DIPs/DIP1042.md) 178 | 179 | [Discussion](https://forum.dlang.org/post/jrigjbciylxzwubuopez@forum.dlang.org) 180 | 181 | [Feedback](https://forum.dlang.org/post/picueoqamrouueyntjmk@forum.dlang.org) 182 | 183 | The following actionable feedback was provided in the feedback thread: 184 | 185 | * The example provided in the Rationale is misleading in its implication that the features saves lines of code, as the original functions could be written as one lines; as such, the example should be dropped. The DIP author responded that the feature still saves on typing, and also that some coding standards may prohibit one-liners with braces. 186 | * The DIP's claim that "function contracts are not possible in function literals" is inaccurate; they simply aren't allowed with the arrow syntax. 187 | 188 | ### Final Review 189 | [Reviewed Version](https://github.com/dlang/DIPs/blob/2c2f6c33f5761236266a96bd268c62a06323a5e8/DIPs/DIP1043.md) 190 | 191 | [Discussion](https://forum.dlang.org/thread/drvmkookrgasjeeuuutn@forum.dlang.org) 192 | 193 | [Feedback](https://forum.dlang.org/post/xxfdyxrnskdxzvdigwld@forum.dlang.org) 194 | 195 | The following items were provided in the feedback thread: 196 | 197 | * Line-counting isn't a contrived argument and should be removed. 198 | * References to more languages should be added, e.g., Dart. 199 | * The DIP should also include arguments against the feature. 200 | * The DIP should explicitly mention that it allows function templates. 201 | 202 | ### Formal Assessment 203 | The language maintainers accepted this DIP on the grounds that the proposed feature had already been implemented as a preview feature for some time without problem or complaint. One of the maintainers suggested an enhancement to the proposal in the form of shortening the syntax even further, such that `T front() => from` would become `T front => from`. The DIP author decided against this, leaving the possibility open for future enhancement. -------------------------------------------------------------------------------- /DIPs/accepted/DIP1046.md: -------------------------------------------------------------------------------- 1 | # `ref` For Variable Declarations 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1046 | 6 | | Author: | Walter Bright walter@walterbright.com | 7 | | Implementation: | https://github.com/dlang/dmd/pull/16428 | 8 | | Status: | Accepted | 9 | 10 | ## Abstract 11 | 12 | Enable local variables to be declared as `ref`. 13 | 14 | 15 | ## Contents 16 | 17 | * [Rationale](#rationale) 18 | * [Prior Work](#prior-work) 19 | * [Description](#description) 20 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 21 | * [Reference](#reference) 22 | * [Copyright & License](#copyright--license) 23 | * [History](#history) 24 | 25 | ## Rationale 26 | 27 | Ref declarations are a restricted form of pointer declarations. They are restricted 28 | in that: 29 | 30 | 1. they cannot reassigned after initialization 31 | 2. pointer arithmetic cannot be done on them 32 | 3. they cannot be copied, other than being used to initialize another ref 33 | 34 | Decades of successful use have demonstrated the utility of this form of 35 | restricted pointer. Ref declarations are a major tool for writing memory-safe code, 36 | and self-documenting the restricted use of being a ref rather than a pointer. 37 | 38 | Currently, ref declarations are only allowed for: 39 | 40 | 1. function parameters 41 | 2. function return values 42 | 3. declaration references to element types in a foreach statement 43 | 44 | Of particular interest here is the success of item (3). There doesn't appear to 45 | be a downside of using `ref` for such declarations, so by extension ordinary 46 | local variables should also benefit from being declared as `ref`. Often I've run 47 | across cases where declaring a local as `ref` rather than a pointer would have 48 | made the code nicer and safer. 49 | 50 | This DIP is for declaring local variables as `ref` and does not extend to globals, `static`s, `extern`s, 51 | `__gshared`s, or fields. 52 | 53 | 54 | ## Prior Work 55 | 56 | C++ allows variables to be declared as a reference rather than a pointer. The same 57 | goes for `ref` struct field declarations, although that is not part of this proposal. 58 | 59 | References in C#: 60 | https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/declarations#reference-variables 61 | 62 | ## Description 63 | 64 | `ref` is already allowed in the grammar for variable declarations, it is disallowed 65 | in the semantic pass. 66 | https://dlang.org/spec/declaration.html#VarDeclarations 67 | This proposal will "turn it on" so to speak, and its behavior will be the same as 68 | the current behavior for assigning to function ref parameters. 69 | 70 | Returning a `ref` variable from a function that returns a `ref` to a local stack variable is not allowed, i.e. 71 | a `ref` cannot be assigned to a `ref` with a scope that exceeds the scope of the source. 72 | 73 | ```d 74 | ref int dark(ref int x, int i, int* q) 75 | { 76 | ref m = *q; // m refers to whatever q points to 77 | 78 | ref j = i; // j now points to i 79 | j = 3; // now i is 3 as well 80 | 81 | auto k = j; // k is an int with value 3 82 | auto p = &j; // p is a pointer to i 83 | 84 | ref int y = x; // ok 85 | if (i) 86 | return x; // ok 87 | else 88 | return y; // nope 89 | } 90 | ``` 91 | 92 | An example showing the utility of `ref`. This is from the DMD code generator: 93 | ```d 94 | void pop87(int line, const(char)* file) 95 | { 96 | if (NDPP) 97 | printf("pop87(%s(%d): stackused=%d)\n", file, line, global87.stackused); 98 | 99 | --global87.stackused; 100 | assert(global87.stackused >= 0); 101 | foreach (i; 0 .. global87.stack.length - 1) 102 | global87.stack[i] = global87.stack[i + 1]; 103 | // end of stack is nothing 104 | global87.stack[$ - 1] = NDP(); 105 | } 106 | ``` 107 | 108 | becomes: 109 | 110 | ```d 111 | void pop87(int line, const(char)* file) 112 | { 113 | ref g = global87; 114 | if (NDPP) 115 | printf("pop87(%s(%d): stackused=%d)\n", file, line, g.stackused); 116 | 117 | --g.stackused; 118 | assert(g.stackused >= 0); 119 | foreach (i; 0 .. g.stack.length - 1) 120 | g.stack[i] = g.stack[i + 1]; 121 | // end of stack is nothing 122 | g.stack[$ - 1] = NDP(); 123 | } 124 | ``` 125 | 126 | which reduces the complexity of the code, as long-winded global names get a shorthand. 127 | 128 | 129 | C++ rvalue references are not part of this proposal. 130 | 131 | ## Breaking Changes and Deprecations 132 | 133 | No breaking changes are anticipated. 134 | 135 | ## Reference 136 | 137 | Implementation: 138 | https://github.com/dlang/dmd/pull/16428 139 | 140 | References in D: 141 | https://dlang.org/spec/declaration.html#ref-storage 142 | 143 | Foreach ref parameters: 144 | https://dlang.org/spec/statement.html#foreach_ref_parameters 145 | 146 | References in C++: 147 | https://en.cppreference.com/w/cpp/language/reference 148 | 149 | ## Copyright & License 150 | 151 | Copyright (c) 2024 by the D Language Foundation 152 | 153 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 154 | 155 | ## History 156 | 157 | This DIP underwent two rounds of community feedback in the DIP development forum: 158 | 159 | Feedback on the first draft: 160 | https://forum.dlang.org/post/uvc6dq$2jjn$1@digitalmars.com 161 | 162 | Feedback on the second draft: 163 | https://forum.dlang.org/post/v11mh1$fvs$1@digitalmars.com 164 | 165 | Given that the DIP author is one of the language maintainers, it was presented at a D Language Foundation meeting to determine if there were any objections to submitting it to the other language maintainer, Átila Neves, for approval. No objections were raised. In addition to the DIP author, the following people were present for that portion of the meeting: 166 | 167 | Jonathan M. Davis, 168 | Timon Gehr, 169 | Martin Kinkelin, 170 | Dennis Korpel, 171 | Mathias Lang, 172 | Mike Parker, 173 | Robert Schadek, 174 | Steven Schveighoffer, and 175 | Adam Wilson 176 | 177 | Átila reviewed the DIP and approved it after asking for a clarification. He agrees with the DIP's rationale that ref declarations are a major tool for writing memory-safe code and believes that aligns with our overarching goal of enhancing memory safety. 178 | -------------------------------------------------------------------------------- /DIPs/archive/DIP20.md: -------------------------------------------------------------------------------- 1 | # Volatile read/write intrinsics 2 | 3 | | Sectin | Value | 4 | |----------------|---------------------------------------------------------------| 5 | | DIP: | 20 | 6 | | Status: | Implemented | 7 | | Author: | Alex Rønne Petersen (alex (AT) lycus.org) | 8 | | Implementation:| | 9 | 10 | ## Abstract 11 | 12 | This document describes a couple of simple compiler intrinsics that D compilers 13 | should implement. These are necessary for low-level, embedded, kernel, and 14 | driver developers. These intrinsics will ensure that a compiler cannot reorder 15 | volatile loads and stores with regards to each other. 16 | 17 | ### Links 18 | 19 | * 20 | 21 | ## Description 22 | 23 | Two intrinsics shall be declared in the core.bitop module. 24 | 25 | The first one, volatileLoad is used to perform volatile read operations from memory: 26 | 27 | ``` D 28 | T volatileLoad(T)(T* ptr); 29 | ``` 30 | 31 | A call to this function, such as: 32 | 33 | ``` D 34 | T* p = ...; 35 | T i = volatileLoad(p); 36 | ``` 37 | 38 | Shall be equivalent to: 39 | 40 | ``` D 41 | T* p = ...; 42 | T i = *p; 43 | ``` 44 | 45 | However, with the exception that the compiler is not allowed to optimize out 46 | seemingly dead calls to volatileLoad, nor reorder calls to volatileLoad with 47 | respect to other calls to it or volatileStore. The second, volatileStore is 48 | used to perform volatile write operations to memory: 49 | 50 | ``` D 51 | void volatileStore(T)(T* ptr, T val); 52 | ``` 53 | 54 | A call to this function, such as: 55 | 56 | ``` D 57 | T* p = ...; 58 | T i = ...; 59 | volatileStore(p, i); 60 | ``` 61 | 62 | Shall be equivalent to: 63 | 64 | ``` D 65 | T* p = ...; 66 | T i = ...; 67 | *p = i; 68 | ``` 69 | 70 | However, with the exception that the compiler is not allowed to optimize out 71 | seemingly dead calls to volatileStore, nor reorder calls to volatileStore with 72 | respect to other calls to it or volatileLoad. 73 | 74 | ### Detection 75 | 76 | Compilers that support these intrinsics should define the D\_Volatile version 77 | identifier. Compilers are free to support the intrinsics without defining this 78 | version identifier, but programmers should not rely on the presence of the 79 | intrinsics if it is not defined. 80 | 81 | ### Rationale 82 | 83 | D currently has no way to do safe memory-mapped I/O. The reason for that is 84 | that the language has no well-defined means to do volatile memory loads and 85 | stores. This means that a compiler is free to reorder memory operations as it 86 | sees fit and even erase some loads/stores that it thinks are dead (but which 87 | have actual impact on program semantics). 88 | 89 | These intrinsics will be essential for low-level development in D. D cannot 90 | truly replace C and/or C++ until it can perform the same low-level operations 91 | that developers who use those languages are accustomed to. 92 | 93 | ### Implementation 94 | 95 | #### DMD 96 | 97 | DMD does not currently reorder loads and stores, so no particular change needs 98 | to happen in this area of the compiler. However, it is quite likely that the 99 | back end eliminates dead loads and stores, so calls to the intrinsics must be 100 | flagged as volatile in whatever way DMD's back end allows it. 101 | 102 | #### GDC 103 | 104 | GCC's internal code representation allows volatile statements in the C sense, 105 | which is sufficient. 106 | 107 | #### LDC 108 | 109 | [LLVM trivially allows marking loads and stores as volatile](http://llvm.org/docs/LangRef.html#volatile) 110 | 111 | #### Other compilers 112 | 113 | Other compilers presumably have similar means to flag loads and stores as volatile. 114 | 115 | ### Alternatives 116 | 117 | A number of alternatives to volatile intrinsics have been suggested. They are, 118 | however, not good enough to actually replace a volatile intrinsics for the 119 | reasons outlined below. 120 | 121 | #### Shared qualifier 122 | 123 | The shared type qualifier has been suggested as a solution to the problems 124 | volatile intrinsics try to solve. However: 125 | 126 | - It is not implemented in any compiler, so practically using it now is not 127 | possible at all. 128 | - It does not have any well-defined semantics yet. 129 | - It will most likely not be portable because it's designed for the x86 130 | memory model. 131 | - If ever implemented, it will result in memory fences and/or atomic 132 | operations, which is \*\*not\*\* what volatile memory operations \* are 133 | about. This will severely affect pipelining and performance in general. 134 | 135 | #### Inline assembly 136 | 137 | It was suggested to use inline assembly to perform volatile memory operations. While a correct solution, it is not reasonable: 138 | 139 | - It leads to unportable programs. 140 | - It leads to a dependency on the compiler's inline assembly syntax. 141 | - Some compilers may even decide to optimize the assembly itself. 142 | - Memory-mapped I/O is too common in low-level programming for a systems 143 | language to require the programmer to drop to assembly. 144 | 145 | ## Copyright & License 146 | 147 | Copyright (c) 2016 by the D Language Foundation 148 | 149 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 150 | -------------------------------------------------------------------------------- /DIPs/archive/DIP22.md: -------------------------------------------------------------------------------- 1 | # Private symbol (in)visibility 2 | 3 | | Section | Value | 4 | |----------------|---------------------------------------------------------------------------------------------| 5 | | DIP: | 22 | 6 | | Status: | Implemented | 7 | | Author: | Михаил Страшун (Dicebot) and Martin Nowak | 8 | | Implementation:| | 9 | 10 | ## Abstract 11 | 12 | This proposal attempts to solve one of important issues with current protection 13 | attribute design: senseless name clashes between **private** and **public** 14 | symbols. So change of **private** related name resolution rules is proposed. 15 | 16 | ### Links 17 | 18 | * [Access specifiers and visibility](https://wiki.dlang.org/Access_specifiers_and_visibility) 19 | 20 | ## Rationale 21 | 22 | **private** is an encapsulation tool. If it is not intended to be used by 23 | "outsiders", it should not interfere with them at all. It creates no new 24 | limitations and reduces amount of code breakage by changes in other modules. 25 | 26 | ## Description 27 | 28 | - Private restricts the visibility of a symbol. 29 | 30 | A **private** symbol will not interact with other modules. 31 | 32 | In case lookup for a symbol fails the compiler might suggest **private** 33 | symbols similar to how spell checking works. 34 | 35 | - The least protected symbol determines the visibility for overloads. 36 | 37 | After overload resolution an additional access check will be performed. 38 | Thereby overload resolution remains independent of lookup origin. 39 | 40 | - Meta programming tools like `__traits` and `.tupleof` can access **private** 41 | symbols. 42 | 43 | This is necessary for some generic code, e.g. serialization. 44 | 45 | - All changes apply for modules as well as for classes. 46 | 47 | Protection has module granularity so looking up **private** 48 | members of a base class from a different module follows 49 | the same rules as accessing other **private** symbols from 50 | a different module. 51 | 52 | Additionally **protected** allows access from derived classes 53 | but not from other modules. 54 | 55 | - Alias protection overrides the protection of the aliased symbol. 56 | 57 | A **public** alias to a **private** symbol makes the symbol 58 | accessibly through the alias. The alias itself needs to be 59 | in the same module, so this doesn't impair protection control. 60 | 61 | ### Other protection attribute changes 62 | 63 | - **public** stays the same 64 | - **package** matches **private** changes from the point of view of other 65 | packages 66 | - **extern** stays the same 67 | - **protected** matches **private** changes, descendants still treat protected 68 | symbols as **public** ones. 69 | 70 | ### Breaking changes / deprecation process 71 | 72 | No previously valid code will become illegal in normal use cases, as this 73 | proposal is more permissive than current behavior. As `__traits` and `.tupleof` 74 | will still work for **private** as before, any library that relies on them 75 | should not break. 76 | 77 | ### Walter's concerns 78 | 79 | [original comment](http://forum.dlang.org/post/kb86il$1u9v$1@digitalmars.com) 80 | 81 | 1. *what access means at module scope* 82 | 83 | "Does this symbol is ignored when doing symbol name lookup?". All protection 84 | attributes boil down to simple answer (Yes/No) depending on symbol origins and 85 | place lookup is made from. In example: 86 | 87 | Symbol origin: module a; 88 | Look-up origin: not module a; 89 | Symbol protection attribute: private 90 | Answer: No 91 | 92 | 2. *at class scope* 93 | 94 | D minimal encapsulation unit is a module. **Private** class members are, 95 | technically, **private** module members and thus have the same behavior. Same 96 | for **package** and **public**. **Protected** is only special case that takes 97 | additional parameter into consideration. 98 | 99 | 3. *at template mixin scope* 100 | 101 | No changes here. For templates lookup origin is definition module. For mixin 102 | templates - instantiation module. Other than that, usual rules apply. 103 | 104 | 4. *backwards compatibility* 105 | 106 | See "Possible code breakage and solutions" 107 | 108 | 5. overloading at each scope level and the interactions with access 109 | 110 | See "Description". 111 | 112 | 6. *I'd also throw in getting rid of the "protected" access attribute completely, as I've seen debate over that being a useless idea* 113 | 114 | I have found no harm in keeping it. This will break code for sure and is 115 | irrelevant to this DIP topic. 116 | 117 | 7. *there's also some debate about what "package" should mean* 118 | 119 | This is also irrelevant to this DIP. While there may be debates on meaning of 120 | package concept, meaning of **package** protection attribute is solid: 121 | encapsulation within set of modules belonging to same package, whatever they 122 | are. 123 | 124 | ## Copyright & License 125 | 126 | Copyright (c) 2016 by the D Language Foundation 127 | 128 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 129 | -------------------------------------------------------------------------------- /DIPs/archive/DIP25.md: -------------------------------------------------------------------------------- 1 | # Sealed references 2 | 3 | | Section | Value | 4 | |----------------|----------------------------------------| 5 | | DIP: | 25 | 6 | | Status: | Implemented | 7 | | Author: | Walter Bright and Andrei Alexandrescu | 8 | 9 | ## Abstract 10 | 11 | D offers a number of features aimed at systems-level coding, such as 12 | unrestricted pointers, casting between integers and pointers, and the 13 | [`@system`](http://dlang.org/function.html#system-functions) attribute. These 14 | means, combined with the other features of D, make it a complete and expressive 15 | language for systems-level tasks. On the other hand, economy of means should be 16 | exercised in defining such powerful but dangerous features. Most other features 17 | should offer good safety guarantees with little or no loss in efficiency or 18 | expressiveness. This proposal makes `ref` provide such a guarantee: with the 19 | proposed rules, it is impossible in safe code to have `ref` refer to a 20 | destroyed object. The restrictions introduced are not entirely backward 21 | compatible, but disallow code that is stylistically questionable and that can 22 | be easily replaced either with equivalent and clearer code. 23 | 24 | ### Links 25 | 26 | * [DIP71: 'noscope' and 'out!param' attributes](http://wiki.dlang.org/DIP71) 27 | 28 | ## Description 29 | 30 | ### In a nutshell 31 | 32 | This DIP proposes that any `ref` parameter that a function received and also 33 | wants to return must be also annotated with `return`. Annotation are deduced 34 | for templates and lambdas, but must be explicit for all other declarations. 35 | 36 | Example: 37 | 38 | ``` D 39 | @safe: 40 | ref int fun(ref int a) { return a; } // ERROR 41 | ref int gun(return ref int a) { return a; } // FINE 42 | ref T hun(T)(ref T a) { return a; } // FINE, templates use deduction 43 | ``` 44 | 45 | ### Detailed Description 46 | 47 | Currently, D has some provisions for avoiding dangling references: 48 | 49 | ``` D 50 | ref int fun(int x) { 51 | return x; // Error: escaping reference to local variable x 52 | } 53 | 54 | ref int gun() { 55 | int x; 56 | return x; // Error: escaping reference to local variable x 57 | } 58 | 59 | struct S { 60 | int x; 61 | } 62 | 63 | ref int hun() { 64 | S s; 65 | return s.x; // see https://issues.dlang.org/show_bug.cgi?id=13902 66 | } 67 | 68 | ref int iun() { 69 | int a[42]; 70 | return a[5]; // see https://issues.dlang.org/show_bug.cgi?id=13902 71 | } 72 | ``` 73 | 74 | However, this enforcement is shallow (even after fixing [issue 75 | 13902](https://issues.dlang.org/show_bug.cgi?id=13902)). The following code 76 | compiles and allows reads and writes through defunct stack locations, bypassing 77 | scoping and lifetime rules: 78 | 79 | ``` D 80 | ref int identity(ref int x) { 81 | return x; // pass-through function that does nothing 82 | } 83 | 84 | ref int fun(int x) { 85 | return identity(x); // escape the address of a parameter 86 | } 87 | 88 | ref int gun() { 89 | int x; 90 | return identity(x); // escape the address of a local 91 | } 92 | 93 | struct S { 94 | int x; 95 | ref int get() { return x; } 96 | } 97 | 98 | ref int hun(S x) { 99 | return x.get; // escape the address of a part of a parameter 100 | } 101 | 102 | ref int iun() { 103 | S s; 104 | return s.get; // escape the address of part of a local 105 | } 106 | 107 | ref int jun() { 108 | return S().get; // worst contender: escape the address of a part of an rvalue 109 | } 110 | ``` 111 | 112 | The escape patterns are obvious in these simple examples that make all code 113 | available and use no recursion, and may be found automatically. The problem is 114 | that generally the compiler cannot see the body of `identity` or `S.get()`. We 115 | need to devise a method that derives enough information for safety analysis 116 | only given the function signatures, not their bodies. 117 | 118 | This DIP devises rules that allow passing objects by reference *down* into 119 | functions, and return references *up* from functions, whilst disallowing cases 120 | such as the above when a reference passed up ends up referring to a deallocated 121 | temporary. 122 | 123 | ### Adding `return` as a parameter attribute 124 | 125 | The main issue is typechecking functions that return a `ref` `T` and accept 126 | some of their parameters by `ref`. Those that attempt to return locals or parts 127 | thereof are already addressed directly, contingent to [Issue 128 | 13902](https://issues.dlang.org/show_bug.cgi?id=13902). The one case remaining 129 | is allowing a function returning `ref` `T` to return a (part of a) parameter 130 | passed by `ref`. 131 | 132 | The key is to distinguish legal from illegal cases. One simple but overly 133 | conservative option would be to simply disallow returning a `ref` parameter or 134 | part thereof. That makes `identity` impossible to implement, and as a 135 | consequence accessing elements of a container by reference becomes difficult or 136 | impossible to typecheck properly. Also, heap-allocated structures with 137 | deterministic destruction (e.g. reference counted) must insert member copies 138 | for all accesses. 139 | 140 | This proposal promotes adding `return` as an attribute that propagates the 141 | lifetime of a parameter to the return value of a function. With the proposed 142 | semantics, a function is disallowed to return a `ref` parameter or a part 143 | thereof UNLESS the parameter is also annotated with `return`. Under the 144 | proposed semantics `identity` will be spelled as follows: 145 | 146 | ``` D 147 | @safe ref int wrongIdentity(ref int x) { 148 | return x; // ERROR! Cannot return a ref, please use "return ref" 149 | } 150 | @safe ref int identity(return ref int x) { 151 | return x; // fine 152 | } 153 | ``` 154 | 155 | Just by seeing the signature `ref` `int` `identity(return` `ref` `int` `x)` the 156 | compiler assumes that the result of identity must have a shorter or equal 157 | lifetime than `x` and typechecks callers accordingly. Example (given the 158 | previous definition of `identity`): 159 | 160 | ``` D 161 | @safe ref int fun(return ref int x) { 162 | int a; 163 | return a; // ERROR per current language rules 164 | static int b; 165 | return b; // fine per current language rules 166 | return identity(a); // ERROR, this may escape the address of a local 167 | return x; // fine, propagate x's lifetime to output 168 | return identity(x); // fine, propagate x's lifetime through identity to the output 169 | return identity(identity(x)); // fine, propagate x's lifetime twice through identity to the output 170 | } 171 | 172 | @safe ref int gun(ref int input) { 173 | static int[42] data; 174 | return data[input]; // works, can always return static-lived data 175 | } 176 | 177 | @safe struct S { 178 | private int x; 179 | ref int get() return { return x; } // should work, see next section 180 | } 181 | ``` 182 | 183 | ### Interaction with `auto` `ref` 184 | 185 | Syntactically it is illegal to use `auto` `ref` and `return` `ref` on the same 186 | parameter. Deduction of the `return` attribute still applies as discussed 187 | below. 188 | 189 | ### Deduction 190 | 191 | Deduction of the `return` attribute will be effected under the same conditions 192 | as for `pure` (currently for generic and lambda functions). That means the 193 | generic `identity` function does not require the `return` attribute: 194 | 195 | ``` D 196 | auto ref T identity(auto ref T x) { 197 | return x; // correct, no need for return 198 | } 199 | ``` 200 | 201 | ### Types of Result vs. Parameters 202 | 203 | Consider: 204 | 205 | ``` D 206 | @safe ref int fun(return ref float x); 207 | ``` 208 | 209 | This function arguably cannot return a value scoped within the lifetime of its 210 | argument for the simple reason it's impossible to find an `int` somewhere in a 211 | `float` (apart from unsafe address manipulation). However, this DIP ignores 212 | types; if a parameter is `return` `ref`, it is always considered potentially 213 | escaped as a result. It is in fact possible that the author of `fun` wants to 214 | constrain its output's lifetime for unrelated reasons. 215 | 216 | Future versions of this DIP may relax this rule. 217 | 218 | ### Multiple Parameters 219 | 220 | If multiple `return` `ref` parameters are present, the result's lifetime is 221 | conservatively assumed to be enclosed in the lifetime of the shortest-lived of 222 | those arguments. 223 | 224 | ### Member Functions 225 | 226 | Member functions of `struct`s must qualify `this` with `return` if they want to 227 | return a result by `ref` that won't outlive `this`. Example: 228 | 229 | ``` D 230 | @safe struct S { 231 | static int a; 232 | int b; 233 | ref int fun() { return a; } // fine, callers assume infinite lifetime 234 | ref int gun() { return b; } // ERROR! Cannot return a direct member 235 | ref int hun() return { return b; } // fine, result is scoped within this 236 | } 237 | ``` 238 | 239 | ### `@safe` 240 | 241 | For the initial release, the requirement of returns for `ref` parameter data to 242 | be marked with `return` will only apply to `@safe` functions. The reasons for 243 | this are to avoid breaking existing code, and because it's not yet clear 244 | whether this feature will interfere with valid constructs in a system language. 245 | 246 | ``` D 247 | @safe ref int fun(ref int x) { return x;} // Error 248 | @safe ref int gun(return ref int x) { return x;} // OK 249 | @system ref int hun(ref int x) { return x;} // OK for now, @system code. 250 | @system ref int jun(return ref int x) { return x;} // preferred, gives more hints to compiler for lifetime of return value 251 | ``` 252 | 253 | ## Copyright & License 254 | 255 | Copyright (c) 2016 by the D Language Foundation 256 | 257 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 258 | -------------------------------------------------------------------------------- /DIPs/archive/DIP37.md: -------------------------------------------------------------------------------- 1 | # Importing Packages as if They Were Modules 2 | 3 | | Section | Value | 4 | |-----------------|------------------| 5 | | DIP: | 37 | 6 | | Status: | Implemented | 7 | | Author: | Jonathan M Davis | 8 | 9 | ## Abstract 10 | 11 | Provide a way to import a package. This is a variation on [DIP15](http://wiki.dlang.org/DIP15). 12 | 13 | ### Links 14 | 15 | * [Enhancement Request in Bugzilla](http://d.puremagic.com/issues/show_bug.cgi?id=10022) 16 | * [Pull Request with the necessary changes to the compiler](https://github.com/D-Programming-Language/dmd/pull/1961) 17 | * [Implement DIP37 Importing Packages as if They Were Modules](https://github.com/D-Programming-Language/dmd/pull/2139) 18 | 19 | ## Description 20 | 21 | If a package has a *package.d* file in it, then an import statement which 22 | imports the package will import that file. 23 | 24 | So, if there's a *foo/bar/package.d* and code imports *foo.bar*, then the 25 | compiler will import *foo.bar.package*, and all aspects of importing will 26 | function as they normally do except that instead of typing *foo.bar.package*, 27 | *foo.bar* is typed by itself. And by using the file *package.d*, we completely 28 | avoid the risk of breaking existing code as package is a keyword and therefore 29 | is normally illegal as a module name. 30 | 31 | If there is no *package.d* file in a package, then importing the package will 32 | be an error as it has been (though the error message will probably indicate 33 | something about *package.d*). Also, having a package and module with the same 34 | name will result in an ambiguity error when you try and import them (e.g. 35 | *foo/bar/package.d* and *foo/bar.d*). 36 | 37 | ### Rationale 38 | 39 | Currently, it's impossible to split up a module into a package in place without 40 | breaking code, and we'd like to be able to do that. There are also people who 41 | want the ability import packages as a whole (as evidenced by the `all.d` idiom 42 | which some people have been using). 43 | 44 | ### Examples 45 | 46 | This will allow us to do something like take std/datetime.d and split into 47 | something like 48 | 49 | ``` 50 | std/datetime/common.d 51 | std/datetime/interval.d 52 | std/datetime/package.d 53 | std/datetime/timepoint.d 54 | std/datetime/timezone.d 55 | ``` 56 | 57 | and `std/datetime/package.d` could then look something like 58 | 59 | ``` D 60 | /++ Package documentation here +/ 61 | module std.datetime;` 62 | 63 | public import std.datetime.common; 64 | public import std.datetime.interval; 65 | public import std.datetime.timepoint; 66 | public import std.datetime.timezone; 67 | ``` 68 | 69 | Code which imports `std.datetime` would then be unaffected by the change, and 70 | new code could choose either to import `std.datetime` or to directly import the 71 | new sub-modules. 72 | 73 | This is identical to what some projects have been doing with `all.d`, where 74 | they have a `foo/bar/all.d` which publicly imports all of the `bar` package, 75 | except that this provides additional syntactic sugar for it. 76 | 77 | Another benefit is that this then gives us a way to document an entire package. 78 | By putting a ddoc comment on the module declaration at the top of the package.d 79 | file, a ddoc page for the package as a whole can be created. 80 | 81 | Also, because `package.d` simply takes advantage of what the module and import 82 | system can already do (the only major new thing being that importing the 83 | package would then import its `package.d` file instead of getting an error), 84 | this change is incredibly straightforward and allows us to have full control 85 | over what gets imported when importing the package (e.g. only publicly 86 | importing modules which are intended to be part of its public API and not 87 | importing modules which are intended for internal use). 88 | 89 | ## Copyright & License 90 | 91 | Copyright (c) 2016 by the D Language Foundation 92 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 93 | -------------------------------------------------------------------------------- /DIPs/archive/DIP42.md: -------------------------------------------------------------------------------- 1 | # Add enum E(T) = expression; eponymous template support 2 | 3 | | Section | Value | 4 | |-----------------|-----------------------------------------------------------| 5 | | DIP: | 42 | 6 | | Status: | Implemented | 7 | | Author: | Walter Bright | 8 | | Implementation: | | 9 | 10 | ## Abstract 11 | 12 | Short-hand syntax for templates that evaluate to single `enum`. 13 | 14 | ## Description 15 | 16 | This pattern has become quite common in D: 17 | 18 | ``` D 19 | template isIntegral(T) 20 | { 21 | enum isIntegral = is(T : long) || is(T : ulong) || ...; 22 | } 23 | ``` 24 | 25 | Analogously to struct S(T), the enum manifest constant could be written as: 26 | 27 | ``` D 28 | enum isIntegral(T) = is(T : long) || is(T : ulong) || ...; 29 | ``` 30 | 31 | This is a natural fit for D. It does not break any existing code, and is simple 32 | to implement - it's just a rewrite in the parser. 33 | 34 | ### Rationale 35 | 36 | The pattern is common, and a bit awkward. It's worth supporting the new syntactic sugar. 37 | 38 | ## Copyright & License 39 | 40 | Copyright (c) 2016 by the D Language Foundation 41 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 42 | -------------------------------------------------------------------------------- /DIPs/archive/DIP56.md: -------------------------------------------------------------------------------- 1 | # Provide pragma to control function inlining 2 | 3 | | Section | Value | 4 | |-----------------|-------------------------| 5 | | DIP: | 56 | 6 | | Status: | Implemented | 7 | | Author: | Walter Bright | 8 | | Implementation: | | 9 | 10 | ## Abstract 11 | 12 | This proposal uses pragmas to add inlining instructions to the compiler. 13 | 14 | ## Description 15 | 16 | This adds a pragma 'inline', which is followed by an optional boolean 17 | expression, which influences the inlining of the function it appears in. An 18 | evaluation of 'true' means always inline, 'false' means never inline, and no 19 | argument means the default behavior, as indicated in the command line. 20 | 21 | If this pragma is outside of a function, it affects the functions in the block 22 | it encloses. 23 | 24 | Nested pragmas override the outer ones. 25 | 26 | If there are multiple pragmas inside a function, the lexically last one that is 27 | semantically analyzed controls the behavior. 28 | 29 | If the pragma is versioned out or in a false static if conditional, it is 30 | ignored. 31 | 32 | If a pragma specifies always inline, and the compiler cannot inline it, a 33 | warning will be generated. Implementations will likely vary in their ability to 34 | inline. 35 | 36 | These are not attributes because they should not affect the semantics of the 37 | function. In particular, the function signature must not be affected. 38 | 39 | ### Rationale 40 | 41 | Sometimes generating better code requires runtime profile information. But 42 | being a static compiler, not a JIT, the compiler could use such hints from the 43 | programmer. 44 | 45 | ### Semantics 46 | 47 | With the `-inline` compiler flag: 48 | 49 | `pragma(inline, true)` always inlines 50 | 51 | `pragma(inline, false)` never inlines 52 | 53 | `pragma(inline)` inlines at compiler's discretion 54 | 55 | Without the `-inline` compiler flag: 56 | 57 | `pragma(inline, true)`    always inlines 58 | 59 | `pragma(inline, false)`   never inlines 60 | 61 | `pragma(inline)`          never inlines 62 | 63 | ## Copyright & License 64 | 65 | Copyright (c) 2016 by the D Language Foundation 66 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 67 | -------------------------------------------------------------------------------- /DIPs/archive/DIP60.md: -------------------------------------------------------------------------------- 1 | # Add @nogc Function Attribute 2 | 3 | | Section | Value | 4 | |-----------------|------------------------| 5 | | DIP: | 60 | 6 | | Version: | 1.2 | 7 | | Status: | Implemented | 8 | | Author: | Walter Bright | 9 | | Implementation: | | 10 | | | | 11 | 12 | ## Abstract 13 | 14 | The @nogc function attribute will mark a function as not making any allocations using the GC. 15 | 16 | ### Links 17 | 18 | * [forum discussion](http://forum.dlang.org/post/lijoli$2jma$1@digitalmars.com) 19 | 20 | ## Description 21 | 22 | @nogc goes in the same way that the nothrow attribute does, and is quite 23 | similar in behavior. It affects inheritance in that it is covariant. The name 24 | mangling for it will be "Ni". @nogc will be inferred for template functions in 25 | the same manner as nothrow is. @nogc will be transitive, in that all functions 26 | called by an @nogc function must also be @nogc. GC allocations in a @nogc 27 | function will be disallowed, and that means calls to operator new, closures 28 | that allocate on the GC, array concatenation, array appends, and some array 29 | literals. 30 | 31 | No functions in the GC implementation will be marked @nogc. 32 | 33 | ### Rationale 34 | 35 | Many users want to be able to guarantee that code will not allocate using the GC. 36 | 37 | ### Examples 38 | 39 | ``` D 40 | @nogc int func(int a) { ... } 41 | ``` 42 | 43 | #### Static allocations should be ignored 44 | 45 | This code (and its mutable \_\_gshared variants) should work since the beginning: 46 | 47 | ``` D 48 | void foo() @nogc nothrow { 49 | static const err = new Error("error"); 50 | throw err; 51 | } 52 | ``` 53 | 54 | The situation is similar to this code, that is allowed (text is not nothrow, 55 | but here it's called at compile-time): 56 | 57 | ``` D 58 | void foo() nothrow 59 | { 60 | import std.conv; 61 | enum msg = text(10); 62 | } 63 | ``` 64 | 65 | #### Behaviour in presence of optimizations 66 | 67 | Using Escape Analysis the LDC2 compiler is able to remove the heap allocation 68 | from this main function when full optimizations are used. However, validity of 69 | code should not be affected by optimization settings. (Nor can it be, without 70 | intertwining the compiler front-end with each back-end in rather complicated 71 | ways.) Hence the following main function cannot be annotated with @nogc even 72 | when Escape Analysis removes the heap allocation: 73 | 74 | ``` D 75 | __gshared int x = 5; 76 | int main() 77 | { 78 | int[] a = [x, x + 10, x * x]; 79 | return a[0] + a[1] + a[2]; 80 | } 81 | ``` 82 | 83 | In a successive development phase of @nogc we can perhaps relax some of its 84 | strictness introducing some standard (required by all conformant D compilers 85 | and performed at all optimization levels) common cases of escape analysis, that 86 | allow to use @nogc annotations in more cases, perhaps also like the one above. 87 | One possible disadvantage of this idea is that such escape analysis could slow 88 | down a little all D compilations, even the fastest debug builds. 89 | 90 | ## Copyright & License 91 | 92 | Copyright (c) 2016 by the D Language Foundation 93 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 94 | -------------------------------------------------------------------------------- /DIPs/archive/DIP61.md: -------------------------------------------------------------------------------- 1 | # Add namespace scopes to support referencing external C++ symbols in C++ namespaces 2 | 3 | | Section | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 61 | 6 | | Status: | Implemented | 7 | | Author: | Walter Bright | 8 | | Implementation: | | 9 | 10 | ## Abstract 11 | 12 | Add ability to reference from D C++ symbols that are in C++ namespaces. 13 | 14 | ### Links 15 | 16 | * [NG discussion that triggered the DIP](http://forum.dlang.org/post/lhi1lt$269h$1@digitalmars.com) 17 | * [NG announcement and discussion](http://forum.dlang.org/post/ljfue4$11dk$1@digitalmars.com) 18 | * [more NG discussion](http://forum.dlang.org/post/ljjnaa$187r$1@digitalmars.com) 19 | 20 | ## Description 21 | 22 | A namespace scope creates a scope with a name, and inside that scope all 23 | declarations become part of the namespace scope. This involves the addition of 24 | a small amount of new grammar. Compiler changes are expected to be minor. The 25 | change is additive and should not impact any existing code. 26 | 27 | The namespace is identified by an identifier following the C++ in extern(C++). 28 | Nested namespaces can be specified using . to separate them. 29 | 30 | ### Rationale 31 | 32 | Best practices in C++ code increasingly means putting functions and 33 | declarations in namespaces. Currently, there is no support in D to call C++ 34 | functions in namespaces. The primary issue is that the name mangling doesn't 35 | match. Need a simple and straightforward method of indicating namespaces. 36 | 37 | ### Examples 38 | 39 | ``` d 40 | extern (C++, MyNamespace) { int foo(); } 41 | ``` 42 | 43 | creates a namespace named "MyNamespace". As is currently the case, 44 | 45 | ``` d 46 | extern (C++) { int foo(); } 47 | ``` 48 | 49 | does not create a namespace. 50 | 51 | The following declarations are all equivalent: 52 | 53 | ``` d 54 | extern (C++) { extern (C++, N) { extern (C++, M) { int foo(); }}} 55 | extern (C++, N.M) { int foo(); } 56 | extern (C++, N) { extern (C++) { extern (C++, M) { int foo(); }}} 57 | ``` 58 | 59 | Namespaces can be nested. Declarations in the namespace can be accessed without 60 | qualification in the enclosing scope if there is no ambiguity. Ambiguity issues 61 | can be resolved by adding the namespace qualifier: 62 | 63 | ``` d 64 | extern (C++, N) { int foo(); int bar(); } 65 | extern (C++, M) { long foo(); } 66 | 67 | bar(); // ok 68 | foo(); // error, ambiguous 69 | N.foo(); // ok 70 | N.bar(); // ok 71 | ``` 72 | 73 | Name lookup rules are the same as for mixin templates. 74 | 75 | Unlike C++, namespaces in D will be 'closed' meaning that new declarations 76 | cannot be inserted into a namespace after the closing }. C++ Argument Dependent 77 | Lookup (aka "Koenig Lookup") will not be supported. 78 | 79 | ### Grammar Change 80 | 81 |
82 | LinkageAttribute:
83 |     extern ( identifier )
84 |     extern ( identifier++ )
85 |     extern ( identifier++ , identifier ( . identifier )* )
86 | 
87 | 88 | ## Copyright & License 89 | 90 | Copyright (c) 2016 by the D Language Foundation 91 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 92 | -------------------------------------------------------------------------------- /DIPs/archive/DIP75.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | | Section | Value | 4 | |----------------|------------------------------------| 5 | | DIP: | 75 | 6 | | Status: | Implemented | 7 | | Author: | David Soria Parra and Martin Nowak | 8 | 9 | ## Abstract 10 | 11 | The current release process of DMD, Druntime and Phobos (from now on referred to as "release package"), is done on a "done when it's done" basis. This DIP proposes a time-based release schedule. This allows: 12 | 13 | - reduced times to get bugfixes out 14 | - a clear way of managing backwards compatibility 15 | - a more predictable release schedule for packagers 16 | - cleaner responsibilities 17 | - assurance to developers regarding timeliness of release of their contributions 18 | - synchronization with releases processes of major distributions 19 | 20 | In addition the DIP proposes the idea of **Release Managers**, who are responsible for a timely release. 21 | 22 | ## Release Process 23 | 24 | We propose to introduce **bugfix versions** and **feature versions**. A **feature version** may contain new features, language changes, and deprecations. For every release version the minor part of the version is incremented: 2.066, 2.067, ... A **bugfix version** is based on a feature version and contains only bugfixes and neither new features, nor deprecations of other features or library changes. Bugfix versions are for example: 2.066.1, 2.066.2, etc. There is only one supported version at a time, but release managers are free to release additional bugfix versions when needed. 25 | 26 | ### Schedule 27 | 28 | A bugfix version is released *every month*. A feature version is released every 2 months. Releases should happen on the first Saturday of the month. Two weeks before a feature release *stable* is branched off *master*. No new features are integrated into *stable*. 29 | 30 | Example schedule: 31 | 32 | - Dec 14th: Branch cut (master becomes stable) 33 | - Jan 1st: 2.069 34 | - Feb 1st: 2.069.1 35 | - Feb 14th: Branch cut (master becomes stable) 36 | - Mar 1st: 2.070 37 | - Apr 1st: 2.070.1 38 | 39 | ### Support and Packages 40 | 41 | Only the most recent version is supported. Distributions are free to backport what is needed. In addition Release Managers can decided to release additional fix versions if needed. The release manager offer the source code of the release as a tarball (\*.tar.gz, \*.tar.xz) as well as a Windows version. All other formats are left to packagers and should be preferable automized. 42 | 43 | ### Branching strategy 44 | 45 | **TL;DR** Safe fixes should **always** go into stable, all the time. 46 | 47 | ------------------------------------------------------------------------ 48 | 49 | There are two branches: master and stable. Two weeks before a feature release the master branch becomes stable. All subsequent *bugfix* versions are tagged off the stable branch. New features go to master, which will become the next major version. Stable is regularly merged back into master to ensure that bugfixes make it into master. 50 | 51 | Branching Figure: 52 | 53 | ``` 54 | ----- master --o--------o------------------------ 55 | \ / / \ 56 | stable --------------------------------- stable 57 | \ \ 58 | TAG 2.069 TAG 2.069.1 59 | ``` 60 | 61 | When compared to cherry-picking fixes from master, this allows us to properly track which releases contain a particular fix. It also causes less merge conflicts b/c no duplicated commits must be merged and reduces the work to identify commits on master that need to be cherry-picked. The downside is that github doesn't allow to change the target branch of a PR. So if a PR inadvertently targets master, it will have to be rebased onto stable and a new PR must be opened. 62 | 63 | ### Security Management 64 | 65 | Release managers should keep track of security related bugs. They are responsible for following a *responsible disclosure policy* for D. This means, set an expected fix date and communicate the date with the original vulnerability reporter. Contact packages to get ready to publish packages at the given date and obtain an CVE if necessary. Upon release date they notify the packagers and write an announcement explaining the vulnerability and include the reporter if desired. That way we ensure a smooth handling of security problems in line with standard community processes. 66 | 67 | ## Release manager 68 | 69 | There are always two or more release managers. This allows the releases being independent from a single point of failure (vacation, personal matters, etc), and allows a smooth ramp-up for release managers. Release managers are responsible for releasing the *release package* on time. They ensure that bugfix releases do not contain any backwards compatibilities and maintain the changelog. Release managers are free to remove features or fixes when necessary. Release managers are able to merge features and bugfixes on github. They are to provide a GPG signed tarball and a feature. Release managers are appointed by Walter and Andrei. 70 | 71 | ## Copyright 72 | 73 | Copyright (c) 2016 by the D Language Foundation 74 | 75 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 76 | -------------------------------------------------------------------------------- /DIPs/archive/README.md: -------------------------------------------------------------------------------- 1 | | ID| Title| Status| 2 | |----------------|----------------------------------------------------------------------------------|-----------| 3 | |[20](./DIP20.md)| Volatile read/write intrinsics|Implemented| 4 | |[22](./DIP22.md)| Private symbol (in)visibility|Implemented| 5 | |[25](./DIP25.md)| Sealed references|Implemented| 6 | |[37](./DIP37.md)| Importing Packages as if They Were Modules|Implemented| 7 | |[42](./DIP42.md)| Add enum E(T) = expression; eponymous template support|Implemented| 8 | |[43](./DIP43.md)| D/Objective-C| Approved| 9 | |[45](./DIP45.md)| making export an attribute| Draft| 10 | |[56](./DIP56.md)| Provide pragma to control function inlining|Implemented| 11 | |[60](./DIP60.md)| Add @nogc Function Attribute|Implemented| 12 | |[61](./DIP61.md)|Add namespace scopes to support referencing external C++ symbols in C++ namespaces|Implemented| 13 | |[75](./DIP75.md)| Release Process|Implemented| 14 | -------------------------------------------------------------------------------- /DIPs/other/DIP1005-countlines.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/zsh 2 | 3 | # Exit on first error 4 | set -e 5 | 6 | if [ -z $D ]; then 7 | echo "Please specify the D stdlib install path in $D" 8 | return 1 9 | fi 10 | 11 | rm -f /tmp/test.log 12 | 13 | # Process all std files 14 | echo "|File|Imports (unittest)|Imports (compile)|Imports (top)" 15 | echo "|---|---|---|---|" 16 | ( 17 | cd $D 18 | for f in std/*.d std/{algorithm,container,digest,experimental,net,range,regex}/**/*.d; do 19 | echo "import $f;" | sed -e 's|/|.|g' -e 's/\.d;/;/' -e 's/\.package//' >/tmp/test.d 20 | echo -n "|$f" 21 | LINES1=$(dmd -o- -c -v -unittest $f 2>>/tmp/test.log | \ 22 | grep '^import *std\.' | wc -l) 23 | LINES2=$(dmd -o- -c -v $f 2>>/tmp/test.log | \ 24 | grep '^import *std\.' | wc -l) 25 | LINES3=$(dmd -o- -c -v /tmp/test.d 2>>/tmp/test.log | \ 26 | grep '^import *std\.' | wc -l) 27 | # Subtract 1 from LINES3 to discount the imported file itself 28 | echo "|$LINES1|$LINES2|$[LINES3-1]|" 29 | done | sort -t'|' --key=3 -nr 30 | ) 31 | -------------------------------------------------------------------------------- /DIPs/other/DIP1005-time.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/zsh 2 | 3 | # Exit on first error 4 | set -e 5 | 6 | if [ -z $D ]; then 7 | echo "Please specify the D stdlib install path in $D" 8 | return 1 9 | fi 10 | 11 | rm -f /tmp/test.log 12 | 13 | T=/tmp/dmd2 14 | DC="$T/linux/bin64/dmd -I$T/src/druntime/import -I$T/src/phobos -L-L$T/linux/lib64" 15 | DC="dmd" 16 | 17 | MODULES=( $(cd $D && echo std/*.d std/regex/package.d std/{algorithm,container,digest,experimental,net,range}/**/*.d ) ) 18 | 19 | function measure() 20 | { 21 | F=$1 22 | rm -f $F 23 | for f in $MODULES; do 24 | echo "import $f;" | sed -e 's|/|.|g' -e 's/\.d;/;/' -e 's/\.package//' >/tmp/test.d 25 | rm -f test.o 26 | NOW=$(date +%s%3N) 27 | eval $DC -c /tmp/test.d 2>>/tmp/test.log 28 | ELAPSED=$[ $(date +%s%3N) - $NOW ] 29 | echo "$ELAPSED|$(wc -c >$F 30 | done 31 | } 32 | 33 | # Process all std files 34 | ( 35 | cd $D 36 | git checkout temp || true 37 | measure /tmp/times_many_top_imports 38 | git checkout master || true 39 | measure /tmp/times_few_top_imports 40 | ) 41 | 42 | rm -f /tmp/modules 43 | for f in $MODULES; do 44 | echo "|$f" >>/tmp/modules 45 | done 46 | 47 | paste -d'|' /tmp/modules /tmp/times_many_top_imports /tmp/times_few_top_imports 48 | -------------------------------------------------------------------------------- /DIPs/other/DIP1006.md: -------------------------------------------------------------------------------- 1 | # Providing more selective control over contracts 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | DIP1006 | 6 | | Review Count: | 2 [Most Recent] | 7 | | Author: | Mathias Lang - mathias.lang@sociomantic.com | 8 | | Implementation: | None | 9 | | Status: | Superseded | 10 | 11 | [Most Recent]: https://github.com/dlang/DIPs/blob/ef031a229629f6995e4d1b885451113b10bfecf7/DIPs/DIP1006.md 12 | 13 | ## Abstract 14 | 15 | A proposal to expose a way to selectively disable some of D's contract features 16 | (invariant, `in` / `out` and `assert`). 17 | 18 | 19 | ### Links 20 | 21 | Limited D1 implementation, used by Sociomantic: https://github.com/dlang/dmd/pull/6347 22 | 23 | 24 | ## Description 25 | 26 | Add a command-line switch, named `-contracts` in this proposal, which takes 4 possible values: 27 | 28 | - `all`: the default, present for completeness and scripts, so one can just append it to a generated command line to enable all contract checks. 29 | - `noinvariant`: Disable implicit `invariant` calls, but leave in function `in` / `out` contracts and `assert`. 30 | - `assert`: Disable `invariant` blocks and `in` / `out` contracts, but leave `assert` in. 31 | - `none`: Disable all `invariant`, `in` and `out` contracts, and `assert`. 32 | 33 | Note that the `noinvariant` value only disables implicit calls to `invariant`. Explicit calls can only be disabled by disabling `assert`. 34 | 35 | 36 | ### Rationale 37 | 38 | #### Prelude on contracts 39 | 40 | Under the broad name "Contracts", we regroup four D features: `assert`, `in` contracts, `out` contracts and `invariant`. 41 | Contracts in D are a means to do sanity checking. A contract that fails is a sign of faulty logic in the code. 42 | Since contracts should never fail, the currently advertised approach for D programmers is to use them during development, 43 | then deploy a `-release` build of the application for maximum performance. 44 | 45 | Contracts naturally fit in a hierarchy, where `assert` is the most basic block (being used by others), 46 | and `invariant` is meant for expensive sanity checking. `in` and `out` contracts are located in between. 47 | 48 | #### Cost of contracts 49 | 50 | `assert` and `in` / `out` contracts follow a pay-for-what-you-use approach: an `assert` which is never executed is free, 51 | and a `in` or `out` contract on a function that is never called is also free of runtime overhead. 52 | 53 | `invariant`s stand out in that regard: they can be used on a pay-for-what-you-use basis, by using `assert(object)` (or `assert(this)`), 54 | but they are also implicitly called twice on every `public` and `protected` class method call. 55 | The call itself is not direct: the compiler inserts a call to `_d_invariant`, [which can be found in druntime](https://github.com/dlang/druntime/blob/v2.072.0/src/rt/invariant.d). 56 | The code, being very simple, results in the class hierarchy being traversed completely twice (no caching is done) 57 | for every call, even for classes which do not define any invariant. 58 | 59 | Profiling some real-time applications within Sociomantic showed that `_d_invariant` was the most expensive call in the application. 60 | Affected applications were using few or no invariants, but since Sociomantic code is mostly written in an OOP style, 61 | simply disabling invariants (with no other optimization) led to 20% more throughput. 62 | 63 | #### Issues with the current approach 64 | 65 | Testing can be complete and it is not rare to miss a scenario that can show up any time in a production setting. 66 | In such a case, having a contract not failing where it should can lead to higher costs than the one induced by a crash of the application. 67 | Examples of such a case include critical data corruption and unexpected monetary spending. 68 | 69 | For this reason, developers are often wary of disabling such safety features, even in production, as long as the performance cost is acceptable. 70 | What can be viewed as an acceptable performance cost is up to the end user and the code base. 71 | Any OOP-intensive code will want to get rid of `invariant` as a first step, while more function-oriented code might be more interested in disabling `in` / `out`. 72 | 73 | #### Relationship with `-release` and `-debug` 74 | 75 | In DMD, `-debug` just mean enabling `debug` blocks, so there is no overlap with `-contracts`'s proposed functionality. 76 | On the other hand, `-release` disables all aforementioned contracts, and, in addition, disables "switch errors" 77 | (compiler-generated `default` case in a switch statement are turned into HLT instruction instead of throwing a `SwitchError`). 78 | As a result, using `-contracts` with `-release` is equivalent to just using `-release`. 79 | 80 | #### Considered alternatives 81 | 82 | The 4 values available to the user are voluntarily simple and hierarchical. It makes little sense to allow any contracts without enabling asserts. 83 | It would be feasible to allow `invariant` without `in` and `out` contracts, or only `out` contracts, only `in` contracts, or some other combination. 84 | Since providing all combinations would increase complexity, but doesn't yet provide an obvious advantage, it was left out of this proposal (but can be subject to another one). 85 | 86 | While a higher granularity is not recommended by the DIP author, it was one of the most discussed points on the review thread, 87 | with several people expression an interest in the feature. 88 | 89 | Since this proposal was heavily motivated by the cost of invariants, an obvious alternative is to reduce said cost. 90 | However, the cost of having `invariant` enabled will never be null for builds that do not use invariants at all, which is the real motivation for this feature. 91 | 92 | Finally, this functionality is already implemented in LDC via `-enable-invariants={0,1}`. 93 | Standardizing it would simplify users' lives and allow tooling that deals with multiple compilers (e.g. `dub`, IDEs...) to provide this option. 94 | 95 | ### Breaking changes / deprecation process 96 | 97 | Since this behavior is entirely opt-in, no breakage is expected. 98 | 99 | ### Implementation difficulty 100 | 101 | The reference front-end already segments the affected features into separate flags, hence the implementation should be trivial. 102 | 103 | ## Copyright & License 104 | 105 | Copyright (c) 2016 by the D Language Foundation 106 | 107 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 108 | 109 | ## Review 110 | 111 | _This DIP was submitted and the review process initiated prior to the procedural changes implemented [in the PROCEDURE document](https://github.com/dlang/DIPs/commits/master/PROCEDURE.md) on March 5, 2018. The only round of Preliminary Review (known as Community Review under the revised procedure) began on April 12, 2017. The Formal Review, which consisted of a community review followed by the Language Maintainers' review (subsequently divided into two review rounds under the revised procedure: Final Review and Formal Assessment) began on September 15, 2017. The previous procedure called for a summary only for the latter half of the Formal Review round to provide a record of the Language Maintainers' decision._ 112 | 113 | [Preliminary Review Round 1](http://forum.dlang.org/post/rsafosvkhxddkxptaziy@forum.dlang.org). 114 | 115 | ### Formal Review 116 | [Reviewed Version](https://github.com/dlang/DIPs/blob/ef031a229629f6995e4d1b885451113b10bfecf7/DIPs/DIP1006.md) 117 | 118 | [Discussion](https://forum.dlang.org/post/rolxkrmfpvygivyumuec@forum.dlang.org) 119 | 120 | The Language Maintainers agreed with the intent of the proposal, but disagreed with the proposed implementation. They felt the proposed compiler switch, `-contracts`, was too narrow and would be better implemented as a switch that could be applied more broadly to enable and disable more language features. Revisions to the DIP were requested to reflect such an implementation. Before the revision was completed, the proposal was superseded by the `-check` compiler switch [released in DMD 2.084.0](https://dlang.org/changelog/2.084.0.html#check-switch). 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /DIPs/other/DIP1008.md: -------------------------------------------------------------------------------- 1 | # Exceptions and @nogc 2 | 3 | | Field | Value | 4 | |-----------------|-------------------------------------------------------------| 5 | | DIP: | 1008 | 6 | | Review Count: | 1 [Most Recent] | 7 | | Author: | Walter Bright - walter@digitalmars.com | 8 | | Implementation: | [PR 6681] | 9 | | Status: | Postponed | 10 | 11 | [Most Recent]: https://github.com/dlang/DIPs/blob/7e24193032ef22c26696f23e68cf82432d9de9b0/DIPs/DIP1008.md 12 | [PR 6681]: https://github.com/dlang/dmd/pull/6681 13 | 14 | ## Abstract 15 | 16 | A proposal for allowing exceptions to be allocated and thrown in `@nogc` code just as they are, otherwise via automated refcounting. 17 | 18 | ### Links 19 | 20 | Previous discussions can be found in the following threads in the General forum: 21 | 22 | [Exceptions in @nogc code](http://forum.dlang.org/thread/oboaa2$17oa$1@digitalmars.com?page=1) 23 | 24 | [Proposal 2: Exceptions and @nogc](http://forum.dlang.org/thread/occ9kk$24va$1@digitalmars.com?page=1) 25 | 26 | ## Description 27 | 28 | Make `Throwable` optionally refcounted. Add a field `_refcount` which 29 | is `!=0` when it is a refcounted instance. The number of parents of 30 | a refcounted `Throwable` is `_refcount+1`. This member is private and only accessible via the `@system` member function `refcount()`, to prevent its use in `@safe` code. 31 | 32 | The only place a refcounted `Throwable` is ever created is when the following statement is in the user code: 33 | 34 | throw new E(string); 35 | 36 | where E is `Throwable` or derived from `Throwable`. Instead of calling the usual `_d_newclass()` to allocate `E` on the GC heap, it will call the new function `_d_newThrowable()` which will allocate `E` and intialize it for refcounting. 37 | 38 | When the exception is thrown, either `_d_throwc()` or `_d_throwdwarf()` gets called, which is where druntime takes over. The refcount is incremented in these functions, usually from 1 to 2. 39 | 40 | The thrown object will then wind up either in a catch statement, or in the `next` linked list of thrown exceptions in flight. 41 | 42 | A catch variable `e` as in: 43 | 44 | catch (E e) 45 | { 46 | ... 47 | } 48 | 49 | becomes a RAII object, meaning that it is destroyed at the closing `}`. Such destruction is done by calling: 50 | 51 | _d_delThrowable(e); 52 | 53 | which will test `e._refcount` to see if it is a refcounted object. If not, it does nothing. If it is, the refcount is decremented, and if it hits one then `e`'s destructor is called, followed by freeing the memory used by `e`. 54 | 55 | In catch blocks, `e` is regarded as `scope` so that it cannot escape the 56 | catch block. As a special case, if `e` is thrown in the catch block as: 57 | 58 | throw e; 59 | 60 | then `e` can escape. This works because, as mentioned before, `_d_throwc()` or `_d_throwdwarf()` will increment the reference count. 61 | 62 | The destructor for `Throwable` will, if the refcount is 1, call `_d_delThrowable(e.next)`, i.e. on the head of the chained list of exceptions. This means that the chained list can be a mixed collection of refcounted and non-refcounted Throwables, although the refcounted ones can only be freed when their antecedent gets reaped by whatever means. 63 | 64 | The chained list must be `protected` so it cannot be altered or escaped by user code. 65 | 66 | ### Rationale 67 | 68 | Exceptions are assumed to be GC-collected by the EH design, in that no 69 | attempt is made to control copies or lifetimes. This dependency is not 70 | a performance issue, as exceptions are presumed to be slow. 71 | 72 | The issue is it impairs use of `@nogc` on any code that throws exceptions, and prevents building D programs that do not link in the GC runtime. 73 | 74 | To fix this, the allocation and destruction of the exception objects 75 | must be completely controlled. The result of this should be no leaking memory, no need to link in the GC, and memory safety. GC, stack, and refcounted exception objects can coexist in the same 76 | program. 77 | 78 | ### Breaking changes 79 | 80 | This will break an unknown amount of existing code. 81 | 82 | Breakage will come in the form of: 83 | 84 | 1. Leaking `Exception` objects from catch clauses (caught by 85 | the compiler) 86 | 87 | 2. Disallowing `Exception` objects with postblit fields. 88 | 89 | 3. Catch objects being `scope` will cause problems in that 90 | everything done with those objects will also have to be `scope`. 91 | The most likely problem will be printing the objects, which 92 | relies on `Object.toString()`, which is not `scope`. One possible 93 | solution is to force `Throwable.toString()` to be `scope`, which 94 | will likely cause minimal disruption. Of course, compiling 95 | with **-dip1000** will disable such checking and can work in 96 | the interim. Code that needs to leak the thrown exception object 97 | can clone the object. 98 | 99 | ## Copyright & License 100 | 101 | Copyright (c) 2016 by the D Language Foundation 102 | 103 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 104 | 105 | ## Review 106 | 107 | [Preliminary Review Round 1](http://forum.dlang.org/thread/blvfxcbfzoyxowsfzlhn@forum.dlang.org) 108 | 109 | ## Addendum 110 | This DIP was postponed at the request of the author. -------------------------------------------------------------------------------- /DIPs/other/DIP1012.md: -------------------------------------------------------------------------------- 1 | # Function Attributes 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1012 | 6 | | Review Count: | 1 [Most Recent] | 7 | | Author: | Nicholas Wilson | 8 | | Implementation: | [Druntime](https://github.com/dlang/druntime/pull/1881) (preliminary) | 9 | | Status: | Abandoned | 10 | 11 | [Most Recent]: https://github.com/dlang/DIPs/blob/95dd8313ba549b4bedf73a7b1dde62890d43da68/DIPs/DIP1012.md 12 | 13 | 14 | ## Abstract 15 | 16 | Addresses the desire for different sets of default attributes and rectifies the non-invertibilty 17 | of the built-in attributes by having a "last applied wins rule". Makes keyword-like attributes regular attributes. 18 | 19 | ### Links 20 | 21 | [Forum discussion](https://forum.dlang.org/thread/wnddmlmfinqqfccdlhqc@forum.dlang.org) 22 | 23 | ## Terminology 24 | 25 | Groups of attributes that are mutually exclusive (such as `@safe`, `@system`, `@trusted`), together with binary attributes 26 | (e.g. `pure`, `nothrow`) and their (currently non-existant) logical negations, are called _attribute categories_. 27 | 28 | Attributes from `core.attribute` are called core attributes. 29 | 30 | ## Rationale 31 | 32 | Many users feel that the default attributes have the wrong default behavior and, given that attributes are not invertable (the negations do not have names), putting 33 | ``` 34 | pure: nothrow: @nogc: @safe: 35 | ``` 36 | at the top of a file means that one can never "undo" those attributes (except `@safe`/`@system`/`@trusted`). 37 | This DIP proposes a solution to change the values of the attributes by making them regular attributes enabling selected enforcement at varying levels of granularity: 38 | * module scope / remainder of scope (`@attribute:`), 39 | * declaration block (`@attribute { ... }`) and 40 | * symbol (`@attribute void foo() { ... }`) 41 | 42 | Regular UDAs are manipulated via `AliasSeq`s, but the compiler recognised attributes are not regular attributes and so they can't be. 43 | This leads to a difference between manipulating the different types of attributes and the need for a host of explicit `__traits` to deal with the compiler attibutes. 44 | 45 | Additionally making the compiler recognised attributes regular attributes has a number of advantages: 46 | * manipulation of lists of attributes becomes simpler as traditional methods of `AliasSeq` manipulation can be used 47 | * decouples (from a metaprogramming prespective) the definition of the attributes from their usage eg. to allow listing required core attributes for a method in meta-type definition. 48 | * new ones can be "phased in" by using `@future` without fear of breaking code. Also having the infrastructure in place will make development of new attributes faster. 49 | * it is hoped that this will lower the aversion to adding new attributes 50 | 51 | ## Description 52 | 53 | Move all (DMD) compiler-recognized function attributes into `core.attribute`, making them symbols in their own right. They shall be organized by attribute category into `enum`s, each with the following members: 54 | * the attribute's default value e.g. `@system` or impure 55 | * the default value's logical negation e.g `@safe` or pure 56 | * any remaining attributes, e.g. `@trusted` 57 | 58 | each with distict values. This decouples the use from the definition enabling traditional methods of attribute manipulation (`AliasSeq`s) 59 | and introspection to be used with core attributes. As all the attributes are now symbols, we can group them in an `AliasSeq`-like fashion 60 | to apply them en masse, as is done in LDC for [`@fastmath`](https://github.com/ldc-developers/druntime/blob/ldc/src/ldc/attributes.d#L58) 61 | 62 | Two new `__tratis`, `getFunctionAttributes` for retrieving the list of UDA symbols corresponding to the attribute categories in this DIP, 63 | and `forceFunctionAttributes` forcing the application without error of a particular attribute (a blunt "I know what I'm doing tool"). 64 | 65 | If multiple attributes from a single category are present, the attribute applied at the innermost scope and lexically last is applied and 66 | all others are removed from the symbols list of UDAs. This is the "last applied wins rule". 67 | 68 | ### Attributes & attribute-like compiler behaviour encompassed in this DIP 69 | 70 | Encompassed: 71 | 72 | * pure 73 | * @nothrow 74 | * @nogc 75 | * @safe/@system/@trusted 76 | 77 | Optionally encompassed: 78 | 79 | * `final`/virtual 80 | * Type\_Info / Module Info generation (other components of -betterC?) 81 | * function parameter attributes (`scope`/`return scope`) 82 | 83 | Not encompassed: 84 | 85 | * `@disable` 86 | * `@property` 87 | * linkage attributes (`extern(foo)`) 88 | * storage class attributes (`const`/`immutable`) 89 | * visibility attributes (`private`/`public`/`export`) 90 | * `align` 91 | * `deprecated` 92 | * `pramga` (e.g. `pragma(inline, true);`) 93 | * `synchronized` 94 | 95 | as they 96 | * do not pertain to functions, 97 | * do not make sense as or do not benefit becoming enums 98 | * require additional information as part of the declataion (e.g. `extern(C++, N.M)`) and are incompatible with enums, or 99 | * introduce too much breakage changing defaults 100 | 101 | ### Breaking changes / deprecation process 102 | 103 | Use of the current attributes that are not prefixed by an `@`, such as `pure` and `nothrow`, and optionally other modifiers that are attribute-like such as `final`, will be changed to refer to the `core.attribute` symbols, and thus their use without the leading `@` will be deprecated. 104 | 105 | During the deprecation phase where `pure` and `nothrow` appear that affect the attributes of a symbol (i.e. their current usage, as opposed to referring to the druntime symbol for e.g. a template parameter) the compiler shall treat `pure` and `nothrow` (without a leading `@`) as though they did have a leading `@`. 106 | 107 | No other breaking changes are intended, although the introduction of the new `enum` symbols to be implicitly imported by `object.d` may break some code if the chosen names clash (unlikely) but can be mitigated with `@future` if need be. 108 | 109 | ### Examples 110 | 111 | ```d 112 | module foo; 113 | @nogc: 114 | 115 | // bar overrides the default @nogc'ness above and is @gc. It is 116 | // applied after defaultAttributeSet and therefore beats it by "last applied wins" rule 117 | // `gc` is an alias for `core.attribute.GarbageCollectedness.gc` 118 | @gc void bar() {auto a = new int;} 119 | 120 | // quux is @nogc 121 | void quux(); 122 | ``` 123 | 124 | Attributes can be used without attachment to symbols enabling introspection without worrying about compiler attribute inference impacting the required attributes: 125 | 126 | ```d 127 | struct RequiredAttrs(T...) if(allSatisfy!(isCoreAttributeValue,T)) 128 | { 129 | alias attributes = T; 130 | } 131 | 132 | template isRequiredAttrs(T) 133 | { 134 | enum bool isRequiredAttrs = isInstanceOf!(RequiredAttrs,T); 135 | } 136 | 137 | struct RestrictedInputRange(T) 138 | { 139 | // Note: no leading '@' as the symbols are used directly 140 | RequiredAttrs!(nothrow,nogc): 141 | 142 | @property T front(); 143 | void popFront(); 144 | bool empty(); 145 | } 146 | 147 | auto algorithm(R)(R r) if(Implements!(R,RestrictedInputRange,ElementType!R) 148 | { 149 | //... 150 | } 151 | 152 | // Illustrative: does not take into account UFCS. 153 | template Implements(Model,alias _Idol, Args...) 154 | { 155 | static if (isTemplate!_Idol) 156 | alias Idol = _Idol!Args; 157 | else 158 | alias Idol = _Idol; 159 | 160 | template signaturesMatch(string member) 161 | { 162 | alias attrs = Filter!(isRequiredAttrs,__traits(getAttributes, __traits(getMember, Idol,member)))[$]; 163 | enum bool signaturesMatch = isCompatiableWith( __traits(getMember, Model,member), 164 | __traits(getMember, Idol,member), 165 | attrs); 166 | } 167 | enum bool Implements = staticFold!(templateAnd, 168 | staticMap!(signaturesMatch, __traits(getMembers,Idol))); 169 | } 170 | 171 | enum bool isCompatiableWith(_F,_G, Attrs...) = is(typeof({ 172 | alias F = ReturnType!F function(Paramters!F); 173 | alias G = ReturnType!G function(Paramters!G); 174 | F f; 175 | @Attrs G g = f; 176 | }); 177 | 178 | ``` 179 | 180 | ## Copyright & License 181 | 182 | Copyright (c) 2017 by the D Language Foundation 183 | 184 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 185 | 186 | ## Review 187 | 188 | [Preliminary Review Round 1](http://forum.dlang.org/post/rqebssbxgrchphyuruwa@forum.dlang.org) 189 | 190 | ## Addendum 191 | Due to a lack of response from the DIP author, the DIP manager marked this DIP Abandoned. -------------------------------------------------------------------------------- /DIPs/other/DIP1025.md: -------------------------------------------------------------------------------- 1 | # Dynamic Arrays Only Shrink, Never Grow 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1025 | 6 | | Review Count: | 1 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | | 9 | | Status: | Withdrawn | 10 | 11 | 12 | ## Abstract 13 | 14 | Disable growing the length of a dynamic array (a.k.a. a slice) via the append operator (`~=`) 15 | and by setting the `.length` property. Slices can be shrunk, but never enlarged. 16 | 17 | 18 | ## Contents 19 | * [Rationale](#rationale) 20 | * [Prior Work](#prior-work) 21 | * [Description](#description) 22 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 23 | * [Reference](#reference) 24 | * [Copyright & License](#copyright--license) 25 | * [Reviews](#reviews) 26 | 27 | 28 | ## Rationale 29 | 30 | Enlarging a slice, using the append operator or by setting the `.length` property, 31 | makes use of the garbage collector. This fosters the incorrect notion that D slices 32 | _require_ the GC. Worse, if the slice is not on the GC heap already, and is managed 33 | explicitly, growing it via the append operator or `.length` puts it onto the 34 | GC heap, thereby complicating any other memory management technique. 35 | There is no way to detect if such has occurred or to prevent the user of a slice 36 | from doing it. 37 | 38 | 39 | Problematic uses: 40 | ```d 41 | int[] slice = cast(int*)malloc(10 * int.sizeof)[0 .. 10]; 42 | slice ~= 1; 43 | free(slice.ptr); // Oops! 44 | ``` 45 | 46 | ```d 47 | enum { dead, alive } 48 | int[] cat = new int[6]; 49 | cat[5] = alive; 50 | int[] b = cat; 51 | b ~= 1; // may or may not move b to new location 52 | b[5] = dead; // indeterminate whether cat[5] is dead or alive 53 | ``` 54 | 55 | Prohibiting size changes from growing a slice will avoid these problems. 56 | This approach also fosters the notion that slices do not manage their own 57 | memory; it is instead managed by the memory object from which the slice was taken. 58 | 59 | This change is a necessary part of evolving D toward being memory safe without using 60 | a GC. 61 | 62 | 63 | ## Prior Work 64 | 65 | The author is unaware of any slices in other languages that don't also carry a `.capacity` 66 | property to keep track of how much the slice can grow before it must be reallocated. 67 | 68 | Rust's notion of pointers owning the memory they point to, unless the pointer is 69 | borrowed, is equivalent with this DIP's notion of a slice "borrowing" a reference to 70 | another object which manages the memory. 71 | 72 | 73 | ## Description 74 | 75 | Using the append operator with a slice as the lvalue will no longer be allowed. 76 | Setting the `.length` property can only be used to shrink a slice. 77 | 78 | Slices can still be allocated by operator `new` or sliced out of existing 79 | arrays. [std.array.appender](https://dlang.org/phobos/std_array.html#appender) 80 | can be used instead of the append operator to build dynamic arrays by appending elements. 81 | 82 | 83 | ### Grammar Changes 84 | 85 | None. 86 | 87 | 88 | ## Breaking Changes and Deprecations 89 | 90 | Any use of `~=` or `.length` which tries to grow the slice will fail, the former 91 | at compile time and the latter at runtime (as a dynamic check is necessary). 92 | Hence, a long deprecation period will be necessary. 93 | The switch used to initially enable the new behavior will be `-preview=nogrowslice` 94 | 95 | A workaround for deprecating: 96 | 97 | ``` 98 | a ~= b; 99 | ``` 100 | is to use `std.array.appender` or array concatenation: 101 | ```d 102 | a = a ~ b; 103 | ``` 104 | although that will generate more GC garbage if used in a loop. 105 | 106 | ## Reference 107 | 108 | [D Dynamic Arrays](https://dlang.org/spec/arrays.html#dynamic-arrays) 109 | 110 | 111 | ## Copyright & License 112 | 113 | Copyright (c) 2019 by the D Language Foundation 114 | 115 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 116 | 117 | ## Reviews 118 | 119 | ### Community Review Round 1 120 | 121 | [Reviewed Version](https://github.com/dlang/DIPs/blob/1b525ec4c914c06bc286c1a6dc93bf1533ee56e4/DIPs/DIP1025.md) 122 | 123 | [Discussion](https://forum.dlang.org/post/wvbeyxlcdthqvzsglofx@forum.dlang.org) 124 | 125 | The feedback was overwhelmingly negative. Aside from expressions of a general dislike of restricting a popular feature, common criticisms included: 126 | 127 | * weak rationale 128 | * extensive breakage of existing code 129 | * lack of clarity on the bigger picture (e.g. is this part of a shift away from using GC in D and, if so, why isn't `@nogc` sufficient?) 130 | * lack of clarity about slices vs. arrays 131 | 132 | ## Addendum 133 | The DIP author chose to withdraw the DIP from consideration. The reason cited was that some of the feedback made clear that the proposed change doesn't actually protect slices, as "the slice can be assigned anything anyway". -------------------------------------------------------------------------------- /DIPs/other/DIP1031.md: -------------------------------------------------------------------------------- 1 | # Deprecate Brace-Style Struct Initializers 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1031 | 6 | | Review Count: | 1 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | | 9 | | Status: | Withdrawn | 10 | 11 | ## Abstract 12 | 13 | With the adoption of named argument lists, the brace-style struct initializer 14 | syntax is redundant with that of function-style struct literals. Removing 15 | the brace-style will reduce the complexity of the language. 16 | 17 | ## Contents 18 | * [Rationale](#rationale) 19 | * [Prior Work](#prior-work) 20 | * [Description](#description) 21 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 22 | * [Reference](#reference) 23 | * [Copyright & License](#copyright--license) 24 | * [Reviews](#reviews) 25 | 26 | ## Rationale 27 | 28 | Having two equivalent means to achieve the same effect is a pointless redundancy in a language. 29 | Even worse, it engenders bikeshedding debates about which approach is "better". It's better 30 | to have one way of achieving the effect in that it reduces the complexity of the compiler, the specification, 31 | and efforts to teach the language. 32 | 33 | ## Prior Work 34 | 35 | This DIP presumes the acceptance of [DIP 1030: Named Arguments](https://github.com/dlang/DIPs/blob/846a6ae37f731cd2e17d2249272b07555a4e7400/DIPs/DIP1030.md). 36 | 37 | ## Description 38 | 39 | Deprecate support for the brace-style struct initializer syntax. 40 | 41 | ### Grammar 42 | 43 | The syntax for [StructInitializer](https://dlang.org/spec/declaration.html#StructInitializer) 44 | will be deprecated and eventually removed. 45 | 46 | ## Breaking Changes and Deprecations 47 | 48 | Suggest users replace brace-style initialization with struct literals. 49 | 50 | ```d 51 | struct S { int a, b; } 52 | 53 | S s = { 1, 2 }; // Deprecated: use S(1, 2) instead 54 | ``` 55 | 56 | ## Reference 57 | 58 | 1. [StructInitializer](https://dlang.org/spec/declaration.html#StructInitializer) 59 | 2. [DIP 1030: Named Arguments](https://github.com/dlang/DIPs/blob/846a6ae37f731cd2e17d2249272b07555a4e7400/DIPs/DIP1030.md) 60 | 61 | ## Copyright & License 62 | Copyright (c) 2019 by the D Language Foundation 63 | 64 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 65 | 66 | ## Reviews 67 | 68 | ### Community Review Round 1 69 | 70 | [Reviewed Version](https://github.com/dlang/DIPs/blob/c0c1c9f9665e0bc1db611f4e93e793d64451f763/DIPs/DIP1031.md) 71 | 72 | [Discussion](https://forum.dlang.org/post/uivuxsycynvgvslkkzmx@forum.dlang.org) 73 | 74 | [Feedback](https://forum.dlang.org/post/iywiuqqmevdghgbyrved@forum.dlang.org) 75 | 76 | 77 | Feedback in the Feedback thread was very light. Specific points: 78 | * One commenter suggested more cons for the brace-style initializers. 79 | * The motivation is weak. Better if the rationale expressed that DIP 1030 was the motivation. The DIP author asserted that redundancy is a good motivation. 80 | * Will the breakage be as simple as the DIP suggests? The DIP author sees no further complications. 81 | * Neither this DIP nor DIP 1030 specify a default struct literal syntax supporting named parameters in the absence of a constructor. 82 | 83 | The Discussion thread went on for several pages. Some expressed support for the change, others were against it, others suggested modifications. 84 | 85 | ## Addendum 86 | Subsequent to Community Review Round 1, the DIP author chose to withdraw this DIP from consideration. -------------------------------------------------------------------------------- /DIPs/other/DIP1032.md: -------------------------------------------------------------------------------- 1 | # Function Pointer and Delegate Parameters Inherit Attributes from Function 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1032 | 6 | | Review Count: | 2 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | | 9 | | Status: | Withdrawn | 10 | 11 | ## Abstract 12 | 13 | When function parameters are declared as delegates or function pointers, any `@safe`, `pure`, 14 | `nothrow`, and `@nogc` attributes that are attached to the function type are ignored. 15 | This DIP proposes that any of these attributes attached to a function 16 | become the defaults for delegate and function pointer types declared in the function's parameter list. 17 | 18 | 19 | ## Contents 20 | * [Rationale](#rationale) 21 | * [Prior Work](#prior-work) 22 | * [Description](#description) 23 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 24 | * [Reference](#reference) 25 | * [Copyright & License](#copyright--license) 26 | * [Reviews](#reviews) 27 | 28 | ## Rationale 29 | 30 | Consider the code: 31 | 32 | ```d 33 | @safe pure nothrow @nogc 34 | int foo(int delegate() dg) 35 | { 36 | return dg(); // Error 37 | } 38 | ``` 39 | 40 | This fails because the delegate `dg` has none of `foo`'s attributes. The user 41 | will need to write: 42 | ```d 43 | @safe pure nothrow @nogc 44 | int foo(int delegate() @safe pure nothrow @nogc dg) 45 | { 46 | return dg(); // No error 47 | } 48 | ``` 49 | 50 | The following also compiles without error: 51 | ```d 52 | @safe pure nothrow @nogc 53 | { 54 | alias dg_t = int delegate(); 55 | 56 | int foo(dg_t dg) 57 | { 58 | return dg(); // No error 59 | } 60 | } 61 | ``` 62 | 63 | demonstrating that the `dg_t` declaration is picking up attributes that 64 | are in scope. 65 | 66 | Having the user repeat these attributes in the parameter declaration is 67 | both surprising and burdensome. It is even more inconvenient because when a delegate 68 | is passed to a function, most of the time it is so the function can call it, 69 | but the function cannot call it if it does not have at least the set of 70 | `@safe`, `pure`, `nothrow`, and `@nogc` attributes that the function has. 71 | 72 | Passing delegates to functions is a key feature of D and underpins a number of 73 | coding patterns. Making them easier to use by eliminating the need for a clutter 74 | of attribute annotations will be welcome and will lower the barrier to adding 75 | annotations to functions in the first place. 76 | 77 | A further reason is that the `lazy` function parameter attribute is underspecified 78 | and is a constant complication in the language specification. With this DIP, `lazy` 79 | can move towards being defined in terms of an equivalent delegate parameter, 80 | thereby simplifying the language by improving consistency. 81 | 82 | This DIP proposes that delegate and function pointer parameters default to having 83 | the same combination of the four aforementioned attributes as the function which 84 | defines the parameter list. 85 | 86 | ## Prior Work 87 | 88 | None known. 89 | 90 | 91 | ## Description 92 | 93 | Function pointer and delegate types defined in the function parameter list default 94 | to the attributes of the function type that defines that parameter list. 95 | With this change, the following will compile without error: 96 | ```d 97 | @safe pure nothrow @nogc 98 | int foo(int delegate() dg, int function() fp) 99 | { 100 | return dg() + fp(); 101 | } 102 | ``` 103 | 104 | 105 | ## Breaking Changes and Deprecations 106 | 107 | It is possible that a parameter declaration may require that a delegate or function pointer 108 | parameter have fewer attributes than the function itself. This would only be possible in the 109 | following cases: 110 | 111 | 1. delegate or function pointer was never called, but was ignored or simply stored elsewhere. 112 | 2. the function is `nothrow` but the delegate throws, and the function wraps the call to the delegate in a try-catch block 113 | 3. the function is `pure` but the delegate is impure, and called only within a `debug` block 114 | 4. the function is `safe` but the delegate is `system`, and is called within a `trusted` block 115 | 116 | 117 | Such can be accomplished by declaring the parameter type elsewhere: 118 | 119 | ```d 120 | alias dg_t = void delegate() dg_t; 121 | alias fp_t = void function() fp_t; 122 | 123 | dg_t global_dg; 124 | fp_t global_fp; 125 | 126 | @safe pure nothrow @nogc 127 | void foo(dg_t dg, fp_t fp) 128 | { 129 | global_dg = dg; 130 | global_fp = fp; 131 | } 132 | ``` 133 | 134 | Because of possible code breakage, this feature will initially be available only via 135 | the `-preview=attrdelegate` compiler switch. 136 | 137 | ## Reference 138 | 139 | An alternative approach [was proposed](https://forum.dlang.org/post/mailman.2553.1586000429.31109.digitalmars-d@puremagic.com) during the community review round and [subsequently clarified](https://forum.dlang.org/post/rgifhwdmvsrfxbqqagnp@forum.dlang.org). The DIP [author responded](https://forum.dlang.org/post/rfq8sc$t6r$1@digitalmars.com). 140 | 141 | ## Copyright & License 142 | Copyright (c) 2020 by the D Language Foundation 143 | 144 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 145 | 146 | ## Reviews 147 | ### Community Review Round 1 148 | 149 | [Reviewed Version](https://github.com/dlang/DIPs/blob/0c99bd854302ade3e6833080410e9050fddec346/DIPs/DIP1032.md) 150 | 151 | [Discussion](https://forum.dlang.org/post/ovllntpiebixbtrbiuxj@forum.dlang.org) 152 | 153 | [Feedback](https://forum.dlang.org/post/tkosvxedhztfjxsxtkdm@forum.dlang.org) 154 | 155 | The following points were raised in the feedback thread: 156 | 157 | * two reviewers noted that this proposal will cause significant breakage and suggested it should be opt-in. Each provided a different approach. 158 | 159 | Option 1: allow `auto` on delegate parameters 160 | ```d 161 | @safe pure nothrow @nogc 162 | int foo(int delegate() auto dg, int function() auto fp) 163 | ``` 164 | Option 2: add a new `@inherit` attribute for parameters 165 | ```d 166 | @safe pure nothrow @nogc 167 | int foo(int delegate() @inherit dg, int function() @inherit fp) 168 | ``` 169 | * the DIP does not discuss templates: what happens when function attributes are inferred but the template doesn't actually call the delegate or function pointer parameter? The DIP author replied that templates do not currently infer attributes for delegates and this DIP does not propose changing that behavior. 170 | * the proposed feature, if accepted at all, should be limited to `lazy` parameters. 171 | * the potential for breaking changes has been oversimplified. 172 | * this would prohibit passing e.g., `@system` delegates to `@safe` constructors or functions, so should be opt-in, though it's not clear to the reviewer if a new attribute is warrented. 173 | 174 | ### Final Review 175 | 176 | [Reviewed Version](https://github.com/dlang/DIPs/blob/5675676cfb21a69cfd6eda033c53356ee2275fd1/DIPs/DIP1032.md) 177 | 178 | [Discussion](https://forum.dlang.org/post/ubcwhqxyjizccoekpgbw@forum.dlang.org) 179 | 180 | [Feedback](https://forum.dlang.org/post/axjajqhksecqdsercgmy@forum.dlang.org) 181 | 182 | There was little activity in the discussion thread and only one review in the feedback thread. The feedback raised the following issues: 183 | 184 | * The DIP adds nothing new, simply moving a restriction from one place to another, and it does so inconsistenly and incompletely. 185 | * Some code that does not compile now would compile with this change, but some that does compile now would break. 186 | * The DIP trades readability for writeability. The DIP author suggests writeability is important: "people don't like writing attribute soup". 187 | * As an example of real-world code, Phobos does not exhibit issues this DIP proposes to solve. The DIP author replied that he had encountered compiler errors with Phobos in the past when delegates were unattributed, so he fixed them. Therefore, it's no surprise that Phobos does not exhibit those issues. 188 | * The real problem is that functions that accept delegates have to be unattributed if the delegate can't be templated. Instead of allowing the deleage parameter to pick up a function's attributes, it should be the other way around. 189 | 190 | ## Addendum 191 | The DIP author chose to withdraw the DIP from consideration prior to the formal assessment. The potential for code breakage was too high and the utility of the feature too low to justify the change. -------------------------------------------------------------------------------- /DIPs/other/DIP1033.md: -------------------------------------------------------------------------------- 1 | # Implicit Conversion of Expressions to Delegates 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1033 | 6 | | Review Count: | 2 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | | 9 | | Status: | Postponed | 10 | 11 | ## Abstract 12 | 13 | Allow implicit conversion of expressions to delegates. This happens already for 14 | arguments to lazy parameters. This proposal extends it more generally and 15 | lays the foundation for removing `lazy` as a special case delegate. 16 | 17 | 18 | ## Contents 19 | * [Rationale](#rationale) 20 | * [Prior Work](#prior-work) 21 | * [Description](#description) 22 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 23 | * [Reference](#reference) 24 | * [Copyright & License](#copyright--license) 25 | * [Reviews](#reviews) 26 | 27 | ## Rationale 28 | 29 | Currently, arguments to `lazy` parameters are automatically converted to delegates. The troubles with `lazy` are: 30 | 31 | 1. it stands out as an oddity 32 | 2. being an oddity means it is hard to reason about, especially with the 33 | proliferation of parameter attributes 34 | 3. it is underdocumented 35 | 4. special case code for it is sprinkled throughout the compiler 36 | 5. it is rarely used, so likely has many undetected problems 37 | 6. that it works like a delegate has largely gone unrecognized 38 | 39 | `lazy` has found a home, however, in functions like this one in `std.path`: 40 | ```D 41 | pure @safe string absolutePath(string path, lazy string base = getcwd()); 42 | ``` 43 | where it is undesirable to compute the `base` argument unless it is actually needed. 44 | With this change, it could be rewritten as: 45 | 46 | ```D 47 | pure @safe string absolutePath(string path, string delegate() base = getcwd()); 48 | ``` 49 | and called the same way. 50 | 51 | There's more than supplanting `lazy`. It makes delegates in general easier to write, 52 | and experience suggests that the easier they are to write, the more uses people will 53 | find for them: 54 | 55 | ```D 56 | int delegate() dg = () { return 3; }; 57 | ``` 58 | or: 59 | ```D 60 | int delegate() dg = () => 3; 61 | ``` 62 | become simply: 63 | ```D 64 | int delegate() dg = 3; 65 | ``` 66 | 67 | ## Prior Work 68 | 69 | None known. 70 | 71 | ## Description 72 | 73 | Allow the implicit conversion of an `Expression` of type `T` to a delegate lambda function that 74 | returns a type `T`. The body of the delegate lambda will be the `Expression` which 75 | will be returned from the lambda. 76 | 77 | I.e.: 78 | 79 | Given expression `E` of type `T`, it is converted to: 80 | 81 | ``` 82 | T delegate() { return E; } 83 | ``` 84 | 85 | Attribute inference is performed on the function as it is for all lambda functions. 86 | 87 | The [match level](http://dlang.org/spec/function.html#function-overloading) 88 | will be: "2. match with implicit conversions". 89 | If the generated delegate lambda is not implicitly convertible to the delegate type 90 | in the funciton declaration, there is no match. 91 | 92 | This is a generalization of the current method of converting variadic arguments 93 | to delegates. See [Lazy Variadic Functions](https://dlang.org/spec/function.html#lazy_variadic_functions). 94 | 95 | ### Grammar Changes 96 | 97 | None. 98 | 99 | ### Function Overloading 100 | 101 | ``` 102 | void biff(int); // A 103 | void biff(int delegate()); // B 104 | 105 | void test(int i) 106 | { 107 | biff(i); 108 | } 109 | ``` 110 | 111 | `i` is of type `int`, which is an exact match for `A`. A match with `B` would be 112 | via a conversion to a delegate lambda, so `A` is better and is selected. 113 | 114 | ``` 115 | void biff(long); // A 116 | void biff(long delegate()); // B 117 | 118 | void test(int i) 119 | { 120 | biff(i); 121 | } 122 | ``` 123 | Both A and B are matched equally at the "conversion" level. Then, partial ordering is 124 | applied. A variable of type `long` can be converted to `long delegate()` lambda, but a 125 | `long delegate()` cannot be converted to `long`. Therefore, `A` is the better match. 126 | This makes sense as the intuitive result. 127 | 128 | 129 | ### `null` 130 | 131 | ``` 132 | void biff(T delegate()); 133 | 134 | void test() 135 | { 136 | biff(null); 137 | } 138 | ``` 139 | `null` implicitly converts directly to any delegate, but is not of type `T`, so it will 140 | not be turned into a lambda. Again, this is what is expected and is consistent 141 | with existing code. 142 | 143 | 144 | ### Function Pointers 145 | 146 | Implicit conversion of expressions to function lambdas is not done. There doesn't seem 147 | much point to it, as there will be no arguments to the function lambda, meaning the expression 148 | can only consist of globals. 149 | 150 | 151 | ### Deprecation of `lazy` 152 | 153 | Although this DIP renders `lazy` redundant and unnecessary, it does not propose actually 154 | removing `lazy`. That will be deferred for a future DIP. 155 | 156 | 157 | ## Breaking Changes and Deprecations 158 | 159 | The only potential difficulty is if delegates are overloaded with other types. But the combination 160 | of matching rules by conversion level and partial ordering appear to resolve this in the direction 161 | of not breaking existing code. 162 | 163 | ## Reference 164 | 165 | None. 166 | 167 | ## Copyright & License 168 | Copyright (c) 2019-2020 by the D Language Foundation 169 | 170 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 171 | 172 | ## Reviews 173 | 174 | ### Community Review Round 1 175 | [Reviewed Version](https://github.com/dlang/DIPs/blob/7b61411cb6cf8db05d9b8e1df5d2d9bae53a5f1e/DIPs/DIP1033.md) 176 | 177 | [Discussion](https://forum.dlang.org/post/ecxdylguqkhtmdomlzhq@forum.dlang.org) 178 | 179 | [Feedback](https://forum.dlang.org/post/nxahrsukobybkezibcsm@forum.dlang.org) 180 | 181 | Regarding the section on "Function Pointers", which says "the expression can only consist of globals", 182 | one reviewer brought up the following case in which there are no globals: 183 | 184 | ```D 185 | int function() = 3; 186 | ``` 187 | 188 | The DIP author replied that it seems pointless to support function pointers only with constants and 189 | that he could think of no compelling use case. 190 | 191 | Another reviewer noted that lazy variadic parameters already work as described in the DIP, and lazy "is not expressive enough to cover that case". The DIP author replied that he had overlooked that. 192 | 193 | ### Final Review 194 | [Reviewed Version](https://github.com/dlang/DIPs/blob/8e56fc593ece5c74f18b8eb68c3f9dcedf2396a7/DIPs/DIP1033.md) 195 | 196 | [Discussion](https://forum.dlang.org/post/ysdmdeemnrfwqemkjrlr@forum.dlang.org) 197 | 198 | [Feedback](https://forum.dlang.org/post/tvwikrkcqqyeyprfdokg@forum.dlang.org) 199 | 200 | The following points were raised in the Feedback Thread: 201 | 202 | * A specific example showing that, given a `pure`, `@safe` functions with a `@trusted` delegate parameter, the delegate is both impure and unsafe, leading to a compiler error without auto inference. If auto inference of parameter types is intended, the DIP should detail it. The DIP author replied that a compiler error seems the be proper result. 203 | * The DIP fails to discuss the readability of `lazy`, citing the C# requirement of modifying the caller when, e.g., calling functions with `ref` parameters. The DIP author replied that the C# approach makes refactoring harder, but he did not indicate if he would add such to the DIP. 204 | * There are already multiple ways to declare the same delegate, and this proposal introduces new syntax that would be easily misunderstood and simply replaces one approach with another. The DIP author replied that the goal is to dispense with unnecessary syntax, and that this DIP introduces no new syntax. 205 | * One reviewer quoted the two sentences on function lambdas ("Implicit conversion of expressions to function lambdas is not done. here doesn't seem much point to it, as there will be no arguments to the function lambda, meaning the expression can only consist of globals.") and suggested the DIP should show how this case is not desirable when explicit conversion to delegate is. 206 | * Attributes for functions taking delegates as parameters should be fixed before this feature is implemented. 207 | * The DIP should be amended such that the feature only applies to `scope` delegates, which should only be allocated on the stack, so that non-scope delegates which allocate on the heap can be more visible. 208 | 209 | ## Addendum 210 | Subsequent to the Final Review, the DIP author requested that the review process be postponed until further notice. -------------------------------------------------------------------------------- /DIPs/other/DIP1039.md: -------------------------------------------------------------------------------- 1 | # Static Arrays with Inferred Length 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1039 | 6 | | Review Count: | 1 | 7 | | Author: | Lucien Perregaux | 8 | | Implementation: | None | 9 | | Status: | Withdrawn | 10 | 11 | ## Abstract 12 | 13 | Allow `$` in the brackets of array declarations in place of integer literals in order to infer array length. 14 | 15 | ## Contents 16 | * [Rationale](#rationale) 17 | * [Prior Work](#prior-work) 18 | * [Description](#description) 19 | * [Reference](#reference) 20 | * [Copyright & License](#copyright--license) 21 | * [Reviews](#reviews) 22 | 23 | ## Rationale 24 | 25 | It is sometimes necessary to modify the contents of an existing static array initializer. For example, 26 | 27 | ```d 28 | int[2] array = [2, 4]; 29 | ``` 30 | 31 | may at some point be changed to 32 | 33 | ```d 34 | int[3] array = [2, 4, 6]; 35 | ``` 36 | 37 | The programmer must remember to update the integer literal in the static array declaration from `2` to `3`, else face a compiler error. 38 | 39 | The goal of this proposal is to eliminate the need to change the length specified in a static array declaration, with minimal impact on compile time, when modifying 40 | the length of the array's initializer. 41 | 42 | Allowing the compiler to infer static array length will potentially save time and prevent compiler errors, 43 | as the programmer will no longer need to change the integer literal in the array declaration. 44 | This is especially beneficial when using `betterC`, where dynamic arrays are not available. 45 | 46 | Conceptually, the new operator `[$]` documents that the programmer does not care about the array's length, 47 | but only that the array is a static array and not a slice. 48 | 49 | No control-flow analysis is needed for this feature. 50 | 51 | ## Prior Work 52 | 53 | ### C and C++ 54 | 55 | In C and C++, we can declare a static array with inferred length like this: 56 | 57 | ```c 58 | int arr[] = {1, 2, 3}; 59 | ``` 60 | In D, the identical syntax 61 | 62 | ```d 63 | int[] arr = [1, 2, 3]; 64 | ``` 65 | is a slice, and not a static array. 66 | 67 | See this [C array initialization documentation](https://en.cppreference.com/w/c/language/array_initialization). 68 | 69 | ### D 70 | - The `$` operator, which is well implemented. 71 | - [PR 3615](https://github.com/dlang/dmd/pull/3615) 72 | - Reverted due to partial deduction [PR 4373](https://github.com/dlang/dmd/pull/4373) 73 | - [PR 590](https://github.com/dlang/dlang.org/pull/590) 74 | - [Issue 14070](https://issues.dlang.org/show_bug.cgi?id=14070) 75 | - [Issue 8008](https://issues.dlang.org/show_bug.cgi?id=8008) 76 | 77 | ## Description 78 | 79 | This feature is compatible with `betterC` and is only available for variable declarations with initializers. 80 | The `$` in the array declaration's brackets will be replaced, at compile time, with the initializer's length. 81 | 82 | Currently, a static array must be declared like this: 83 | ```d 84 | uint[2] arr = [ 2, 4 ]; 85 | ``` 86 | When doing this, we have a DRY violation because we are spelling out the array's length 87 | even though the compiler knows the length of the array literal used to initialize it. 88 | 89 | With the proposed feature, the above array could be declared like this: 90 | ```d 91 | uint[$] arr = [ 2, 4 ]; // $ = 2 92 | ``` 93 | There is no need to change the length of the static array every time we modify the length of its initializer. 94 | Eliminating that need is the only goal of this proposal. 95 | 96 | More examples: 97 | ```d 98 | char[$] a1 = "cerise"; // OK, `$` is replaced with `6` at compile time 99 | 100 | const int[] d = [1, 2, 3]; 101 | int[$] a2 = d; // OK, `$` = 3 102 | 103 | auto a3 = cast(int[$]) [1, 2, 3]; // OK, `a3` is `int[3]` (same behavior as `cast(int[3])`) 104 | 105 | int[$][] a4 = [[1, 2], [3, 4]]; // OK, same as `int[2][]` 106 | foreach (int[$] a; a4) {} // OK, we can deduce `$` because the length of `a4[0]` is equal to 2. 107 | 108 | void foo(int[$] a5 = [1,2]); // OK, `a5` has a default value, so we can deduce it's length 109 | 110 | int[5] bar(); 111 | int[$] a6 = bar(); // OK, `bar` returns a static array. 112 | ``` 113 | 114 | Those examples won't work: 115 | ```d 116 | int[$] b1; // Error: we don't know the length of `b1` at compile-time. 117 | 118 | int[$][] = [[1, 2],[1, 2, 3]]; // Error: cannot implicitly convert expression `[[1, 2], [1, 2, 3]]` of 119 | // type `int[][]` to `int[2][]` 120 | 121 | /* 122 | * `$` is equal to `3`, because it's the length of `b2[0]`. 123 | * As `b2[1]`'s length is 4, a RangeViolation error is thrown. 124 | */ 125 | int[][] b2 = [[1, 2, 3], [1, 2, 3]]; 126 | foreach (int[$] b; b2) {} // Error: we don't know the length of `b` at compile-time. 127 | 128 | void foo(int[$] b3); // Error: we don't know the length of `b3` at compile-time. 129 | 130 | int[$] bar(int[2] arr) // Error: not allowed in functions declarations 131 | { 132 | return arr ~ [3, 4]; 133 | } 134 | 135 | int baz(int[$] b5)(string s); // Error: not allowed in templates declarations 136 | 137 | int[] d = [1, 2]; 138 | int[$] b6 = d; // Error, we don't know the length of `d` at compile-time. 139 | ``` 140 | 141 | ### Grammar changes 142 | 143 | [declaration spec](https://dlang.org/spec/declaration.html) 144 | ```diff 145 | TypeSuffix: 146 | * 147 | [ ] 148 | + [ $ ] 149 | [ AssignExpression ] 150 | [ AssignExpression .. AssignExpression ] 151 | [ Type ] 152 | delegate Parameters MemberFunctionAttributes 153 | delegate Parameters 154 | function Parameters FunctionAttributes 155 | function Parameters 156 | 157 | 158 | 2. Arrays read right to left as well: 159 | int[3] x; // x is an array of 3 ints 160 | int[3][5] x; // x is an array of 5 arrays of 3 ints 161 | int[3]*[5] x; // x is an array of 5 pointers to arrays of 3 ints 162 | +int[$] x = [ 0, 1 ]; // x is a static array of 2 ints 163 | +int[$][] x = [[0, 2], [1, 3]]; // x is a dynamic array of static arrays with a length of 2 164 | ``` 165 | 166 | ## Reference 167 | None 168 | 169 | ## Copyright & License 170 | Copyright (c) 2020, 2021 by the D Language Foundation 171 | 172 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 173 | 174 | ## Reviews 175 | 176 | [Reviewed Version](https://github.com/dlang/DIPs/blob/c06ce7f144b3dabf363d1896ddcd31a2a6b7c969/DIPs/DIP1039.md) 177 | 178 | [Discussion](https://forum.dlang.org/post/ucqyqkvaznbxkasvdjpx@forum.dlang.org) 179 | 180 | [Feedback](https://forum.dlang.org/post/qglydztoqxhhcurvbxhs@forum.dlang.org) 181 | 182 | * The DIP should provide a rationale as to why the feature is not allowed in function declarations. 183 | * The DIP does not provide enough examples; it should clearly demonstrate behavior for every situation in which a type can be used. The DIP author agrees. 184 | * The DIP should explain what the problem was with the first attempt and how this proposal address that problem. The DIP author disagrees. 185 | * The DIP should specify if arrays of character types include a terminating `\0` and, if so, if it is part of the length. 186 | * The DIP fails to provide a rationale as to why `std.array.staticArray` is insufficient. 187 | * Better examples are needed. The DIP author agreed. 188 | * The DIP should use ease of reading/writing code as an argument and provide examples to that effect. The DIP author agreed. 189 | * The benefit gained is very minor, so the DIP should address this in relation to the difficulty of the implementation and maintenance. The DIP author agreed. 190 | 191 | ## Addendum 192 | After the first round of Community Review, the DIP author felt that the general opinion of the DIP was negative, and that he needed to revise the DIP with a strong argument in favor of the proposed feature over `std.array.staticArray`. He was unable to formulate such an argument, so he asked that the DIP be withdrawn. -------------------------------------------------------------------------------- /DIPs/rejected/DIP1001.md: -------------------------------------------------------------------------------- 1 | # DoExpression 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1001 | 6 | | Review Count: | 1 [Most Recent] | 7 | | Author: | [Cauterite](https://github.com/Cauterite) | 8 | | Implementation: | https://github.com/dlang/dmd/compare/master...Cauterite:doExpr0 | 9 | | Status: | Rejected | 10 | 11 | [Most Recent]: https://github.com/dlang/DIPs/tree/16f0f0f5915483c55bf38a6844a8717308923a70/DIPs/DIP1001.md 12 | 13 | ## Abstract 14 | 15 | A *DoExpression* `do(x,y,z)` is exactly equivalent to a *CommaExpression* `(x,y,z)`, but 16 | doesn't emit a deprecation warning. 17 | 18 | ### Links 19 | 20 | [Updated grammar spec](https://github.com/dlang/dlang.org/compare/master...Cauterite:patch-1) 21 | 22 | [Deprecation of CommaExpression](https://dlang.org/deprecate.html#Using%20the%20result%20of%20a%20comma%20expression) 23 | 24 | ## Description 25 | 26 | Using the result of a comma expression is scheduled for deprecation, so it would be 27 | nice to have new syntax which replaces it. *DoExpression* is a new *PrimaryExpression* 28 | which serves the purpose of *CommaExpression* with a more explicit syntax, avoiding 29 | the problems which lead to *CommaExpression*'s deprecation. 30 | 31 | ### Rationale 32 | 33 | - Sometimes you still need to use a comma expression. We don't live in a perfect world where every function is pure, 34 | but we can live in a world where you don't need to split your expression into statements because of side-effects. 35 | - The `do` keyword is currently wasted on a single rarely-used statement type ('do-while' statements). 36 | Sure, you could implement this syntax with a variadic template function, 37 | but why waste this opportunity to recycle `do`, when it's the perfect keyword for this purpose? 38 | - Implementation is dead-simple (already finished). 39 | 40 | ### Breaking changes / deprecation process 41 | 42 | The only existing syntax it collides with is a *CommaExpression* inside a *do-while* statement with no braces: 43 | ```d 44 | do(x,y,z); while (a); 45 | ``` 46 | Such a statement is currently equivalent to: 47 | ```d 48 | do {(x,y,z);} while (a); 49 | ``` 50 | But with *DoExpression* in the grammar it would instead be equivalent to: 51 | ```d 52 | (x,y,z); 53 | while (a); 54 | ``` 55 | Note that `while (a);` is a syntax error in D, so the breakage would not be a silent change of behaviour. 56 | 57 | Once *CommaExpression* is fully deprecated and removed from the language, this 58 | ambiguity will not exist. 59 | 60 | ### Examples 61 | 62 | ```d 63 | // same expression, different syntax 64 | assert((x, y, z) == do(x, y, z)); 65 | 66 | auto x = do(); // Error: do-expression requires at least one argument 67 | ``` 68 | 69 | ## Copyright & License 70 | 71 | Copyright (c) 2016 by the D Language Foundation 72 | 73 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 74 | 75 | ## Review 76 | 77 | [Preliminary NG discussion](http://forum.dlang.org/post/nqem7g$1hm6$1@digitalmars.com) 78 | 79 | ### Decision 80 | 81 | Disposition: REJECT. A proposal for a similar or identical feature would need 82 | to be include qualitatively new motivation/evidence of usefulness. 83 | 84 | ### Rationale 85 | 86 | (By means of background information, the comma operator has been a documented 87 | source of bugs in the C, C++, and D languages. The D language has deemed that 88 | virtually all bugs occur when the result of the operator (i.e. the last 89 | expression in the comma-separated list) is used. Therefore, it has deprecated 90 | that behavior, keeping the other uses legal.) 91 | 92 | DIP1001 proposes a do-expression that behaves like the now-deprecated comma 93 | operator, allowing the programmer to use `do(e1, e2)` for the semantics 94 | equivalent to "e1, e2" in C/C++/former D, where e1 and e2 are (non-comma) 95 | expressions, and similarly for three and more arguments. The obvious lowering 96 | (not specified by the DIP) for e.g. three arguments is: 97 | 98 | ```D 99 | do(e1, e2, e3) 100 | ``` 101 | => 102 | ```D 103 | { e1; e2; return e3; }() 104 | ``` 105 | 106 | This would fit most use cases except those that require a reference to be 107 | returned by e3. (For ref returns, refer to 108 | https://issues.dlang.org/show_bug.cgi?id=16271.) Since the lowering is terse 109 | and readable enough to be usable directly by the programmer (in addition to a 110 | variety of other context-dependent idioms), a key question is whether the 111 | frequency of usage justifies introducing a higher-level syntax that is 112 | marginally more brief. DIP1001 does not present evidence of numerous codes 113 | broken by the deprecation of the comma expression, and shows no examples of 114 | coding patterns and idioms that would be plausibly frequent and improved by the 115 | proposed construct. 116 | 117 | Three points are given in the proposed rationale. The first is that the old 118 | comma expression semantics is still necessary, but fails to mention the obvious 119 | alternative (given above) of using a lambda expression. 120 | 121 | The second rationale given is that the keyword "do" is currently underused. 122 | This rationale does nor argue for the usefulness of the feature at hand. 123 | 124 | The third rationale is that the implementation is simple and finished. Ease and 125 | availability of implementation are obvious pluses for a feature, but cannot be 126 | part of the core reasoning in favor of usefulness of said feature. (The 127 | implication direction should be "useful features should ideally be easy to 128 | implement", not "easy to implement features should ideally be useful"). 129 | 130 | The grammar change is shown but not the change to the language definition. This 131 | observation has not contributed to the decision, but would be a request for 132 | changes should the rationale be accepted. 133 | 134 | Also reviewed from the forum discussion were the following arguments. (Please 135 | note that future proposals would need to integrate arguments aired in forum 136 | exchanges within the DIP in order to be formally considered.) 137 | 138 | - Feature is inspired from Clojure, but no further argument to how its benefits 139 | in Clojure translate to D 140 | - Discussion on a function seq() that is a partial replacement. 141 | - Argument that the lambda equivalent is syntactically less clear. 142 | 143 | Our assessment is that radically new arguments, angles, and examples would be 144 | necessary to successfully push such a feature. 145 | -------------------------------------------------------------------------------- /DIPs/rejected/DIP1028.md: -------------------------------------------------------------------------------- 1 | # Make @safe the Default 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1028 | 6 | | Review Count: | 2 | 7 | | Author: | Walter Bright walter@digitalmars.com | 8 | | Implementation: | https://github.com/dlang/dmd/pull/10709 | 9 | | Status: | Rejected | 10 | 11 | ## Abstract 12 | 13 | Currently, D functions default to being `@system`. This DIP proposes changing the default to `@safe`. 14 | 15 | 16 | ## Contents 17 | * [Rationale](#rationale) 18 | * [Prior Work](#prior-work) 19 | * [Description](#description) 20 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 21 | * [Reference](#reference) 22 | * [Copyright & License](#copyright--license) 23 | * [Reviews](#reviews) 24 | 25 | ## Rationale 26 | 27 | When D was first developed, there was little interest in the extra safety checks 28 | introduced by `@safe`. But as the costs of unsafe code have become ever more apparent 29 | and expensive, and `@safe` has grown more capable, the balance has shifted. Users expect 30 | safety to be opt-out, not opt-in. 31 | 32 | Most code should be naturally safe, and system code should be relatively rare. It makes 33 | sense that the common case - safe code - should be the default and not require an 34 | annotation. 35 | 36 | 37 | ## Prior Work 38 | 39 | * Other languages such as Rust and C# have safety as opt-out, rather than opt-in. 40 | * A previous draft proposal: [@safe-by-default First Draft](https://github.com/dlang/DIPs/pull/153) 41 | 42 | ## Description 43 | 44 | Functions such as template functions, nested functions, and lambdas that are not annotated 45 | currently have their `@safe` / `@system` attribute inferred. This behavior will not change. 46 | Other unannotated functions will now be assumed to be `@safe` rather than `@system`. 47 | 48 | Because this is expected to break a lot of existing code, it will be enabled with the 49 | compiler switch: 50 | 51 | ``` 52 | -preview=safedefault 53 | ``` 54 | 55 | There are no grammar changes. 56 | 57 | ### Non-Virtual Templated Functions 58 | 59 | Non-virtual function templates get their attributes inferred if they are not explicitly marked. 60 | Hence, this proposal should not affect them. 61 | 62 | ## Breaking Changes and Deprecations 63 | 64 | This will likely break most code that has not already been annotated with `@safe`, 65 | `@trusted`, or `@system`. Annotate functions that aren't safe with `@system`. 66 | Once the project compiles again successfully, start with the leaves marked `@system` and 67 | modify as required to make them `@safe`. 68 | 69 | In general, `@system` should not be applied to blocks of functions. It should be added 70 | specifically to each function that requires it. 71 | 72 | ### Extern C and C++ Functions 73 | 74 | An unmarked `extern (D)` function will now be considered `@safe`. If its implementation is not recompiled, 75 | it will no longer link because the mangling will be different. But for `extern (C)` and `(C++)` functions, 76 | safety is not part of the mangling and it will compile and link without error. This has always 77 | relied on the user getting it correct. 78 | 79 | Interfaces to extern C and C++ functions should always be explicitly marked. 80 | 81 | ### 3rd Party Libraries 82 | 83 | It's best practice for 3rd party libraries to use explicit safety annotations and not rely on defaults. 84 | It is also best practice to compile those libraries with the same compiler that is being used 85 | to compile the project. 86 | 87 | ### Virtual Functions (Covariance) 88 | 89 | An `@safe` function can override an `@system` function, but not vice-versa. Hence, with `@safe` being 90 | the default, the user may see compile errors when overriding a now-default `@safe` function with 91 | a `@system` one. The user will have to decide which the inheritance hierarchy should be and annotate 92 | as required. 93 | 94 | ## Reference 95 | 96 | ## Copyright & License 97 | Copyright (c) 2019 by the D Language Foundation 98 | 99 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 100 | 101 | ## Reviews 102 | 103 | ### Community Review Round 1 104 | [Reviewed Version](https://github.com/dlang/DIPs/blob/1b705f8d4faa095d6d9e3a1b81d6cfa6d688554b/DIPs/DIP1028.md) 105 | 106 | [Discussion](https://forum.dlang.org/post/ejaxvwklkyfnksjkldux@forum.dlang.org) 107 | 108 | In a very long discussion thread, there was a mix of support and opposition. Some critical feedback points were: 109 | * The DIP should specify a deprecation plan. 110 | * The DIP should specify an extended deprecation period. 111 | * Such a major change should be saved for a potential D3. 112 | * The DIP should not be approved until it is possible to make `@safe` ref-counted types and a tool exists to annotate existing default `@system` functions as `@system`. Another commenters suggested the tool should additionally annotate functions `@safe` if they compile. The DIP author replied that such a tool would be welcome. 113 | * Introduce `@legacy` that, when added to the top of a module, makes every function `@trusted` by default. 114 | * Weak rationale. 115 | * The rationale should be enhanced to say that the majority of existing, non-template D code is already `@safe`, but not annotated as such, preventing projects with dependencies from using the annotation. This change makes dependencies useful in `@safe` code. 116 | * Advising users to fix breakage by annotating unsafe functions with `@trusted` or `@system` should be revised to just advise `@system`, otherwise users may misunderstand and misuse `@trusted`. The DIP author agreed this is a good idea. 117 | * The DIP should also include the introduction of `@trusted` expressions. This was countered by the argument that changes to `@trusted` should be a separate DIP. 118 | * Make it a compiler option only. 119 | * The DIP does not address bugs in `@safe` which require a DIP to fix. The DIP author replied that this DIP is about making `@safe` the default, not changing its behavior. 120 | * The impact of the change should be assessed. The DIP author replied that compatibility can be achieved by labeling functions that don't compile as `@system`. 121 | * Too many DIPs resulting in new `-preview` switches. The DIP author replied that all programming languages improve or die. 122 | * The DIP does not explore alternatives, as recommended by the DIP guidelines. Examples would be a linting tool that annotates functions as `@safe` when they compile, or the ability to annotate module declarations with `@safe` or `@system` to specify the default behavior in that module. 123 | * What about function declarations with no body? 124 | * The DIP should also change `@system` to `@unsafe`. The DIP author replied that `@unsafe` was rejected when `@system` was introduced because it has negative connotations. 125 | * Perhaps the DIP should discuss DIP1000, since it may have an impact on the amount and nature of breakage this DIP causes. Is this DIP dependent on DIP1000 being the default? Does `-preview=safedefault` imply `-preview=dip1000`? The DIP should discuss the types breakage that will be avoided with DIP1000 enabled. The DIP author replied that DIP1000 and DIP1028 will remain independent. 126 | * The DIP should go into more detail about breaking changes, i.e., migration paths, third-party libraries that are no longer actively maintained, the problem with a catch-all `@system:` disabling template inference, the impact of the change on `extern` APIs, the impact of the change on `@nogc` code, and more. 127 | * The consideration of prior work should provide more detail. 128 | * How does the DIP affect interfaces and virtual functions? Implementations and subclasses with unmarked `@system` implementations will fail to compile when their interface/superclass member functions become `@safe`. The DIP author replied that functions in interfaces and base classes will initially need to be explicitly marked `@system` and can later be marked `@safe` in a transition. 129 | 130 | ### Final Review 131 | [Reviewed Version](https://github.com/dlang/DIPs/blob/5afe088809bed47e45e14c9a90d7e78910ac4054/DIPs/DIP1028.md) 132 | 133 | [Discussion](https://forum.dlang.org/post/jelbtgegkwcjhzwzesig@forum.dlang.org) 134 | 135 | [Feedback](https://forum.dlang.org/post/wkdpnzarkbtqryighzpx@forum.dlang.org) 136 | 137 | The following points were raised in the feedback thread: 138 | * The DIP specifically mentions `extern (D)` functions as being marked as `@safe`? The author replied that *all* `extern` functions will be `@safe`. 139 | * Saying that interfaces to C and C++ functions "should be explicitly marked" is too vague. How should they be marked? 140 | * Adding `@system:` to the top of a file will kill template inference of `@safe`. The DIP should deal with this somehow. 141 | * `@safe` should not be allowed on function declarations that are not `extern (D)` or, alternatively, the compiler should require all non-D mangled functions to be explictly marked with one of `@safe`, `@trusted`, or `@system`. 142 | 143 | ### Formal Assessment 144 | [Reviewed Version](https://github.com/dlang/DIPs/blob/8356ab359d5a6bf9db562ef90dec51a0c39eaafd/DIPs/DIP1028.md) 145 | 146 | [Discussion](https://forum.dlang.org/post/rwjxbgsauknjjrvousti@forum.dlang.org) 147 | 148 | This proposal was initially accepted by the language maintainers. After [further discussion in the D forums](https://forum.dlang.org/post/rwjxbgsauknjjrvousti@forum.dlang.org), the DIP author in his role as language maintainer chose to reverse the decision. The proposal is now rejected. 149 | -------------------------------------------------------------------------------- /DIPs/rejected/DIP1047.md: -------------------------------------------------------------------------------- 1 | # Add `@gc` as a Function Attribute 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | 1047 | 6 | | Author: | Quirin F. Schroll ([@Bolpat](github.com/Bolpat)) | 7 | | Implementation: | | 8 | | Status: | Rejected | 9 | 10 | ## Abstract 11 | 12 | Add `@gc` as a new function attribute that acts as the inverse of the `@nogc` attribute. 13 | 14 | ## Contents 15 | * [Rationale](#rationale) 16 | * [Prior Work](#prior-work) 17 | * [Description](#description) 18 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 19 | * [Reference](#reference) 20 | * [Copyright & License](#copyright--license) 21 | * [History](#history) 22 | 23 | ## Rationale 24 | 25 | When the `@nogc` attribute is applied to multiple functions via the syntax `@nogc:` or `@nogc {}`, 26 | possibly among other attributes, 27 | subsequently including a function that may allocate using the garbage collector (GC) requires one of the following: 28 | * The programmer changes where the function is defined. 29 | * The programmer closes the braced declaration block and reopens it after the definition (DRY violation when more attributes are used). 30 | * The programmer changes the colon syntax to a braced syntax, then applies the aforementioned bullet point. 31 | * The programmer eliminates the colon or block syntax and attaches the attributes to every function definition excluding the new one. 32 | 33 | Such changes make for a bigger diff and are harder to review. 34 | 35 | ## Prior Work 36 | 37 | This proposal is similar in spirit to [DIP 1029](https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1029.md), 38 | which added `throw` as a function attribute/storage class as the inverse of the `nothrow` attribute. 39 | 40 | ## Description 41 | 42 | ### Semantics 43 | 44 | Semantically, a `@gc` function is exactly a function that is not `@nogc`. 45 | Anything that can syntactically have the `@nogc` attribute attached can have the `@gc` attribute attached. 46 | 47 | ```d 48 | @nogc 49 | { 50 | int[] f() => [1]; // Error: array literal in `@nogc` function `f` may cause a GC allocation 51 | int[] g() @gc => [1]; // Okay, `g` is not `@nogc` 52 | } 53 | ``` 54 | 55 | The `@gc` and `@nogc` attributes are mutually exclusive on the same level 56 | exactly as the other pairs of opposing attributes (`@safe` / `@system` and `nothrow` / `throw`). 57 | 58 | ```d 59 | void f() @gc @nogc; // Error: conflicting attributes 60 | ``` 61 | 62 | Like `@system` and `throw`, the `@gc` attribute is contravariant. 63 | 64 | ```d 65 | void f(void function() @gc callback); 66 | void function(void function() @nogc) fp = &f; // Okay 67 | 68 | void g(void function() @nogc callback); 69 | void function(void function() @gc callback) gp = &g; // Error: cannot implicitly convert expression `& g` of type `void function(void function() @nogc callback)` to `void function(void function() @gc callback)` 70 | ``` 71 | 72 | A virtual `@gc` method can be overridden by a `@nogc` method, 73 | but a virtual `@nogc` method cannot be overridden by a `@gc` method. 74 | 75 | ### Grammar 76 | 77 | ```diff 78 | AtAttribute: 79 | @ disable 80 | @ __future 81 | @ nogc 82 | + @ gc 83 | @ live 84 | Property 85 | @ safe 86 | @ system 87 | @ trusted 88 | UserDefinedAttribute 89 | ``` 90 | 91 | ### Scope 92 | 93 | This DIP specifically aims to address the lack of a contravariant inverse of an existing attribute 94 | with a new attribute that can be added easily and with minimal syntactical and naming controvercy. 95 | 96 | The only remaining function attribute without a contravariant inverse will be `pure`. 97 | While the lack of an inverse for `pure` is unfortunate and will become more apparent, 98 | adding one is in all likelihood not as uncontroversial as adding `throw` (cf. [DIP 1029](https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1029.md)) 99 | or `@gc` (this DIP). 100 | 101 | ## Breaking Changes and Deprecations 102 | 103 | This proposal potentially breaks code that uses `@gc` as a user-defined attribute. 104 | Such breakage is unlikely as D programmers likely anticipate the addition of `@gc` as the opposite of `@nogc`. 105 | In the unlikely scenario where code breaks, 106 | renaming `gc` to `gc_` as is customary with other keywords fixes the issue. 107 | 108 | ## Copyright & License 109 | Copyright © 2024 by the D Language Foundation 110 | 111 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 112 | 113 | ## History 114 | This DIP underwent one round of community feedback in the DIP development forum: 115 | 116 | Feedback on the first draft: 117 | https://forum.dlang.org/post/ojjsplombwzzjhjymrnw@forum.dlang.org 118 | 119 | This proposal references [DIP 1029](https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1029.md), an accepted proposal that added the `throw` function attribute, which negates `nothrow`, as a justification for adding `@gc` to negate `@nogc`. In the time since that DIP was accepted, the language maintainers have come to a different opinion. They no longer support the idea of having attributes such as `throw`, `@gc`, and `impure` as counterparts to `nothrow`, `@nogc`, and `pure`. That clutters the language and implies that any new binary attributes added in the future would require a counter-attribute to negate it. 120 | 121 | The maintainers would prefer to see a single attribute that resets all binary attributes to their default state. For example, `@default`. 122 | 123 | They considered the inconsistency of rejecting `@gc` when `throw` had already been approved, but noted that the implementation of `throw` was never completed. As such, they have decided simply to leave DIP 1029 unimplemented in favor of a feature like `@default`. 124 | -------------------------------------------------------------------------------- /GUIDELINES.md: -------------------------------------------------------------------------------- 1 | This document has been superseded by the [DIP Author Guidelines document](./docs/guidelines-authors.md). -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /PROCEDURE.md: -------------------------------------------------------------------------------- 1 | This document has been superseded by the following documents: 2 | 3 | * [The DIP Authoring Process](./docs/process-authoring.md) 4 | * [DIP Author Guidelines](./docs/guidelines-authors.md) 5 | * [DIP Forum Guidelines](./docs/guidelines-forums.md) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # D Improvement Proposals 2 | This repository is intended for the storage and management of improvement proposals for the D programming language. A D Improvement Proposal (DIP) is a formal document that details a potential feature or enhancement to the language, or the official tooling, and the rationale behind it. 3 | 4 | Each DIP is steered through a process of public review by the DIP manager. Each stage of the process is intended to prepare the DIP for its ultimate evaluation by the language maintainers (Walter Bright and Átila Neves). The process and the responsibilities of DIP authors and reviewers are laid out in the following documents: 5 | 6 | * [The DIP Authoring Process](./docs/process-authoring.md) 7 | * [The DIP Review Process](./docs/process-reviews.md) 8 | * [DIP Author Guidelines](./docs/guidelines-authors.md) 9 | * [DIP Reviewer Guidelines](./docs/guidelines-reviewers.md) 10 | 11 | Questions about the DIP process should be directed to the current DIP Manager, Mike Parker (aldacron@gmail.com). The following lists show DIPs that have been submitted in the current process and DIPs that were approved before this repository existed: 12 | 13 | * [currently submitted DIPs](https://github.com/dlang/DIPs/blob/master/DIPs/README.md) 14 | * [older approved DIPs](https://github.com/dlang/DIPs/blob/master/DIPs/archive/README.md) 15 | -------------------------------------------------------------------------------- /Template.md: -------------------------------------------------------------------------------- 1 | # (Your DIP title) 2 | 3 | | Field | Value | 4 | |-----------------|-----------------------------------------------------------------| 5 | | DIP: | (number/id -- assigned by DIP Manager) | 6 | | Author: | (your name and contact email address) | 7 | | Implementation: | (links to implementation PR if any) | 8 | | Status: | Draft | 9 | 10 | ## Abstract 11 | 12 | Required. 13 | 14 | Short and concise description of the idea in a few lines. 15 | 16 | 17 | ## Contents 18 | * [Rationale](#rationale) 19 | * [Prior Work](#prior-work) 20 | * [Description](#description) 21 | * [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) 22 | * [Reference](#reference) 23 | * [Copyright & License](#copyright--license) 24 | * [History](#history) 25 | 26 | ## Rationale 27 | Required. 28 | 29 | A short motivation about the importance and benefits of the proposed change. An existing, 30 | well-known issue or a use case for an existing projects can greatly increase the 31 | chances of the DIP being understood and carefully evaluated. 32 | 33 | ## Prior Work 34 | Required. 35 | 36 | If the proposed feature exists or has been proposed in other languages, this is the place 37 | to provide the details of those implementations and proposals. Ditto for prior DIPs. 38 | 39 | If there is no prior work to be found, it must be explicitly noted here. 40 | 41 | ## Description 42 | Required. 43 | 44 | Detailed technical description of the new semantics. Language grammar changes 45 | (per https://dlang.org/spec/grammar.html) needed to support the new syntax 46 | (or change) must be listed. Examples demonstrating the new semantics will 47 | strengthen the proposal and should be considered mandatory. 48 | 49 | ## Breaking Changes and Deprecations 50 | This section is not required if no breaking changes or deprecations are anticipated. 51 | 52 | Provide a detailed analysis on how the proposed changes may affect existing 53 | user code and a step-by-step explanation of the deprecation process which is 54 | supposed to handle breakage in a non-intrusive manner. Changes that may break 55 | user code and have no well-defined deprecation process have a minimal chance of 56 | being approved. 57 | 58 | ## Reference 59 | Optional links to reference material such as existing discussions, research papers 60 | or any other supplementary materials. 61 | 62 | ## Copyright & License 63 | Copyright (c) 2024 by the D Language Foundation 64 | 65 | Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) 66 | 67 | ## History 68 | The DIP Manager will supplement this section with links to forum discsusionss and a summary of the formal assessment. 69 | -------------------------------------------------------------------------------- /docs/guidelines-authors.md: -------------------------------------------------------------------------------- 1 | # DIP Author Guidelines 2 | 3 | Thank you for deciding to write a D Improvement Proposal (DIP). Your time and effort in enhancing the D programming language are greatly appreciated. This document aims to guide you through the process of creating a clear, concise, and understandable proposal. 4 | 5 | ## General Advice 6 | 7 | When drafting your initial DIP, allow your thoughts to flow freely. You can refine the language, add examples, and fill in gaps through subsequent revisions. 8 | 9 | Before submission, the DIP manager will ensure your proposal adheres to these guidelines: 10 | 11 | 1. Clearly motivate the proposal, explaining its value and comparing it with alternative solutions. 12 | 2. Incorporate real-world examples, preferably from specific projects. 13 | 3. Anticipate and address potential objections with thorough research. 14 | 4. Use formal and technical language, avoiding colloquialisms. A DIP is a technical document, not an opinion piece or blog post. 15 | 5. Provide detailed technical information for D compiler developers to use as a specification. 16 | 17 | ## Proper Motivation 18 | 19 | A DIP must justify its existence by focusing on the "why" as much as the "what". Unnecessary or valueless language changes are likely to be rejected. 20 | 21 | Research alternative solutions, explaining why your proposal is superior. Refer to successes or failures in other languages and how they relate to D. 22 | 23 | Avoid using redundancy in existing features or language flaws as justification for similar additions. 24 | 25 | Consider the cost of adding, changing, or removing features. Changes that build on existing syntax and semantics are less costly than those requiring new concepts. Costlier proposals should offer significant benefits. 26 | 27 | Steer clear of speculation. Unless you are an expert, avoid claims about increased popularity or adoption. Personal or anecdotal evidence should be supported by data or solid reasoning. 28 | 29 | ## Demonstrative Examples 30 | 31 | Include examples in the Rationale section showing situations that are currently impossible, overly complex, or verbose in D. Preferably use real code examples (e.g., from DUB, Phobos). 32 | 33 | Without such examples, a theoretically sound proposal might be disregarded. Practical improvements to real-world code are essential. 34 | 35 | An accompanying implementation allows reviewers to test the examples, verifying their functionality. 36 | 37 | ## Potential Objections 38 | 39 | Addressing potential objections strengthens your proposal. If you foresee objections but cannot counter them, or you ignore them completely, the chance of acceptance is decreased. 40 | 41 | Consider your proposal from all angles and perspectives, including those of potential opposition. 42 | 43 | ## Formal and Technical Language 44 | 45 | A DIP is a formal specification for language features, intended for a technical audience. 46 | 47 | During development, it is acceptable to prioritize clarity and factual accuracy over formality: 48 | 49 | 1. Aim for clear, concise, precise, and factual text. 50 | 2. Remove unsupported personal opinions about the proposed feature. 51 | 3. Avoid ornate or flowery language. 52 | 53 | The DIP manager will assist in formalizing the text before submission. The more effort you put into the language initially, the less revision will be needed. 54 | 55 | ## Technical Details 56 | 57 | DIP authors should understand how the proposal affects existing features and how it can be implemented. If you lack certain knowledge, research or seek expert help before submission. 58 | 59 | List all potential issues, including any possible disruption to existing D code. Describe the intended deprecation process if significant code breakage is likely. 60 | 61 | Cover as many details as possible in your proposal. While not expected to be experts in language design or compiler technology, authors should address community feedback comprehensively. 62 | 63 | The final draft should be detailed enough for independent compiler authors to implement the feature without ambiguity. For example, changes to the language grammar must include a detailed description, formatted as in the [existing grammar spec](https://dlang.org/spec/grammar.html). 64 | -------------------------------------------------------------------------------- /docs/guidelines-forums.md: -------------------------------------------------------------------------------- 1 | # DIP Forum Guidelines 2 | 3 | The DIP Ideas and DIP Development forums facilitate feedback for D Improvement Proposals (DIPs) from the D community and language maintainers. These forums have stricter moderation than standard D forums. 4 | 5 | Posts violating these guidelines may be deleted without warning. Our aim is to maintain focused, purposeful discussions. 6 | 7 | Guidelines may change as needed. 8 | 9 | ## DIP Ideas 10 | This forum is for floating new DIP ideas or seeking authors to develop them. 11 | 12 | Rules for new threads: 13 | 14 | 1. Focus on a new DIP idea or a variation of an existing one. 15 | 2. Provide a detailed description of the idea within the post for informed feedback. Links for additional context are acceptable. 16 | 3. Titles should clearly state the core idea, avoiding unnecessary words. For example, use "A variation on sumtypes" or "Tuples v2" instead of vague titles like "Looking for feedback" or "What do you think about this tuple idea?". 17 | 18 | ## DIP Development 19 | This forum is for discussing drafts of DIPs. 20 | 21 | Rules for new threads: 22 | 23 | 1. Focus on a specific draft of a DIP (e.g., first draft, second draft). 24 | 2. Include a permanent GitHub link to the draft under discussion. 25 | 3. For the first draft, summarize the DIP; for subsequent drafts, summarize revisions. 26 | 4. Format titles as "First|Second|Third|N Draft: DIP Title", like "First Draft: Tuples". 27 | 28 | ## Feedback 29 | Feedback in both forums must: 30 | 31 | 1. Be on-topic, relating directly to the DIP idea or draft. 32 | 2. Be respectful and constructive. 33 | 3. Provide context and useful information. Avoid short, contextless remarks like "LGTM" or "Thumbs up!" Explain your reasoning. 34 | 35 | In the DIP Ideas forum, there is more leeway for off-topic discussion to refine ideas. 36 | 37 | In the DIP Development forum, feedback should be actionable, helping authors refine their proposals. Express opinions on a feature in the DIP Ideas forum; provide constructive improvement suggestions in the DIP Development forum. 38 | -------------------------------------------------------------------------------- /docs/process-authoring.md: -------------------------------------------------------------------------------- 1 | # The DIP Authoring Process 2 | 3 | Anyone interested in enhancing the D programming language is welcome to submit a D Improvement Proposal (DIP). Prior to starting your DIP, familiarize yourself with the goals of the DIP process and read [the DIP Guidelines](./guidelines-authors.md). 4 | 5 | This document outlines the responsibilities of a DIP author. 6 | 7 | ## When to Write a DIP 8 | 9 | Consider writing a DIP for: 10 | 11 | - Changes to the language, including syntax and semantics. 12 | - Modifications to the functional behavior of code generated by the compiler. 13 | 14 | Assess the full impact of your proposed change; even minor modifications can have far-reaching effects. 15 | 16 | ## Step 1 - The DIP Ideas Forum 17 | 18 | Begin by seeking community feedback in the DIP Ideas forum. Your post should detail your proposal, enabling informed feedback. Submissions must be self-contained, but links for additional context are acceptable. Refer to the [DIP Forum Guidelines] for more information. 19 | 20 | Goals of this step: 21 | 22 | 1. Gauge the proposal's feasibility based on community and maintainer feedback. 23 | 2. Identify potential flaws and gather useful information for crafting your DIP. 24 | 25 | Allow two to three weeks for discussion before proceeding. The feedback should inform your decision to continue and assist in preparing a robust initial draft. 26 | 27 | ## Step 2 - Notify the DIP Manager 28 | 29 | If you decide to move forward, please notify the DIP manager via social@dlang.org of your intent. The DIP manager will ensure that the language maintainers have provided initial feedback in the idea forum. Their feedback may impact your decision to move forward. For example, you might choose not to spend time on a DIP if their feedback is negative. 30 | 31 | ## Step 3 - Fork the DIP Repository 32 | 33 | The primary author should fork the [DIP repository], creating a file in the `DIPs` subdirectory named `1NNN-(POC initials).md`, e.g., `1NNN-JQC.md`. 34 | 35 | ## Step 4 - Develop the DIP 36 | 37 | Develop your DIP according to the [DIP Template], without altering the heading order. Add subheadings as needed and complete all "Required" sections. 38 | 39 | Do not submit a pull request at this stage. When ready, post a link to your draft in the DIP Development forum. Ensure the link points to a specific revision of your DIP. Allow two to three weeks for feedback, and revise your DIP as needed. 40 | 41 | ## Step 5 - Submission for Formal Assessment 42 | 43 | After feedback, the POC may contact the DIP manager for formal evaluation. If significant revisions have been made since the last feedback round, additional forum feedback may be required. Otherwise, the DIP manager will ask you to submit your DIP as a pull request to the [DIP Repository]. 44 | 45 | The DIP manager will assign a number and rename the file upon merging. Submission timing is at the discretion of the author(s)/POC, but ensure availability to respond to queries during the assessment period. 46 | 47 | ## Step 6 - Formal Assessment 48 | 49 | Language maintainers typically review a DIP within two weeks of notification. The DIP manager will coordinate with maintainers for any necessary deadline extensions and inform the POC. 50 | 51 | Maintainers may request minor revisions for clarity or parameter adjustments. The DIP manager will specify mandatory and optional revisions. Prompt response to revision requests is crucial, as failure to comply can lead to rejection or indefinite postponement of the decision. 52 | 53 | [DIP Repository]: https://github.com/dlang/DIPs 54 | [DIP Template]: https://github.com/dlang/DIPs/blob/master/Template.md 55 | [DIP Forum Guidelines]: ./guidelines-forums.md 56 | -------------------------------------------------------------------------------- /tools/dwikiquery/dub.sdl: -------------------------------------------------------------------------------- 1 | name "dwikiquery" 2 | description "Wrapper for Mediawiki API backing wiki.dlang.org" 3 | authors "Михаил Страшун" 4 | copyright "Copyright © 2016, Михаил Страшун" 5 | license "Boost" 6 | dependency "vibe-d" version="==0.7.30-alpha.2" 7 | -------------------------------------------------------------------------------- /tools/dwikiquery/source/app.d: -------------------------------------------------------------------------------- 1 | import std.format : format; 2 | import std.exception : enforce; 3 | 4 | enum CommandVerbs 5 | { 6 | /// Attempts to load DIP source, convert it to markdown and write 7 | /// result to disk in a current folder. Example: 8 | /// dwikiquery fetch --id 42 9 | fetch 10 | } 11 | 12 | void main(string[] args) 13 | { 14 | { 15 | import std.process; 16 | enforce( 17 | executeShell("pandoc -v").status == 0, 18 | "pandoc (http://pandoc.org) must be on PATH" 19 | ); 20 | } 21 | 22 | ulong id; 23 | 24 | import std.getopt; 25 | 26 | auto optinfo = getopt( 27 | args, 28 | "id", "DIP number", &id 29 | ); 30 | 31 | string verb = args[1]; 32 | 33 | import std.conv : to; 34 | 35 | final switch (to!CommandVerbs(verb)) 36 | { 37 | case CommandVerbs.fetch: 38 | enforce(id > 0, "Must specify DIP id to fetch"); 39 | string source = preProcess(getDIPfromWiki(id)); 40 | toMarkdownFile(source, id); 41 | break; 42 | } 43 | } 44 | 45 | /** 46 | Fetches DIP source text using Mediawiki API 47 | 48 | Params: 49 | ID of a DIP such that wiki.dlang.org/DIP page contains 50 | current text of the DIP. 51 | 52 | Returns: 53 | Text of DIP wiki page in Mediawiki format 54 | */ 55 | string getDIPfromWiki(ulong id) 56 | { 57 | import vibe.data.json; 58 | import vibe.http.client; 59 | 60 | string api_url = format( 61 | "https://wiki.dlang.org/api.php?format=json&action=query&prop=revisions&rvprop=content&titles=DIP%s", 62 | id 63 | ); 64 | 65 | string wikitext; 66 | 67 | requestHTTP( 68 | api_url, 69 | (scope req) { }, 70 | (scope res) { 71 | auto json = res.readJson(); 72 | json = json["query"]["pages"]; 73 | // object key may vary but there will always be exactly one: 74 | enforce(json.length == 1); 75 | foreach (page; json) 76 | { 77 | enforce(page["revisions"].length == 1); 78 | wikitext = page["revisions"][0]["*"].get!string(); 79 | } 80 | } 81 | ); 82 | 83 | return wikitext; 84 | } 85 | 86 | /** 87 | Does some pre-processing of downloaded mediwiki sources to 88 | prepare those for pandoc conversion. 89 | 90 | Params: 91 | original downloaded mediawiki source 92 | 93 | Returns: 94 | same source adjusted for better conversion results 95 | */ 96 | string preProcess ( string source ) 97 | { 98 | import std.regex; 99 | import std.algorithm; 100 | import std.range; 101 | 102 | // remove category link 103 | static rgx_category = regex(r"\[Category: DIP\]", "s"); 104 | 105 | source = source 106 | .splitter('\n') 107 | .filter!(line => !line.matchFirst(rgx_category)) 108 | .join('\n'); 109 | 110 | return source; 111 | } 112 | 113 | /** 114 | Does some post-processing on converted sources to make resulting markdown 115 | Github-compatible 116 | 117 | Params: 118 | converted = pandoc conversion output 119 | 120 | Returns: 121 | final markdown source 122 | */ 123 | string postProcess ( string converted ) 124 | { 125 | import std.regex; 126 | import std.algorithm; 127 | import std.range; 128 | 129 | /// fix code blocks 130 | static rgx_codeblock = regex(r"``` \{\.d\}", "si"); 131 | 132 | converted = converted 133 | .splitter('\n') 134 | .map!(line => line.replaceAll(rgx_codeblock, "```d")) 135 | .join('\n'); 136 | 137 | return converted; 138 | } 139 | 140 | /** 141 | Converts mediawiki source to markdown (using pandoc shell call) and writes 142 | resulting text to a file in current folder named "DIP.md". 143 | 144 | Params: 145 | wikitext = Mediawiki formatted DIP source text 146 | id = DIP number 147 | */ 148 | void toMarkdownFile(string wikitext, ulong id) 149 | { 150 | import std.process; 151 | 152 | auto pandoc = pipeShell( 153 | format("pandoc -t markdown_github -f mediawiki -o DIP%s.md", id) 154 | ); 155 | pandoc.stdin.write(wikitext); 156 | pandoc.stdin.flush(); 157 | pandoc.stdin.close(); 158 | wait(pandoc.pid); 159 | } 160 | -------------------------------------------------------------------------------- /tools/genoverview/dub.sdl: -------------------------------------------------------------------------------- 1 | name "genoverview" 2 | description "Overview page generator for DIPs" 3 | license "Boost" 4 | -------------------------------------------------------------------------------- /tools/genoverview/source/app.d: -------------------------------------------------------------------------------- 1 | import metadata; 2 | 3 | version (unittest) { } else 4 | void main ( string[] args ) 5 | { 6 | import std.string; 7 | 8 | string dipFolder; 9 | 10 | if (args.length == 1) 11 | dipFolder = "./DIPs"; 12 | else 13 | dipFolder = args[1 .. $].join(); 14 | 15 | import std.format; 16 | 17 | import std.path, std.file, std.utf; 18 | 19 | DIPMetadata[] DIPs; 20 | 21 | foreach (entry; dirEntries(dipFolder, "DIP*.md", SpanMode.shallow)) 22 | { 23 | auto contents = cast(string) read(entry.name); 24 | validate(contents); 25 | DIPs ~= DIPMetadata.fromAA(parseFirstMdTable(contents)); 26 | } 27 | 28 | import std.algorithm : sort; 29 | 30 | static bool sortPredicate ( DIPMetadata a, DIPMetadata b ) 31 | { 32 | if (a.status == b.status) 33 | return a.id < b.id; 34 | else 35 | return a.status < b.status; 36 | } 37 | 38 | sort!sortPredicate(DIPs); 39 | writeSummary(DIPs, buildNormalizedPath(dipFolder, "README.md")); 40 | } 41 | 42 | /** 43 | Extracts metadata from DIP markdown sources. 44 | 45 | Looks for markdown resembling table lines and parses first table 46 | column as key and second as value. 47 | 48 | Params: 49 | source = markdown source to parse 50 | 51 | Returns: 52 | Associative array storing key-value mapping from found table lines 53 | */ 54 | string[string] parseFirstMdTable ( string source ) 55 | { 56 | import std.regex; 57 | import std.string : strip; 58 | 59 | typeof(return) result; 60 | 61 | static title = regex(r"^# (.+)$", "mg"); 62 | auto title_match = source.matchFirst(title); 63 | if (!title_match.empty) 64 | result["Title"] = strip(title_match[1]); 65 | 66 | static lines = regex(r"^\|\s*(\w+):\s*\|(.+)\|$", "mg"); 67 | 68 | foreach (match; source.matchAll(lines)) 69 | result[match[1]] = strip(match[2]); 70 | 71 | return result; 72 | } 73 | 74 | unittest 75 | { 76 | string input = 77 | ` 78 | # Volatile read/write intrinsics 79 | | Section | Value | 80 | |----------------|------------------------------------------------------------------------------------------------------------------------------------------------| 81 | | DIP: | 20 | 82 | | Status: | Implemented | 83 | | Links: | [proposed implementation](https://issues.dlang.org/show_bug.cgi?id=13138), [pull](https://github.com/D-Programming-Language/druntime/pull/892) | 84 | `; 85 | 86 | auto metadata = parseFirstMdTable(input); 87 | assert(metadata["Title"] == "Volatile read/write intrinsics"); 88 | assert(metadata["DIP"] == "20"); 89 | assert(metadata["Status"] == "Implemented"); 90 | } 91 | 92 | /** 93 | */ 94 | void writeSummary ( DIPMetadata[] DIPs, string fileName ) 95 | { 96 | import std.uni : byGrapheme; 97 | import std.range : walkLength; 98 | import std.conv, std.format; 99 | 100 | static struct ColumnWidths 101 | { 102 | size_t id, title, status; 103 | } 104 | 105 | ColumnWidths widths; 106 | 107 | void updateMax ( ref size_t max_width, string next ) 108 | { 109 | auto next_width = next.byGrapheme.walkLength; 110 | if (next_width > max_width) 111 | max_width = next_width; 112 | } 113 | 114 | foreach (dip; DIPs) 115 | { 116 | updateMax(widths.id, format("[%s](./DIP%1$s.md)", dip.id)); 117 | updateMax(widths.title, dip.title); 118 | updateMax(widths.status, to!string(dip.status)); 119 | } 120 | 121 | import std.stdio; 122 | import std.range : repeat; 123 | 124 | auto output = File(fileName, "w"); 125 | 126 | auto lineFormat = format("|%%%ss|%%%ss|%%%ss|", 127 | widths.id, widths.title, widths.status); 128 | 129 | output.writefln(lineFormat, "ID", "Title", "Status"); 130 | output.writefln( 131 | lineFormat, 132 | '-'.repeat(widths.id), 133 | '-'.repeat(widths.title), 134 | '-'.repeat(widths.status) 135 | ); 136 | 137 | foreach (dip; DIPs) 138 | output.writefln(lineFormat, format("[%1$s](./DIP%1$s.md)", dip.id), 139 | dip.title, dip.status); 140 | } 141 | -------------------------------------------------------------------------------- /tools/genoverview/source/metadata.d: -------------------------------------------------------------------------------- 1 | module metadata; 2 | 3 | struct Status 4 | { 5 | enum StatusEnum 6 | { 7 | Approved, 8 | PendingImplementation, 9 | InformationRequested, 10 | Draft, 11 | Implemented, 12 | Rejected, 13 | } 14 | 15 | StatusEnum value; 16 | alias value this; 17 | 18 | string toString ( ) 19 | { 20 | static import std.conv; 21 | 22 | if (value == Status.PendingImplementation) 23 | return "Pending Implementation"; 24 | else if (value == Status.InformationRequested) 25 | return "Information Requested"; 26 | else 27 | return std.conv.to!string(value); 28 | } 29 | 30 | static auto fromString ( string status ) 31 | { 32 | static import std.conv; 33 | 34 | if (status == "Pending Implementation") 35 | return Status.PendingImplementation; 36 | else if (status == "Information Requested") 37 | return Status.InformationRequested; 38 | else 39 | return std.conv.to!StatusEnum(status); 40 | } 41 | } 42 | 43 | struct DIPMetadata 44 | { 45 | size_t id; 46 | string title; 47 | Status status; 48 | 49 | string author; 50 | 51 | static DIPMetadata fromAA ( string[string] kv ) 52 | { 53 | import std.conv; 54 | 55 | DIPMetadata metadata; 56 | metadata.id = to!size_t(kv["DIP"]); 57 | metadata.title = kv["Title"]; 58 | metadata.author = kv["Author"]; 59 | metadata.status = Status.fromString(kv["Status"]); 60 | return metadata; 61 | } 62 | } 63 | --------------------------------------------------------------------------------