Difference between revisions of "Language issues"
(→Null References: Add summary) |
(→Attribute creep: Mention inference and split out method type constructors as they DON'T apply to return type!) |
||
(16 intermediate revisions by 5 users not shown) | |||
Line 32: | Line 32: | ||
* [http://forum.dlang.org/post/lfbbcn$2th7$1@digitalmars.com March 2014 discussion] | * [http://forum.dlang.org/post/lfbbcn$2th7$1@digitalmars.com March 2014 discussion] | ||
* [https://github.com/D-Programming-Language/phobos/pull/2423 Related discussion in pull request "add range version of setExtension"] | * [https://github.com/D-Programming-Language/phobos/pull/2423 Related discussion in pull request "add range version of setExtension"] | ||
+ | * [http://jackstouffer.com/blog/d_auto_decoding_and_you.html D's Auto Decoding and You] | ||
+ | * [http://forum.dlang.org/post/nh2o9i$hr0$1@digitalmars.com The Case against Autodecode] - NG discussion in May 2016 | ||
+ | |||
+ | === std2 === | ||
+ | |||
+ | Auto-decoding will be removed in Phobos V2: | ||
+ | https://forum.dlang.org/thread/sl7l32$1umj$1@digitalmars.com | ||
+ | |||
+ | Phobos 2 would allow importing certain modules from V2 whilst continuing to use other V1 modules. | ||
== Attribute creep == | == Attribute creep == | ||
Line 50: | Line 59: | ||
* [http://dlang.org/attribute.html#disable <tt>@disable</tt>] | * [http://dlang.org/attribute.html#disable <tt>@disable</tt>] | ||
* [http://dlang.org/attribute.html#deprecated <tt>deprecated</tt>] | * [http://dlang.org/attribute.html#deprecated <tt>deprecated</tt>] | ||
+ | * [[DIP25 | <tt>return</tt>]] | ||
+ | |||
+ | Note that attributes such as @nogc, nothrow, pure, @safe and scope can be inferred for template functions, function literals and auto-return functions. | ||
− | Additionally, function return types can be or be annotated with the following | + | Additionally, function return types can be or be annotated with the following storage classes: |
* [http://dlang.org/function.html#auto-functions <tt>auto</tt>] | * [http://dlang.org/function.html#auto-functions <tt>auto</tt>] | ||
* [http://dlang.org/function.html#ref-functions <tt>ref</tt>] | * [http://dlang.org/function.html#ref-functions <tt>ref</tt>] | ||
+ | |||
+ | Methods can be annotated with the following type constructors: | ||
* [http://dlang.org/const3.html <tt>const</tt> / <tt>immutable</tt>] / [http://dlang.org/function.html#inout-functions <tt>inout</tt>] | * [http://dlang.org/const3.html <tt>const</tt> / <tt>immutable</tt>] / [http://dlang.org/function.html#inout-functions <tt>inout</tt>] | ||
* [http://dlang.org/attribute.html#shared <tt>shared</tt>] | * [http://dlang.org/attribute.html#shared <tt>shared</tt>] | ||
Line 60: | Line 74: | ||
== Signed/unsigned comparisons == | == Signed/unsigned comparisons == | ||
− | ( | + | Currently, the following code fails: |
+ | |||
+ | <syntaxhighlight lang="d"> | ||
+ | uint i = 1; | ||
+ | assert(i > -2); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <tt>i > -2</tt> evaluates to <tt>false</tt> due to C compatibility (the same expression also evaluates to <tt>false</tt> in C, and one of D's goals is that if any C code compiles in D, then it should act like in C). One proposal is to make signed/unsigned comparisons generate a warning. | ||
+ | |||
+ | See [https://d.puremagic.com/issues/show_bug.cgi?id=259 issue 259] for discussion. | ||
== Null References == | == Null References == | ||
Line 70: | Line 93: | ||
* [http://forum.dlang.org/post/vhtcmmnihixpmaqtakmg@forum.dlang.org September 2012 discussion] | * [http://forum.dlang.org/post/vhtcmmnihixpmaqtakmg@forum.dlang.org September 2012 discussion] | ||
* [http://d.puremagic.com/issues/show_bug.cgi?id=4595 Issue 4595 - <nowiki>[tdpl]</nowiki> Accessing non-static member of a null reference compiles] | * [http://d.puremagic.com/issues/show_bug.cgi?id=4595 Issue 4595 - <nowiki>[tdpl]</nowiki> Accessing non-static member of a null reference compiles] | ||
+ | |||
+ | == Arrays in boolean context == | ||
+ | Dynamic array variables in boolean context (e.g. when encountered in an <code>if</code> condition by themselves) are considered equivalent to their <code>.ptr</code> property. It has been argued they should instead use their <code>.length</code> property, so that empty (but not null) arrays evaluate as <code>false</code>. See [https://issues.dlang.org/show_bug.cgi?id=4733 Issue 4733 - Possible bugs caused by dynamic arrays in boolean evaluation context] and related pull requests. | ||
== Virtual by default == | == Virtual by default == | ||
Line 75: | Line 101: | ||
In D, methods are virtual by default. Although this approach does have benefits from the point of view of extensibility, it has been criticized that this default incurs a considerable performance impact and harms forward compatibility in user code, unless explicitly disabled everywhere as appropriate using the <tt>final</tt> keyword. | In D, methods are virtual by default. Although this approach does have benefits from the point of view of extensibility, it has been criticized that this default incurs a considerable performance impact and harms forward compatibility in user code, unless explicitly disabled everywhere as appropriate using the <tt>final</tt> keyword. | ||
− | Although at one point Walter Bright intended to change the default (see [https://d.puremagic.com/issues/show_bug.cgi?id=11616 Issue 11616] and [[DIP51]]), ultimately this proposal [http://forum.dlang.org/post/ | + | Although at one point Walter Bright [http://forum.dlang.org/post/lfqoan$5qq$1@digitalmars.com intended] to change the default (see [https://d.puremagic.com/issues/show_bug.cgi?id=11616 Issue 11616] and [[DIP51]]), ultimately this proposal [http://forum.dlang.org/post/lfrdst$oav$1@digitalmars.com has been rejected]. |
== Default constructors == | == Default constructors == | ||
Line 82: | Line 108: | ||
D's restriction prevents implementing certain C++ patterns, and requires users to rely on conventions for factory functions. | D's restriction prevents implementing certain C++ patterns, and requires users to rely on conventions for factory functions. | ||
+ | |||
+ | === Advantages of <tt>.init</tt> === | ||
+ | |||
+ | [http://forum.dlang.org/post/m18aku$2q7e$1@digitalmars.com According to Walter Bright], some advantages of <tt>.init</tt> over default constructors are: | ||
+ | |||
+ | # the default object is trivially constructable and cannot fail (for nested struct <code>.init</code> contains null context pointer, use default constructor instead) | ||
+ | # an easy way for other constructors to not have overlooked field initializers, so they get garbage initialized like in C++ | ||
+ | # generic code can rely on the existence of trivial construction that cannot fail | ||
+ | # dummy objects can be created, useful for "does this compile" semantics | ||
+ | # an object can be "destroyed" by overwriting it with .init (overwriting with 0 is not the same thing) | ||
+ | # when you see: <tt>T t;</tt> in code, you know it is trivially constructed and will succeed | ||
+ | # objects can be created using <tt>TypeInfo</tt> | ||
+ | |||
+ | Notes: | ||
+ | * (4) can be done with a function literal: <tt>(T v) { ... }</tt>. This works even when T has <tt>@disable this</tt>. | ||
+ | * (5) can be done with <tt>obj.move;</tt>. | ||
+ | |||
+ | |||
+ | === Explicit syntax and <tt>@disable this</tt> === | ||
+ | |||
+ | In theory, explicit struct construction syntax <tt>S s = S();</tt> could allow calling a zero-argument constructor (vs. just <tt>S s;</tt> which is default construction). Forgetting to use the explicit syntax can be solved by disabling the default constructor (<tt>@disable this;</tt>). | ||
+ | |||
+ | See also: | ||
+ | * [http://forum.dlang.org/post/li3n8n$7ci$1@digitalmars.com April 2014 discussion] | ||
+ | * [http://forum.dlang.org/post/k8ti2b$1iqj$1@digitalmars.com November 2012 discussion] (note we do now support <tt>int(2)</tt> syntax) | ||
== Memory management == | == Memory management == | ||
− | D is often criticized for its | + | D is often criticized for its usage of garbage collection, and the quality of the current GC implementation. |
− | The | + | The default GC implementation is: |
* conservative (meaning, it can't guarantee whether any object actually has live references to it) | * conservative (meaning, it can't guarantee whether any object actually has live references to it) | ||
Line 93: | Line 144: | ||
* stop-the-world (all threads are stopped during a GC scan) | * stop-the-world (all threads are stopped during a GC scan) | ||
− | + | Note: The GC only runs when a GC memory allocation is made. | |
− | |||
− | |||
− | Although | + | Built-in alternatives: |
+ | |||
+ | * Precise GC is available as an option: https://dlang.org/spec/garbage.html#precise_gc. | ||
+ | * A concurrent <tt>fork</tt>-based GC is available on *nix systems: https://dlang.org/blog/2019/07/22/symmetry-autumn-of-code-experience-report-porting-a-fork-based-gc/. | ||
+ | |||
+ | Although GC collections can [https://dlang.org/phobos/core_memory.html#.GC.disable easily be disabled, re-enabled and run manually], using D completely without the GC may be challenging, as some features of D make GC allocations: | ||
* Many modules in Phobos, D's standard library, expect a GC to be present to clean up temporary allocations; | * Many modules in Phobos, D's standard library, expect a GC to be present to clean up temporary allocations; | ||
− | * D language features such as arrays require careful use to avoid memory leaks; | + | * D language features such as dynamic arrays require careful use to avoid memory leaks; |
− | * D language features such as closures and exceptions cannot be used, as they do not provide a way to manually deallocate allocated memory. | + | * D language features such as closures and heap exceptions cannot be used, as they do not provide a way to manually deallocate allocated memory. |
+ | |||
+ | Note that <tt>@nogc</tt> can be used to statically check no GC allocations are made: https://dlang.org/spec/function.html#nogc-functions. | ||
Some alternative runtimes / standard libraries which do not rely on the GC are listed [[Libraries_and_Frameworks#Alternative_standard_libraries_.2F_runtimes|here]]. | Some alternative runtimes / standard libraries which do not rely on the GC are listed [[Libraries_and_Frameworks#Alternative_standard_libraries_.2F_runtimes|here]]. |
Latest revision as of 12:20, 22 September 2022
Like any programming language, D is not perfect. This page lists some potential problems that have been brought up and debated throughout the language's history. Fixing these is not straight-forward or may not justify breaking backwards-compatibility. As of the moment of writing this, there are no plans for a major revision of D which would allow such breaking changes, but this list may also be useful for other programming languages which wish to learn from D's experience.
See also: Language design discussions
Contents
Properties
Design of properties has been an oft-discussed topic. This language feature has evolved throughout D's history (e.g. the addition and removal of the -property switch). There are numerous DIPs with proposals on improving the design:
See also:
Unicode and ranges
D's ranges currently treat strings in a special way: they present them as a range of code points, thus implicitly performing UTF decoding. Algorithms that do not require working with decoded code points, and which would gain a performance advantage by treating the input as a range of code units (or an array of code units), must incorporate D strings as a special case. This approach complicates the implementation by some degree, and only solves a certain subset of problems for a subset of written languages.
Walter Bright has mentioned that auto-decoding is his #1 thing he currently dislikes about D [1] [2].
See also:
- Element type of string ranges
- March 2014 discussion
- Related discussion in pull request "add range version of setExtension"
- D's Auto Decoding and You
- The Case against Autodecode - NG discussion in May 2016
std2
Auto-decoding will be removed in Phobos V2: https://forum.dlang.org/thread/sl7l32$1umj$1@digitalmars.com
Phobos 2 would allow importing certain modules from V2 whilst continuing to use other V1 modules.
Attribute creep
In a 2014 forum thread titled "What are the worst parts of D?", a prevalent complaint was the number of attributes that functions can be decorated with.
D currently allows the following attributes:
- override / final / abstract
- extern
- @property
- const / immutable / inout
- shared
- @safe / @trusted / @system
- pure
- nothrow
- @nogc
- @disable
- deprecated
- return
Note that attributes such as @nogc, nothrow, pure, @safe and scope can be inferred for template functions, function literals and auto-return functions.
Additionally, function return types can be or be annotated with the following storage classes:
Methods can be annotated with the following type constructors:
Signed/unsigned comparisons
Currently, the following code fails:
uint i = 1;
assert(i > -2);
i > -2 evaluates to false due to C compatibility (the same expression also evaluates to false in C, and one of D's goals is that if any C code compiles in D, then it should act like in C). One proposal is to make signed/unsigned comparisons generate a warning.
See issue 259 for discussion.
Null References
Null references have often been blamed as a common class of bugs, which could be prevented statically by the compiler (e.g. as a NotNull modifier, or explicitly marking variables possibly containing null values). This can be done by statically checking if all code paths (e.g. all class constructors) initialize a reference variable to a non-null value.
See also:
- February 2014 discussion
- September 2012 discussion
- Issue 4595 - [tdpl] Accessing non-static member of a null reference compiles
Arrays in boolean context
Dynamic array variables in boolean context (e.g. when encountered in an if
condition by themselves) are considered equivalent to their .ptr
property. It has been argued they should instead use their .length
property, so that empty (but not null) arrays evaluate as false
. See Issue 4733 - Possible bugs caused by dynamic arrays in boolean evaluation context and related pull requests.
Virtual by default
In D, methods are virtual by default. Although this approach does have benefits from the point of view of extensibility, it has been criticized that this default incurs a considerable performance impact and harms forward compatibility in user code, unless explicitly disabled everywhere as appropriate using the final keyword.
Although at one point Walter Bright intended to change the default (see Issue 11616 and DIP51), ultimately this proposal has been rejected.
Default constructors
D does not support custom default constructors for value types: attempting to declare a struct constructor without any arguments is an error. The rationale for this limitation is to allow any type to have a known constant default value (.init property). This is unlike C++, where structs and classes can have default constructors, which allow executing custom code at the point of a variable's declaration.
D's restriction prevents implementing certain C++ patterns, and requires users to rely on conventions for factory functions.
Advantages of .init
According to Walter Bright, some advantages of .init over default constructors are:
- the default object is trivially constructable and cannot fail (for nested struct
.init
contains null context pointer, use default constructor instead) - an easy way for other constructors to not have overlooked field initializers, so they get garbage initialized like in C++
- generic code can rely on the existence of trivial construction that cannot fail
- dummy objects can be created, useful for "does this compile" semantics
- an object can be "destroyed" by overwriting it with .init (overwriting with 0 is not the same thing)
- when you see: T t; in code, you know it is trivially constructed and will succeed
- objects can be created using TypeInfo
Notes:
- (4) can be done with a function literal: (T v) { ... }. This works even when T has @disable this.
- (5) can be done with obj.move;.
Explicit syntax and @disable this
In theory, explicit struct construction syntax S s = S(); could allow calling a zero-argument constructor (vs. just S s; which is default construction). Forgetting to use the explicit syntax can be solved by disabling the default constructor (@disable this;).
See also:
- April 2014 discussion
- November 2012 discussion (note we do now support int(2) syntax)
Memory management
D is often criticized for its usage of garbage collection, and the quality of the current GC implementation.
The default GC implementation is:
- conservative (meaning, it can't guarantee whether any object actually has live references to it)
- non-moving (the GC doesn't attempt to compact the heap to reduce fragmentation and working set size)
- stop-the-world (all threads are stopped during a GC scan)
Note: The GC only runs when a GC memory allocation is made.
Built-in alternatives:
- Precise GC is available as an option: https://dlang.org/spec/garbage.html#precise_gc.
- A concurrent fork-based GC is available on *nix systems: https://dlang.org/blog/2019/07/22/symmetry-autumn-of-code-experience-report-porting-a-fork-based-gc/.
Although GC collections can easily be disabled, re-enabled and run manually, using D completely without the GC may be challenging, as some features of D make GC allocations:
- Many modules in Phobos, D's standard library, expect a GC to be present to clean up temporary allocations;
- D language features such as dynamic arrays require careful use to avoid memory leaks;
- D language features such as closures and heap exceptions cannot be used, as they do not provide a way to manually deallocate allocated memory.
Note that @nogc can be used to statically check no GC allocations are made: https://dlang.org/spec/function.html#nogc-functions.
Some alternative runtimes / standard libraries which do not rely on the GC are listed here.