www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Yearly "can we please have void foo() auto" post

reply Anonymouse <zorael gmail.com> writes:
I love `auto`, it makes my life easier. The compiler infers what 
it can and I primarily enjoy the bonuses of ` safe` without 
having to annotate it manually.

But it's not always applicable.

1. Some functions I would normally declare as returning `void` 
that have return statements that should implicitly discard their 
return values.

```d
string forTheSakeOfImpurity;
int alsoForTheSakeOfImpurity;

string setString()
{
     forTheSakeOfImpurity = "blah";
     return forTheSakeOfImpurity;
}

int setInt()
{
     alsoForTheSakeOfImpurity = 42;
     return alsoForTheSakeOfImpurity;
}

auto foo(bool condition)
{
     if (condition) return setString();
     else return setInt();
}

/*
onlineapp.d(20): Error: expected return type of `string`, not 
`int`:
onlineapp.d(19):        Return type of `string` inferred here.
  */
```

Can be worked around by making it `return cast(void)` everywhere, 
but I'm appealing here to not have to.

2. Some functions that I want to coerce the return value of to a 
specific type. Related to point 1.

```d
string bar() pure
{
     Appender!(char[]) sink;
     // ...
     return sink[];
}

auto baz()
{
     Appender!(char[]) sink;
     // ...
     return sink[];
}

static assert(is(ReturnType!bar == string));
static assert(!is(ReturnType!baz == string));  // :c
```

3. Any void function that I don't want the tooling to nag about.

```d
auto foo() {}

/*
asdf.d(3:1)[warn]: Auto function without return statement, prefer 
replacing auto with void
  */
```

---

Can we please have `void foo() auto`? It would behave as `auto 
foo()` does, except enforce the return type. As a bonus we'd also 
get `string bar() auto`.

Yes, I can make it `string foo()()`. I can even `return 
cast(string)sink[]`. There are technically workarounds for all of 
this; I'm just trying to make the case for repurposing the neat 
shortcut we already have in place.
Jul 27 2023
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 27 July 2023 at 15:22:45 UTC, Anonymouse wrote:
 I love `auto`, it makes my life easier. The compiler infers 
 what it can and I primarily enjoy the bonuses of ` safe` 
 without having to annotate it manually.

 But it's not always applicable.
[...]
 Can we please have `void foo() auto`? It would behave as `auto 
 foo()` does, except enforce the return type. As a bonus we'd 
 also get `string bar() auto`.
IMO the correct solution is to just make the compiler infer attributes like ` safe` for *all* functions, with exceptions only in cases like `extern (C)` or virtual class/interface methods where the full implementation is not available, or if the user explicitly opts out (e.g., with something like ` noinfer`). I have a half-written draft DIP for this that I plan to get back to once Mike Parker announces that the DIP queue is open again. If anyone else is working on this or wants to collaborate, please let me know!
Jul 27 2023
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 27 July 2023 at 18:55:25 UTC, Paul Backus wrote:
 On Thursday, 27 July 2023 at 15:22:45 UTC, Anonymouse wrote:
 I love `auto`, it makes my life easier. The compiler infers 
 what it can and I primarily enjoy the bonuses of ` safe` 
 without having to annotate it manually.

 But it's not always applicable.
[...]
 Can we please have `void foo() auto`? It would behave as `auto 
 foo()` does, except enforce the return type. As a bonus we'd 
 also get `string bar() auto`.
IMO the correct solution is to just make the compiler infer attributes like ` safe` for *all* functions, with exceptions only in cases like `extern (C)` or virtual class/interface methods where the full implementation is not available, or if the user explicitly opts out (e.g., with something like ` noinfer`). [snip]
Or if the function doesn't have a body?
Jul 27 2023
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 27 July 2023 at 19:21:40 UTC, jmh530 wrote:
 On Thursday, 27 July 2023 at 18:55:25 UTC, Paul Backus wrote:
 IMO the correct solution is to just make the compiler infer 
 attributes like ` safe` for *all* functions, with exceptions 
 only in cases like `extern (C)` or virtual class/interface 
 methods where the full implementation is not available, or if 
 the user explicitly opts out (e.g., with something like 
 ` noinfer`).
 [snip]
Or if the function doesn't have a body?
Yes, naturally. Here's what I've got written down so far: https://github.com/pbackus/DIPs/blob/universal-attribute-inference/DIPs/1NNN-PJB.md
Jul 27 2023
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 27 July 2023 at 19:27:26 UTC, Paul Backus wrote:
 Yes, naturally. Here's what I've got written down so far:
I wrote some thoughts on this concept about a year ago to: http://dpldocs.info/this-week-in-d/Blog.Posted_2022_07_11.html#inferred-attributes
Jul 27 2023
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 27 July 2023 at 19:45:03 UTC, Adam D Ruppe wrote:
 On Thursday, 27 July 2023 at 19:27:26 UTC, Paul Backus wrote:
 Yes, naturally. Here's what I've got written down so far:
I wrote some thoughts on this concept about a year ago to: http://dpldocs.info/this-week-in-d/Blog.Posted_2022_07_11.html#inferred-attributes
Thanks! The point about documentation is not something I'd considered--although given the execrable state of DDoc, I am not optimistic about improvements there.
Jul 27 2023
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Thu, Jul 27, 2023 at 06:55:25PM +0000, Paul Backus via Digitalmars-d wrote:
[...]
 IMO the correct solution is to just make the compiler infer attributes
 like ` safe` for *all* functions, with exceptions only in cases like
 `extern (C)` or virtual class/interface methods where the full
 implementation is not available, or if the user explicitly opts out
 (e.g., with something like ` noinfer`).
Opting out could be as simple as specifying at least one attribute explicitly. Where no attributes are specified, it should be inferred by default.
 I have a half-written draft DIP for this that I plan to get back to
 once Mike Parker announces that the DIP queue is open again. If anyone
 else is working on this or wants to collaborate, please let me know!
This is awesome! This is the right direction to go. Looking forward to seeing this through the DIP process. T -- Tell me and I forget. Teach me and I remember. Involve me and I understand. -- Benjamin Franklin
Jul 27 2023
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 27 July 2023 at 19:34:09 UTC, H. S. Teoh wrote:
 On Thu, Jul 27, 2023 at 06:55:25PM +0000, Paul Backus via 
 Digitalmars-d wrote: [...]
 IMO the correct solution is to just make the compiler infer 
 attributes like ` safe` for *all* functions, with exceptions 
 only in cases like `extern (C)` or virtual class/interface 
 methods where the full implementation is not available, or if 
 the user explicitly opts out (e.g., with something like 
 ` noinfer`).
Opting out could be as simple as specifying at least one attribute explicitly. Where no attributes are specified, it should be inferred by default.
Problematic when it comes to code like the following: nothrow nogc: void foo() { // ... } auto bar() { // ... } For `bar`, the compiler will currently infer safe and pure, even though nothrow and nogc have been specified explicitly. For consistency, if we want to extend attribute inference to `foo`, it needs to work the same way.
Jul 27 2023
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/27/23 2:55 PM, Paul Backus wrote:
 On Thursday, 27 July 2023 at 15:22:45 UTC, Anonymouse wrote:
 I love `auto`, it makes my life easier. The compiler infers what it 
 can and I primarily enjoy the bonuses of ` safe` without having to 
 annotate it manually.

 But it's not always applicable.
[...]
 Can we please have `void foo() auto`? It would behave as `auto foo()` 
 does, except enforce the return type. As a bonus we'd also get `string 
 bar() auto`.
IMO the correct solution is to just make the compiler infer attributes like ` safe` for *all* functions, with exceptions only in cases like `extern (C)` or virtual class/interface methods where the full implementation is not available, or if the user explicitly opts out (e.g., with something like ` noinfer`). I have a half-written draft DIP for this that I plan to get back to once Mike Parker announces that the DIP queue is open again. If anyone else is working on this or wants to collaborate, please let me know!
I think it would be nicer to specify exact attributes than to "opt out" of inference. For e.g. ` safe`, we are covered, because there is ` system`. For `nothrow`, there is `throw` (I think?). But for ` nogc` and `pure`, there is no opposite. I would like to see some mechanism or additional attributes that make it so you can specify what should not be inferred before turning on full inference. One large problem with all this is people who "don't care" about attributes. Of course, now their code will infer attributes! But that has become part of the public API. If they change something to change the attribute inference, all of a sudden code that is marked explicitly will stop compiling, and the author will say "too bad, not my fault". I think the only way to fix this is to only infer when explicitly stated. And to that effect... we could just make the storage class `auto` mean that, like the OP says. I mean, we already allow `static void foo()`, why not `auto void foo()`? If I do `auto void foo() {}` it complains: ``` Error: function `onlineapp.foo` storage class `auto` has no effect if return type is not inferred ``` Well, let's make it... have an effect. -Steve
Jul 27 2023
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 27 July 2023 at 22:08:27 UTC, Steven Schveighoffer 
wrote:
 I think it would be nicer to specify exact attributes than to 
 "opt out" of inference.

 For e.g. ` safe`, we are covered, because there is ` system`. 
 For `nothrow`, there is `throw` (I think?). But for ` nogc` and 
 `pure`, there is no opposite.

 I would like to see some mechanism or additional attributes 
 that make it so you can specify what should not be inferred 
 before turning on full inference.
I'm 100% in favor of adding ` gc` and ` impure`. Unfortunately, every time this topic comes up, the discussion degenerates into endless bikeshedding and no progress is made. IMO this would be a perfect opportunity for Walter to exercise his BDFL power and push through a decision unilaterally.
 One large problem with all this is people who "don't care" 
 about attributes. Of course, now their code will infer 
 attributes! But that has become part of the public API. If they 
 change something to change the attribute inference, all of a 
 sudden code that is marked explicitly will stop compiling, and 
 the author will say "too bad, not my fault".
Yes, this is the main pain point of universal attribute inference. OTOH, with the current system, the pain point is that you often can't even use a library in the first place, because the author forgot to add an explicit attribute that the compiler *could* have inferred--and the author will say, "not my problem, I don't care about attributes." Ultimately, I think universal inference comes out on top, because "I can't upgrade `<package>`" is a less severe failure mode than "I can't use `<package>` at all." But I accept that reasonable people can disagree on this.
 I think the only way to fix this is to only infer when 
 explicitly stated.

 And to that effect... we could just make the storage class 
 `auto` mean that, like the OP says.

 I mean, we already allow `static void foo()`, why not `auto 
 void foo()`?
Requiring the programmer to take *any action at all* to enable inference is too much of an obstacle. People naturally take the path of least resistance; as language designers, it's our job to make that path the correct one. Not to mention, there is a non-trivial amount of existing D code that would likely never be updated to use `auto` for inference, but *would* benefit from having inference enabled by default.
Jul 27 2023
prev sibling parent Basile B. <b2.temp gmx.com> writes:
On Thursday, 27 July 2023 at 15:22:45 UTC, Anonymouse wrote:
 I love `auto`, it makes my life easier. The compiler infers 
 what it can and I primarily enjoy the bonuses of ` safe` 
 without having to annotate it manually.

 But it's not always applicable.

 [...]

 3. Any void function that I don't want the tooling to nag about.

 ```d
 auto foo() {}

 /*
 asdf.d(3:1)[warn]: Auto function without return statement, 
 prefer replacing auto with void
  */
For this you can (and should) open a D-Scanner PR that proposes to deactivate the check by default. The rationale for this check (IIRC) is that if you have an `asm` block that returns something then the compiler infers void as return type. A quite rare case actually... Unfortunately I did not thought to the attribute problem when I wrote the check, a long time ago.
Jul 27 2023