D needs a type expression syntax

Quirin Schroll qs.il.paperinik at gmail.com
Sat May 6 16:20:56 UTC 2023


On Friday, 5 May 2023 at 15:11:50 UTC, Nick Treleaven wrote:
> On Thursday, 4 May 2023 at 15:40:20 UTC, Quirin Schroll wrote:
>> ```d
>> ref int refId   (ref int i) => i;
>> ref int function(ref int i) refIdPtr = &refId; // Doesn’t 
>> parse!
>> ```
>> You can declare `refIdPtr` with `auto` because the type of 
>> `&refId` is 100 % well-formed, it’s just a syntax issue 
>> spelling it out in code; if you `pragma(msg, 
>> typeof(refIdPtr))` you get:
>> ```d
>> int function(ref int i) ref
>> ```
>> Interesting where the `ref` is, isn’t it? Go ahead, try using 
>> *that* instead of `auto`. It doesn’t parse! And frankly, it 
>> shouldn’t; it’s confusing to read.
>
> It could be trailing return type syntax:
> ```d
> function(ref int i) -> ref int refIdPtr;
> ```
> Then we don't need the `alias A = ref T` rule, and we can keep 
> parentheses for expressions (including tuples in future).

I agree that trailing return types (TRT) are really well readable 
– in a language designed around them, which D isn’t. I find it 
irritating that the `-> Type` is followed by the variable name. 
In languages that have them, variables are declared by a keyword, 
then follows the name, then a separator and then comes the type. 
In that order, TRT makes sense.

> Trailing return is much easier to read, when you read a 
> function signature the return type is not as salient as the 
> name or the parameter list (particularly as there's no 
> overloading by return type). The return type gets in the way, 
> especially when its a complex type:
> ```
> some_package.Foo!(const(ElementType!R)[]) oh_hi(long parameter, 
> list following)
> ```
> Some people also recommend putting attributes after the 
> parameter list rather than before the declaration for this 
> reason.

I do that. I’ll never understand why people use them in front. 
And why `unittest` don’t work with trailing attributes. It’s 
inconsistent and annoying.

I put parts of a declaration in their own line when they’re 
getting big: Big return type → own line. 1 big (template) 
parameter or lots of them → each its own line. Constraints and 
contracts → own line (always). It’s another thing what a 
documentation generator makes of them.
```d
some_package.Foo!(const(ElementType!R)[])
oh_hi(R, T)(
     T parameter,
     ...
)
const @safe pure
if (T.sizeof > 0)
in (true)
out(r; true)
{
     …
}
```

> Imagine in an IDE seeing a list of function overloads, if they 
> were shown with trailing return syntax it would be much easier 
> to find the overload you want.

Could be. When looking through overloads, the important part is 
the parameters.

TRT are are a much greater language change, though, compared to 
making a token at a very specific place optional. Their grammar 
must really be implemented and maintained separately. Also, we 
get the same as C++: Two ways to declare a function.

>> ```d
>>  const Object  function()  f0; // Make this an error …
>> const (Object  function()) f1; // … and require this!
>> (const Object) function()  f2; // To differentiate from this.
>>  const(Object) function()  f3; // (Same type as f2)
>> ```
>
> I don't get what the issue is with f0 and f3, aren't they clear 
> enough?

With `f0`: Does `const` apply to the return value or the variable 
`f0`? I’m quite adept with D and I’m only 95% sure it applies to 
`f0`. 95 is not 100, and frankly, when it comes to syntax, it 
should be 100.
With `f3`: Less of an issue, but basically the same. To someone 
new to D, it might be odd that `const` applies to something 
different if a parenthesis follows.
`f1` and `f2` are beyond misapprehension. If you show any 
programmer what `const` applies to (return type or the declared 
variable), they’ll assume it’s a trick question because the 
answer is plain obvious.


More information about the Digitalmars-d mailing list