One thing nobody's mentioned yet, so I'll mention it: The desire to nest comments often indicates that the programmer is Doing It Wrong.
First, let's agree that the only time "nesting" or "not nesting" is visible to the programmer is when the programmer writes something structurally like this:
do_something();
/* comment /* nested comment */ more comment */
do_something_else();
Now, when does such a thing come up in practice? Certainly the programmer isn't going to be writing nested comments that literally look like the above snippet! No, in practice when we nest comments (or wish we could nest them), it's because we want to write something like this:
do_something(); /* do a thing */
/* [ajo] 2017-12-03 this turned out to be unnecessary
do_something_else(); /* do another thing */
*/
And this is BAD. This is not a pattern we (as language designers) want to encourage! The correct way to write the above snippet is:
do_something(); /* do a thing */
That "wrong" code, that false start or whatever it was, doesn't belong in the codebase. It belongs, at best, in the source-control history. Ideally, you'd never even write the wrong code to begin with, right? And if the wrong code was serving a purpose there, by warning maintainers not to reinstate it for some reason, well, that's probably a job for a well-written and intentional code comment. Trying to express "don't do X" by just leaving in some old code that does X, but commented out, is not the most readable or effective way to keep people from doing X.
This all boils down to a simple rule of thumb that you may have heard before: Don't comment out code. (Searching for this phrase will turn up a lot of opinions in agreement.)
Before you ask: yes, languages such as C, C#, and C++ already give the programmer another tool to "comment out" large blocks of code: #if 0
. But this is just a particular application of the C preprocessor, which is a large and useful tool in its own right. It would actually be extremely difficult and special-casey for a language to support conditional compilation with #if
and yet not support #if 0
.
So, we've established that nested comments are relevant only when the programmer is commenting out code; and we've established (via consensus of a lot of experienced programmers) that commenting out code is a Bad Thing.
To complete the syllogism, we must accept that language designers have an interest in promoting Good Things and discouraging Bad Things (assuming that all else is equal).
In the case of nested comments, all else is equal — you can safely ignore the low-voted answers that claim that parsing nested /*
would somehow be "difficult" for the parser. (Nested /*
are no harder than nested (
, which just about every parser in the world already needs to handle.)
So, all else being equal, should a language designer make it easy to nest comments (i.e., to comment out code), or difficult? Recall that commenting out code is a Bad Thing.
Q.E.D.
Footnote. Notice that if you don't allow nested comments, then
hello /* foo*/bar.txt */ world
is a misleading "comment" — it's equivalent to
hello bar.txt */ world
(which is likely a syntax error). But if you do allow nested comments, then
hello /* foo/*.txt */ world
is a misleading "comment" — it's equivalent to
hello
but leaves the comment open all the way to the end of the file (which again is almost certainly a syntax error). So neither way is particularly less prone to unintentional syntax errors. The only difference is in how they handle the intentional antipattern of commented-out code.
The D programming language and DMC's extension to C and C++ did support these operators (all 14 combinations of them), but interestingly, D is going to deprecate these operators, mainly because
- what exactly is
a !< b
? It is a>=b || isNaN(a) || isNaN(b)
. !<
is not the same as >=
, because NaN !< NaN
is true while NaN >= NaN
is false. IEEE 754 is hard to master, so using a !< b
to will just cause confusion over NaN handling — you can search for such operators in Phobos (D's standard library), and quite a number of use has comments beside it to remind the readers NaN is involved,
- therefore, few people will use it, even if such operators exist like in D,
- and one have to define 8 more tokens for these seldomly used operators, which complicates the compiler for little benefit,
- and without those operators, one could still use the equivalent
!(a < b)
, or if one likes to be explicit, a >= b || isNaN(a) || isNaN(b)
, and they are easier to read.
Besides, the relations (≮, ≯, ≰, ≱) are seldomly seen in basic math, unlike !=
(≠) or >=
(≥), so it's hard to understand for many people.
These are probably also the reasons why most languages do not support them.
Best Answer
These are binary operators, which when chained, normally and naturally produce an abstract syntax tree like:
When evaluated (which you do from the leaves up), this produces a boolean result from
x < y
, then you get a type error trying to doboolean < z
. In order forx < y < z
to work as you discussed, you have to create a special case in the compiler to produce a syntax tree like:Not that it isn't possible to do this. It obviously is, but it adds some complexity to the parser for a case that doesn't really come up that often. You're basically creating a symbol that sometimes acts like a binary operator and sometimes effectively acts like a ternary operator, with all the implications of error handling and such that entails. That adds a lot of space for things to go wrong that language designers would rather avoid if possible.