www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Disallowing ?:?: syntax

reply bearophile <bearophileHUGS lycos.com> writes:
Where the operation isn't no symmetric, all binary operators (but assignment)
in C are left-associative.
But x?y:z is right-associative, so:

x ? y : a ? b : c

is:

x ? y : (a ? b : c)

My little proposal for D is to turn the following into a syntax error, to avoid
possile programmer mistakes (so the programmer must put parentheses here to
make it compile):

x ? y : a ? b : c

If it becomes a syntax error, then it's better if the error message tells to
put how to fix generic code, for example:

"x ? y : a ? b : c  ==> x ? y : (a ? b : c)"

Bye,
bearophile
Jan 05 2009
next sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
bearophile wrote:
<snip>
 My little proposal for D is to turn the following into a syntax 
 error, to avoid possile programmer mistakes (so the programmer must 
 put parentheses here to make it compile):
 
 x ? y : a ? b : c

Here, right-associativity is intuitive - it's analogous to if-then-elseif. So it should probably still be allowed. IMO if there's anywhere where parentheses should be required, it's on the confusing combinations of bitwise and relational operators. Stewart.
Jan 05 2009
prev sibling parent reply Miles <_______ _______.____> writes:
bearophile wrote:
 My little proposal for D is to turn the following into a syntax
 error, to avoid possile programmer mistakes (so the programmer must
 put parentheses here to make it compile):
 
 x ? y : a ? b : c

The ternary operator is not ambiguous, I see no need for making it an error. I have used such constructs very often, with no problem: writefln("Printer is %s.", status == OFFLINE ? "offline" : status == ONLINE ? "online" : status == CHECK ? "out of paper" : status == ONLINE_CHECK ? "on fire" : "unknown status"); That would become a real mess of parenthesis.
Jan 05 2009
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Miles" <_______ _______.____> wrote in message 
news:gjst46$2hh1$1 digitalmars.com...
 bearophile wrote:
 My little proposal for D is to turn the following into a syntax
 error, to avoid possile programmer mistakes (so the programmer must
 put parentheses here to make it compile):

 x ? y : a ? b : c

The ternary operator is not ambiguous, I see no need for making it an error. I have used such constructs very often, with no problem: writefln("Printer is %s.", status == OFFLINE ? "offline" : status == ONLINE ? "online" : status == CHECK ? "out of paper" : status == ONLINE_CHECK ? "on fire" : "unknown status"); That would become a real mess of parenthesis.

This makes my highly DRY-oriented mind think: While ?: is an expression-based counterpart to the statement-based if...else, maybe we could use a similar expression-based counterpart to switch? (I think I've seen such a thing in hardware description languages) -------------------- writefln("Printer is %s.", status ?? // Purely illustrative syntax OFFLINE => "offline" :: ONLINE => "online" :: CHECK => "out of paper" :: ONLINE_CHECK => "on fire" :: default => "unknown status"); -------------------- Although, I've often created re-usable lookup tables to handle that sort of thing: -------------------- char[] getPrinterStatusStr(uint code) { // Somthing like this, I forget the exact syntax and nuances. D's array literals are a PITA. char[][uint] printerStatusCodeToStr = [ OFFLINE : "offline", ONLINE : "online", CHECK : "out of paper", ONLINE_CHECK : "on fire", ]; return (code in printerStatusCodeToStr)? printerStatusCodeToStr[code] : "unknown status"; } writefln("Printer is %s.", getPrinterStatusStr(status)); -------------------- But the ??=>:: (again, purely illustrative syntax) would be a nice alternative to have at my disposal. And it would make writing getPrinterStatusStr much nicer. Back to the original ?:?: issue: If I were to ever chain ?:'s, Miles's example above is the only time I ever would feel comfortable omitting any disambiguating parens. If we got a ??=>:: (or something like it), then I would agree with making ?:?: illegal without disambiguating parens. But without a ??=>::, I think Miles's example provides a compelling reason to keep the ?:?:.
Jan 05 2009
parent Miles <_______ _______.____> writes:
Nick Sabalausky wrote:
 This makes my highly DRY-oriented mind think:
 
 While ?: is an expression-based counterpart to the statement-based 
 if...else, maybe we could use a similar expression-based counterpart to 
 switch? (I think I've seen such a thing in hardware description languages)

I think I have seen that using a mixture of recursive templates and lazy evaluation. But sure, that would be a nice addition to support a relatively common use-case. Two things I miss are the ?: GNU C extension ( a ?: b expands to a ? a : b , except that a is evaluated only once) or the ?? C# construct (similar idea, but only tests for null reference).
Jan 05 2009
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Miles,

 bearophile wrote:
 
 My little proposal for D is to turn the following into a syntax
 error, to avoid possile programmer mistakes (so the programmer must
 put parentheses here to make it compile):
 
 x ? y : a ? b : c
 


I think not. x ? y : a ? b : c => (x ? y : a) ? b : c or x ? y : a ? b : c => x ? y : (a ? b : c) without checking the actual syntax you can't tell which of the above will be used and (according to bearophile) if ?: followed after +/-/etc the first would be.
 I see no need for making it an
 error. I have used such constructs very often, with no problem:
 

However I agree. Don't change it.
 writefln("Printer is %s.",
 status == OFFLINE      ? "offline"      :
 status == ONLINE       ? "online"       :
 status == CHECK        ? "out of paper" :

 status == ONLINE_CHECK ? "on fire"      :

ha ha ha :)
 "unknown status");
 That would become a real mess of parenthesis.
 

Jan 05 2009
parent reply Miles <_______ _______.____> writes:
BCS wrote:
 I think not.
 
 x ? y : a ? b : c => (x ? y : a) ? b : c
 
 or
 
 x ? y : a ? b : c => x ? y : (a ? b : c)
 
 without checking the actual syntax you can't tell which of the above
 will be used and (according to bearophile) if ?: followed after +/-/etc
 the first would be.

It simply can't be the first, due to the kind of parser used for C and most of its derived languages (D included). When a '?' is found, the parser recurses until it finds a ':' (it gets stuck in a branch of the syntax tree until a colon token is found). This is in how the language is defined (http://www.digitalmars.com/d/2.0/expression.html): ConditionalExpression: OrOrExpression OrOrExpression ? Expression : ConditionalExpression So, the third operand to the ternary operator is a ConditionalExpression itself, the parser have no reason to finish this evaluation branch if it finds another '?', it naturally recurses. So, x ? y : a ? b : c => x ? y : (a ? b : c). But I think that I know what kind of ambiguity you are talking about now... For me, ambiguity is something like the <...> C++ template definition/instantiation operator, or the function declaration/object variable definition ambiguity.
Jan 05 2009
parent BCS <ao pathlink.com> writes:
Reply to Miles,

 BCS wrote:
 
 I think not.
 
 x ? y : a ? b : c => (x ? y : a) ? b : c
 
 or
 
 x ? y : a ? b : c => x ? y : (a ? b : c)
 
 without checking the actual syntax you can't tell which of the above
 will be used and (according to bearophile) if ?: followed after
 +/-/etc the first would be.
 

most of its derived languages (D included). When a '?' is found, the parser recurses until it finds a ':' (it gets stuck in a branch of the syntax tree until a colon token is found). This is in how the language is defined (http://www.digitalmars.com/d/2.0/expression.html): ConditionalExpression: OrOrExpression OrOrExpression ? Expression : ConditionalExpression So, the third operand to the ternary operator is a ConditionalExpression itself, the parser have no reason to finish this evaluation branch if it finds another '?', it naturally recurses. So, x ? y : a ? b : c => x ? y : (a ? b : c).

You have just proven my exact point. To find how it parses you need to dig up the syntax, as you just did (Note I said that you can't tell how it's parsed *without* doing that). Also note that most (or all) of the other operators in C/C++/C#/D/etc go the other way: OrOrExpression: AndAndExpression OrOrExpression || AndAndExpression
 But I think that I know what kind of ambiguity you are talking about
 now... For me, ambiguity is something like the <...> C++ template
 definition/instantiation operator, or the function declaration/object
 variable definition ambiguity.
 

Yes, I think you've spotted the point. I'm referring to ambiguities that will cause problems with <joke>I-BAL</joke> type parsers.
Jan 05 2009