Non-nullable references, again

Don nospam at nospam.com
Fri Jan 2 05:00:38 PST 2009


Benji Smith wrote:
> Daniel Keep wrote:
>> Benji Smith wrote:
>>> Don wrote:
>>>> Denis Koroskin wrote:
>>>>> Foo nonNull = new Foo();
>>>>> Foo? possiblyNull = null;
>>>  >
>>>> Wouldn't this cause ambiguity with the "?:" operator?
>>>
>>> At first, thought you might be right, and that there would some 
>>> ambiguity calling constructors of nullable classes (especially given 
>>> optional parentheses).
>>>
>>> But for the life of me, I couldn't come up with a truly ambiguous 
>>> example, that couldn't be resolved with an extra token or two of 
>>> lookahead.
>>>
>>> The '?' nullable-type operator is only used  in type declarations, 
>>> not in expressions, and the '?:' operator always consumes a few 
>>> trailing expressions.
>>>
>>> Also (at least in C#) the null-coalesce operator (which converts 
>>> nullable objects to either a non-null instance or a default value) 
>>> looks like this:
>>>
>>>   MyClass? myNullableObj = getNullableFromSomewhere();
>>>   MyClass myNonNullObj = myNullableObj ?? DEFAULT_VALUE;
>>>
>>> Since the double-hook is a single token, it's also unambiguous to parse.
>>>
>>> --benji
>>
>> Disclaimer: I'm not an expert on compilers.  Plus, I just got up.  :P
>>
>> The key is that the parser has to know what "MyClass" means before it 
>> can figure out what the "?" is for; that's why it's context-dependant. 
>> D avoids this dependency between compilation stages, because it 
>> complicates the compiler.  When the parser sees "MyClass", it *doesn't 
>> know* that it's a type, so it can't distinguish between a nullable 
>> type and an invalid ?: expression.
>>
>> At least, I think that's how it works; someone feel free to correct me 
>> if it's not.  :P
>>
>>   -- Daniel
> 
> I could be wrong too. I've done a fair bit of this stuff, but I'm no 
> expert either :)
> 
> Nevertheless, I still don't think there's any ambiguity, as long as the 
> parser can perform syntactic lookahead predicates. The grammar would 
> look something like this:
> 
> DECLARATION :=
>   IDENTIFIER         // Type name
>   ( HOOK )?          // Is nullable?
>   IDENTIFIER         // Var name
>   (
>     SEMICOLON        // End of declaration
>     |
>     (
>       OP_ASSIGN      // Assignment operator
>       EXPRESSION     // Assigned value
>     )
>   )
> 
> Whereas the ternary expression grammar would look something like this:
> 
> TERNARY_EXPRESSION :=
>   IDENTIFIER         // Type name
>   HOOK               // Start of '?:' operator
>   EXPRESSION         // Value if true
>   COLON              // End of '?:' operator
>   EXPRESSION         // Value if false
> 
> The only potential ambiguity arises because the "value if true" 
> expression could also just be an identifier. But if the parser can 
> construct syntactic predicates to perform LL(k) lookahead with arbitrary 
> k, then it can just keep consuming tokens until it finds either a 
> SEMICOLON, an OP_ASSIGN, or a COLON (potentially, recursively, if it 
> encounters another identifier and hook within the expression).
> 
> Still, though, once it finds one of those tokens, the syntax has been 
> successfully disambiguated, without resorting to a semantic predicate.
> 
> It requires arbitrary lookahead, but it can be done within a 
> context-free grammar, and all within the syntax-processing portion of 
> the parser.
> 
> Of course, I could be completely wrong too :)
> 
> --benji

case a?.b:c:
   break;

is this

   case ((a?).b):
c:
   break;

or is it

case (a ? b : c ) :
break;




More information about the Digitalmars-d mailing list