Difference between revisions of "Language Designs Explained"
Marler8997 (talk | contribs) |
m (Fix typo) |
||
(12 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
− | + | == Function attributes == | |
=== Why do some function attributes have an '@' and some don't? === | === Why do some function attributes have an '@' and some don't? === | ||
Line 12: | Line 12: | ||
=== Why are some function attributes keywords and some not? === | === Why are some function attributes keywords and some not? === | ||
− | Originally, all | + | Originally, all function attributes were also keywords, like <code>pure</code> and <code>nothrow</code>. Eventually, new features were added to the language that required new function attributes. However, making the new attributes into keywords would have fundamentally changed the syntax of the language and would result in breaking existing code. So instead of making these new attributes keywords, a decision was made to allow function attributes to be used that were not keywords so long as an '@' character was used. This allowed new function attributes to be added without breaking existing code. The disadvantage of this was that now a function with both kinds of attributes looks a bit odd, i.e. |
<syntaxhighlight lang="D">void foo() @safe pure @nogc nothrow;</syntaxhighlight> | <syntaxhighlight lang="D">void foo() @safe pure @nogc nothrow;</syntaxhighlight> | ||
Line 20: | Line 20: | ||
<syntaxhighlight lang="D">int safe = 0; // This code would break if "safe" was added as a keyword</syntaxhighlight> | <syntaxhighlight lang="D">int safe = 0; // This code would break if "safe" was added as a keyword</syntaxhighlight> | ||
− | === Why do non-keyword attributes like safe and nogc require | + | === Why do non-keyword attributes like safe and nogc require an '@' character? === |
− | Supporting non-keyword attributes without requiring an '@' character would remove redundancy in the language. Redundancy in a language helps | + | Supporting non-keyword attributes without requiring an '@' character would remove redundancy in the language. Redundancy in a language helps: |
* compilers give better error messages | * compilers give better error messages | ||
Line 37: | Line 37: | ||
<code>Error: expected ';' or '{' after function declaration, not '='</code> | <code>Error: expected ';' or '{' after function declaration, not '='</code> | ||
+ | |||
+ | === Why don't we create a special rule in the syntax to handle non-keyword function attributes without an '@' character? === | ||
+ | |||
+ | The idea would be to add a new grammar rule for function attributes like this: | ||
+ | |||
+ | <code><function-attribute> => <keyword> | "@" <identifier> | "safe" | "nogc" | ...</code> | ||
+ | |||
+ | This would allow a function to have attributes that are not keywords at the expense of syntax complexity. This solves the problem of redundancy, however, it is unknown whether or not this would make the grammar of the language ambiguous. If the function attributes were restricted to appear on the right hand side of a function signature (after the parameters), then this may solve the ambiguity problem. The other concern would be that this would complicate the syntax. The compiler and every syntax highlighter would need to handle this special case which can seem like a hack. In addition, this may seem confusing to some people. If a word is used as a function attribute, they may assume it is also a keyword, and if someone were to use it as an identifier this may be confusing. This would also create inconsistency with the brace and colon syntax: | ||
+ | <syntaxhighlight lang="D"> | ||
+ | void foo1() safe; | ||
+ | @safe { | ||
+ | void foo2(); | ||
+ | } | ||
+ | @safe: | ||
+ | void foo3(); | ||
+ | </syntaxhighlight > | ||
+ | |||
+ | These examples all apply the "safe" attribute to their respective function, but now some use an '@' and some don't. | ||
=== Why don't we just allow an '@' character on all function attributes so it looks consistent? === | === Why don't we just allow an '@' character on all function attributes so it looks consistent? === | ||
− | To appreciate the answer for this remember that the original problem is a matter of consistency. It's inconsistent that some function attributes use an '@' character and some don't. If D supported putting an '@' character on the function attributes that are also keywords, then this moves the | + | To appreciate the answer for this remember that the original problem is a matter of consistency. It's inconsistent that some function attributes use an '@' character and some don't. If D supported putting an '@' character on the function attributes that are also keywords, then this moves the inconsistency somewhere else. Since keywords are re-used all over the place, some instances of the keyword will require an '@' and some will not, i.e. |
<syntaxhighlight lang="D"> | <syntaxhighlight lang="D"> | ||
Line 47: | Line 65: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | See the inconsistency? Then you might say, let's make some attributes require an '@' and some not, but how does that solve the original problem? You've just moved some keywords into the '@' bin and some into the "no @' bin. Even worse, you've now made the rule more complex. The current rule is "Use an '@' symbol if the word is not a keyword". Now the rule is "Use an '@' symbol | + | See the inconsistency? Then you might say, let's make some attributes require an '@' and some not, but how does that solve the original problem? You've just moved some keywords into the '@' bin and some into the "no @' bin. Even worse, you've now made the rule more complex. The current rule is "Use an '@' symbol if the word is not a keyword". Now the rule is "Use an '@' symbol if the word not a keyword, except when you are using the keyword as ...". When the alternatives are considered, the simple rule is not that bad of an option. |
+ | |||
+ | === Why wasn't nogc made a keyword? === | ||
+ | |||
+ | Ideally, if the language were designed from scratch, <code>nogc</code> ''would'' be made a keyword. However, since the language has been around for a while, it is deemed undesirable to introduce new keywords. The reason is that before <code>nogc</code> was introduced, some existing code may have used identifiers called <code>nogc</code>; if it were suddenly regarded as a keyword now, that code would no longer compile, and the author would need to revise all parts of the code that used that identifier. | ||
+ | |||
+ | == Operators == | ||
+ | |||
+ | === Why does D not support chaining comparison operators? === | ||
+ | |||
+ | First off, what are chaining comparison operators? The term refers to a certain way that comparison operators behave in various languages, which allows for writing multiple comparisons without using logical '''and''' between them. Chaining comparison operators are popular in more dynamic languages like Python or Perl, and also provide a slight performance benefit as the middle value only needs to be evaluated once. | ||
+ | |||
+ | Example: | ||
+ | <syntaxhighlight lang="Python"> | ||
+ | age = 25 | ||
+ | |||
+ | if 18 < age <= 25: | ||
+ | print('Chained comparison!') | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The equivalent C code would be: | ||
+ | <syntaxhighlight lang="C"> | ||
+ | int age = 25; | ||
+ | |||
+ | if (18 < age && age <= 25) | ||
+ | { | ||
+ | printf("No chaining here!"); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | So why does D not support this behaviour for comparison operators if it is more efficient, more concise, and more elegant than the equivalent C code? It is because D strives to be backwards-compatible with C wherever possible, and comparison operator chaining is not backwards-compatible with C. | ||
+ | |||
+ | While code like <code>18 < age <= 25</code> is valid C and will generally do what you want (at least in an if-statement), it is not the same as the Python code above. First <code>18 < age</code> is evaluated, producing 1 (C does not have the boolean type), which is then compared to 25, which just happens to be greater than 1. This is more evident when checking if two variables are equal to a third value: | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | int age1 = 25; | ||
+ | int age2 = 25; | ||
+ | |||
+ | if (age1 == age2 == 25) | ||
+ | { | ||
+ | printf("Something's fishy..."); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The above code will '''NOT''' print "Something's fishy...", as the expression <code>age1 == age2</code> produces 1, which is then compared to 25. Since 1 is not equal to 25 the whole expression evaluates to false and the if-statement will not execute. | ||
− | + | As was mentioned earlier, D strives to be backwards-compatible with C wherever possible. It was decided that while chaining comparison operators are somewhat desirable, it would be a bad idea to have a construct that is also valid C code but with subtly different semantics. The potential benefits were not worth the break in compatibility with C. | |
− | + | [[Category:Tutorials]] |
Latest revision as of 10:09, 8 June 2016
Contents
- 1 Function attributes
- 1.1 Why do some function attributes have an '@' and some don't?
- 1.2 Why are some function attributes keywords and some not?
- 1.3 Why do non-keyword attributes like safe and nogc require an '@' character?
- 1.4 Why don't we create a special rule in the syntax to handle non-keyword function attributes without an '@' character?
- 1.5 Why don't we just allow an '@' character on all function attributes so it looks consistent?
- 1.6 Why wasn't nogc made a keyword?
- 2 Operators
Function attributes
Why do some function attributes have an '@' and some don't?
A function attribute requires an '@' if and only if it is not a keyword. Since "pure" and "nothrow" are keywords, but "safe" and "nogc" are not, using them all together would look like this:
void foo() pure nothrow @safe @nogc;
A list of the current keywords are found here. This looks odd, however, we haven't come up with an idea we like to solve this. Read on to understand the potential solutions and the problems they create.
Why are some function attributes keywords and some not?
Originally, all function attributes were also keywords, like pure
and nothrow
. Eventually, new features were added to the language that required new function attributes. However, making the new attributes into keywords would have fundamentally changed the syntax of the language and would result in breaking existing code. So instead of making these new attributes keywords, a decision was made to allow function attributes to be used that were not keywords so long as an '@' character was used. This allowed new function attributes to be added without breaking existing code. The disadvantage of this was that now a function with both kinds of attributes looks a bit odd, i.e.
void foo() @safe pure @nogc nothrow;
Because of this, in the future some of these attributes may be added as keywords. However, doing so would result in breaking any code that previously used these words somewhere else such as a variable or function name. i.e.
int safe = 0; // This code would break if "safe" was added as a keyword
Why do non-keyword attributes like safe and nogc require an '@' character?
Supporting non-keyword attributes without requiring an '@' character would remove redundancy in the language. Redundancy in a language helps:
* compilers give better error messages * syntax highlighters when the code is under development or contains errors
The less redundancy a language has the more chances that one character change can propagate an error through the entire program. Consider the following example:
void func()
safe T = 7;
This is an error since the function definition is not finished. It should have ended with a semi-colon or a function body. If D allowed non-keyword function attributes, then "safe" and "T" would be considered attributes of the function by the parser and the error would not be found until the '=' character.
Error: expected ';' or '{' after function declaration, not '='
Why don't we create a special rule in the syntax to handle non-keyword function attributes without an '@' character?
The idea would be to add a new grammar rule for function attributes like this:
<function-attribute> => <keyword> | "@" <identifier> | "safe" | "nogc" | ...
This would allow a function to have attributes that are not keywords at the expense of syntax complexity. This solves the problem of redundancy, however, it is unknown whether or not this would make the grammar of the language ambiguous. If the function attributes were restricted to appear on the right hand side of a function signature (after the parameters), then this may solve the ambiguity problem. The other concern would be that this would complicate the syntax. The compiler and every syntax highlighter would need to handle this special case which can seem like a hack. In addition, this may seem confusing to some people. If a word is used as a function attribute, they may assume it is also a keyword, and if someone were to use it as an identifier this may be confusing. This would also create inconsistency with the brace and colon syntax:
void foo1() safe;
@safe {
void foo2();
}
@safe:
void foo3();
These examples all apply the "safe" attribute to their respective function, but now some use an '@' and some don't.
Why don't we just allow an '@' character on all function attributes so it looks consistent?
To appreciate the answer for this remember that the original problem is a matter of consistency. It's inconsistent that some function attributes use an '@' character and some don't. If D supported putting an '@' character on the function attributes that are also keywords, then this moves the inconsistency somewhere else. Since keywords are re-used all over the place, some instances of the keyword will require an '@' and some will not, i.e.
@abstract void foo();
abstract class C { }
See the inconsistency? Then you might say, let's make some attributes require an '@' and some not, but how does that solve the original problem? You've just moved some keywords into the '@' bin and some into the "no @' bin. Even worse, you've now made the rule more complex. The current rule is "Use an '@' symbol if the word is not a keyword". Now the rule is "Use an '@' symbol if the word not a keyword, except when you are using the keyword as ...". When the alternatives are considered, the simple rule is not that bad of an option.
Why wasn't nogc made a keyword?
Ideally, if the language were designed from scratch, nogc
would be made a keyword. However, since the language has been around for a while, it is deemed undesirable to introduce new keywords. The reason is that before nogc
was introduced, some existing code may have used identifiers called nogc
; if it were suddenly regarded as a keyword now, that code would no longer compile, and the author would need to revise all parts of the code that used that identifier.
Operators
Why does D not support chaining comparison operators?
First off, what are chaining comparison operators? The term refers to a certain way that comparison operators behave in various languages, which allows for writing multiple comparisons without using logical and between them. Chaining comparison operators are popular in more dynamic languages like Python or Perl, and also provide a slight performance benefit as the middle value only needs to be evaluated once.
Example:
age = 25
if 18 < age <= 25:
print('Chained comparison!')
The equivalent C code would be:
int age = 25;
if (18 < age && age <= 25)
{
printf("No chaining here!");
}
So why does D not support this behaviour for comparison operators if it is more efficient, more concise, and more elegant than the equivalent C code? It is because D strives to be backwards-compatible with C wherever possible, and comparison operator chaining is not backwards-compatible with C.
While code like 18 < age <= 25
is valid C and will generally do what you want (at least in an if-statement), it is not the same as the Python code above. First 18 < age
is evaluated, producing 1 (C does not have the boolean type), which is then compared to 25, which just happens to be greater than 1. This is more evident when checking if two variables are equal to a third value:
int age1 = 25;
int age2 = 25;
if (age1 == age2 == 25)
{
printf("Something's fishy...");
}
The above code will NOT print "Something's fishy...", as the expression age1 == age2
produces 1, which is then compared to 25. Since 1 is not equal to 25 the whole expression evaluates to false and the if-statement will not execute.
As was mentioned earlier, D strives to be backwards-compatible with C wherever possible. It was decided that while chaining comparison operators are somewhat desirable, it would be a bad idea to have a construct that is also valid C code but with subtly different semantics. The potential benefits were not worth the break in compatibility with C.