digitalmars.dip.ideas - Inlined out arguments declaration
- Anton Pastukhov (24/24) Jul 19 Currently, there is no special treatment for `out` function args:
- Richard (Rikki) Andrew Cattermole (23/56) Jul 19 I considered this as part of opUnwrapIfTrue, and it has properties that
- Anton Pastukhov (5/11) Jul 20 This is a much broader approach than my proposal. I'm talking
- Anton Pastukhov (15/65) Jul 20 Reading opUnwrapOfTrue thread now. There's a Walter's response,
- Anton Pastukhov (2/4) Jul 20 Ugh, D's forum engine strikes again
- Juraj (21/34) Jul 21 I had a go on this.
- Anton Pastukhov (24/59) Jul 21 Thanks, and I'm glad I'm not the only one bothered with the
- Juraj (5/28) Jul 21 Basically having the `x` and `y` be in the scope of `foo` and not
- Richard (Rikki) Andrew Cattermole (22/57) Jul 21 I would go further, it completely removes the benefit.
- Juraj (22/35) Jul 22 This is legal D code, not sure it is related to the proposed
- Juraj (17/17) Jul 22 FIXED:
- user1234 (9/47) Jul 22 "out vars" is a limited point of view. Imagine a variable
- Richard (Rikki) Andrew Cattermole (20/22) Jul 22 You have misunderstood the purpose of this syntax, and its implications.
- Anton Pastukhov (8/10) Jul 22 The limited scope of the proposal is intentional. I believe that
- Richard (Rikki) Andrew Cattermole (12/23) Jul 22 The limited scope of this proposal isn't an issue.
- Juraj (5/7) Jul 22 I am saying, you are dismissing this idea on a premise, that
- Nick Treleaven (3/6) Jul 22 That is backwards - adding special language support for something
- Richard (Rikki) Andrew Cattermole (24/33) Jul 22 I have not dismissed this based upon what is already existing in the
- Juraj (14/26) Jul 22 Fair and good luck
Currently, there is no special treatment for `out` function args:
```d
bool tryParseURL(string value, out URL url) {
// snip
}
// elsewhere
URL url;
URL parsed;
if (tryParseURL("http://example.com"), parsed)) {
url = parsed;
}
assert(url == "http://example.com");
```
```d
URL url;
if (tryParseURL("http://example.com"), out URL parsed)) {
url = parsed;
}
assert(url == "http://example.com");
assert(parsed == "http://example.com"); // parsed is _not_ scoped
to if
```
Not a big deal, but it's IMO better ergonomic
Jul 19
On 20/07/2026 12:02 AM, Anton Pastukhov wrote:
Currently, there is no special treatment for `out` function args:
```d
bool tryParseURL(string value, out URL url) {
// snip
}
// elsewhere
URL url;
URL parsed;
if (tryParseURL("http://example.com"), parsed)) {
url = parsed;
}
assert(url == "http://example.com");
```
```d
URL url;
if (tryParseURL("http://example.com"), out URL parsed)) {
url = parsed;
}
assert(url == "http://example.com");
assert(parsed == "http://example.com"); // parsed is _not_ scoped to if
```
Not a big deal, but it's IMO better ergonomic
I considered this as part of opUnwrapIfTrue, and it has properties that
make me as a compiler developer rather unhappy with.
Consider:
```d
struct Type1 { ~this() {} }
struct Type2 { ~this() {} }
if (foo(Type1 har).bar(Type2 dar)) {
} else {
}
```
Where do you put the destructor calls?
If its in the true branch, `har` can have a valid value, but not `dar`,
and then won't get its destructor called. Also what happens if `bar`
throws an exception?
If you put it outside the if, now you have to scope the variables
outside of the if statement, and make them accessible to the else
branch. It also means you can have double initialization, once in the
function, and once outside.
To implement this, it would require a new tree walk to extract the
variable declarations out. Not the cheapest thing.
There are other variants of this pattern, like logical or and and
expressions. So there is no special casing our way out of this.
Jul 19
On Sunday, 19 July 2026 at 15:15:59 UTC, Richard (Rikki) Andrew Cattermole wrote:On 20/07/2026 12:02 AM, Anton Pastukhov wrote:This is a much broader approach than my proposal. I'm talking about a very focused case: declaring `out` variables inline, not about hoisting arbitrary code.[...]I considered this as part of opUnwrapIfTrue, and it has properties that make me as a compiler developer rather unhappy with. [...]
Jul 20
On Monday, 20 July 2026 at 16:52:42 UTC, Anton Pastukhov wrote:On Sunday, 19 July 2026 at 15:15:59 UTC, Richard (Rikki) Andrew Cattermole wrote:Reading opUnwrapOfTrue thread now. There's a Walter's response, let me quote it verbatim: On Monday, 20 July 2026 at 16:52:42 UTC, Anton Pastukhov wrote:On 20/07/2026 12:02 AM, Anton Pastukhov wrote:This is a much broader approach than my proposal. I'm talking about a very focused case: declaring `out` variables inline, not about hoisting arbitrary code.[...]I considered this as part of opUnwrapIfTrue, and it has properties that make me as a compiler developer rather unhappy with. [...]On Sunday, 19 July 2026 at 15:15:59 UTC, Richard (Rikki) Andrew Cattermole wrote:Reading opUnwrapOfTrue thread now. There's a Walter's response, let me quote it verbatim:On 20/07/2026 12:02 AM, Anton Pastukhov wrote:This is a much broader approach than my proposal. I'm talking about a very focused case: declaring `out` variables inline, not about hoisting arbitrary code.[...]I considered this as part of opUnwrapIfTrue, and it has properties that make me as a compiler developer rather unhappy with. [...]This is a bit simpler and doesn't require language changes: ```d struct Result(T) { bool hasValue; T value; bool get(out T x) { if (hasValue) { x = value; return true; } return false; } } void bar(int); void foo() { Result!int r; int x; if (r.get(x)) { bar(x); } } ```The only difference in my proposal is that the last part would look like this: ```d void foo() { Result!int r; if (r.get(out int x)) { bar(x); } } ```
Jul 20
On Monday, 20 July 2026 at 17:03:29 UTC, Anton Pastukhov wrote:let me quote it verbatim: let me quote it verbatim:Ugh, D's forum engine strikes again
Jul 20
On Monday, 20 July 2026 at 16:52:42 UTC, Anton Pastukhov wrote:On Sunday, 19 July 2026 at 15:15:59 UTC, Richard (Rikki) Andrew Cattermole wrote:I had a go on this. Made a POC that supports ```d if (Boo(out int x, out float y)) { ... } ``` But sadly, destructors are the road block. One place DMD does something like this (<https://dlang.org/spec/statement.html#condition-variables>) it spacial case destructor handling. The that would more challenging for arbitrary call expressions. If one would made types with `~this` an error for *Inlined var declarations*, than the implementation is quite straightforward (rewrite the calls `CommaExp`) - Destructors on classes in not guaranteed. So the dodged this problem. JurajOn 20/07/2026 12:02 AM, Anton Pastukhov wrote:This is a much broader approach than my proposal. I'm talking about a very focused case: declaring `out` variables inline, not about hoisting arbitrary code.[...]I considered this as part of opUnwrapIfTrue, and it has properties that make me as a compiler developer rather unhappy with. [...]
Jul 21
On Tuesday, 21 July 2026 at 16:55:04 UTC, Juraj wrote:On Monday, 20 July 2026 at 16:52:42 UTC, Anton Pastukhov wrote:Thanks, and I'm glad I'm not the only one bothered with the existing implementation. The problem with destructors both you and Rikki Cattermole mentioned honestly eludes me. ```d void foo() { if (Boo(out int x, out float y)) { ... } } ``` should be functionally identical to ```d void foo() { int x; int y; if (Boo(x, y)) { ... } } ``` ...which is perfectly fine D code. There's no behavior change, including the behavior of destructors.On Sunday, 19 July 2026 at 15:15:59 UTC, Richard (Rikki) Andrew Cattermole wrote:I had a go on this. Made a POC that supports ```d if (Boo(out int x, out float y)) { ... } ``` But sadly, destructors are the road block. One place DMD does something like this (<https://dlang.org/spec/statement.html#condition-variables>) it spacial case destructor handling. The that would more challenging for arbitrary call expressions. If one would made types with `~this` an error for *Inlined var declarations*, than the implementation is quite straightforward (rewrite the calls `CommaExp`) - Destructors on classes in not guaranteed. So the dodged this problem. JurajOn 20/07/2026 12:02 AM, Anton Pastukhov wrote:This is a much broader approach than my proposal. I'm talking about a very focused case: declaring `out` variables inline, not about hoisting arbitrary code.[...]I considered this as part of opUnwrapIfTrue, and it has properties that make me as a compiler developer rather unhappy with. [...]
Jul 21
On Tuesday, 21 July 2026 at 17:44:48 UTC, Anton Pastukhov wrote:
Thanks, and I'm glad I'm not the only one bothered with the
existing implementation.
The problem with destructors both you and Rikki Cattermole
mentioned honestly eludes me.
```d
void foo() {
if (Boo(out int x, out float y)) {
...
}
}
```
should be functionally identical to
```d
void foo() {
int x;
int y;
if (Boo(x, y)) {
...
}
}
```
...which is perfectly fine D code. There's no behavior change,
including the behavior of destructors.
Basically having the `x` and `y` be in the scope of `foo` and not
only the `if(true)` branch diminish a lot of the value, at that
point, just write it out.
Juraj
Jul 21
On 22/07/2026 5:56 AM, Juraj wrote:On Tuesday, 21 July 2026 at 17:44:48 UTC, Anton Pastukhov wrote:I would go further, it completely removes the benefit. The problem is having a get without a check that you have a value. Its its own class of bug, one that I want to entirely eliminate out of existence. Consider: ```d if (foo(int* ptr1) || bar(int* ptr2)) { int val1 = *ptr1; int val2 = *ptr2; } ``` You can't prove that this will not dereference null, they are mutually exclusive. And before you say, oh we can disallow logical or expressions! Nope. ```d bool or(bool a, bool b) => a || b; if (foo(int* ptr1).or(bar(int* ptr2))) ``` Boom, same problem. You have to decouple the check from the get entirely. So separate calls.Thanks, and I'm glad I'm not the only one bothered with the existing implementation. The problem with destructors both you and Rikki Cattermole mentioned honestly eludes me. ```d void foo() { if (Boo(out int x, out float y)) { ... } } ``` should be functionally identical to ```d void foo() { int x; int y; if (Boo(x, y)) { ... } } ``` ...which is perfectly fine D code. There's no behavior change, including the behavior of destructors.Basically having the `x` and `y` be in the scope of `foo` and not only the `if(true)` branch diminish a lot of the value, at that point, just write it out. Juraj
Jul 21
On Tuesday, 21 July 2026 at 21:20:53 UTC, Richard (Rikki) Andrew Cattermole wrote:Consider: ```d if (foo(int* ptr1) || bar(int* ptr2)) { int val1 = *ptr1; int val2 = *ptr2; } ``` You can't prove that this will not dereference null, they are mutually exclusive. And before you say, oh we can disallow logical or expressions! Nope.This is legal D code, not sure it is related to the proposed *inline declaration*. ```d int* ptr1; int* ptr2; if (foo(int* ptr1) || bar(int* ptr2)) { int val1 = *ptr1; int val2 = *ptr2; } bool foo(out int* p) { p = null; return true; } bool boo(out int* p) { p = null; return true; } ```TryGet.And I use this pattern in D daily, the only issue I have is the scope of the out vars.
Jul 22
FIXED:
```d
int* ptr1;
int* ptr2;
if (foo(ptr1) || bar(ptr2)) {
int val1 = *ptr1;
int val2 = *ptr2;
}
bool foo(out int* p) {
p = null;
return true;
}
bool bar(out int* p) {
p = null;
return true;
}
```
Jul 22
On Wednesday, 22 July 2026 at 08:25:49 UTC, Juraj wrote:On Tuesday, 21 July 2026 at 21:20:53 UTC, Richard (Rikki) Andrew Cattermole wrote:"out vars" is a limited point of view. Imagine a variable declaration as an expression. [Everything is more simple](https://styx-lang.gitlab.io/styx/primary_expressions.html#vardeclexpression). You see, this is something I really worked on; I still believe this would be nice for D. Problem is the way we think default init. Styx is "zeroes", D is "poison you can track". Now about the scope problem. There's no problem. You can test the idea with styx.Consider: ```d if (foo(int* ptr1) || bar(int* ptr2)) { int val1 = *ptr1; int val2 = *ptr2; } ``` You can't prove that this will not dereference null, they are mutually exclusive. And before you say, oh we can disallow logical or expressions! Nope.This is legal D code, not sure it is related to the proposed *inline declaration*. ```d int* ptr1; int* ptr2; if (foo(int* ptr1) || bar(int* ptr2)) { int val1 = *ptr1; int val2 = *ptr2; } bool foo(out int* p) { p = null; return true; } bool boo(out int* p) { p = null; return true; } ```TryGet.And I use this pattern in D daily, the only issue I have is the scope of the out vars.
Jul 22
On 22/07/2026 8:25 PM, Juraj wrote:This is legal D code, not sure it is related to the proposed /inline declaration/.You have misunderstood the purpose of this syntax, and its implications. The TryGet pattern is unlikely to result in a null value if it returns true. analysis capabilities for nullability specifically to solve this. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis#conditional-postconditions-notnullwhen-maybenullwhen-and-notnullifnotnull bool TryGetMessage(string key, [NotNullWhen(true)] out string? message) { if (_messageMap.ContainsKey(key)) message = _messageMap[key]; else message = null; return message is not null; } ``` Being legal, and being correct code is two vastly different things. This particular feature being proposed has limited uses outside of the TryGet pattern, so its correctness and program security must be considered and weighted quite heavily compared to other use cases.
Jul 22
On Wednesday, 22 July 2026 at 09:28:59 UTC, Richard (Rikki) Andrew Cattermole wrote:This particular feature being proposed has limited uses outside of the TryGet pattern.The limited scope of the proposal is intentional. I believe that being a small, low-risk change is the only possible way for it to see the light of day. user1234's idea, as interesting as it is, is unlikely to happen in D. This is really just a minor syntax sugar/ergonomic improvement. In 2026 D feels old-school and boxy sometimes.
Jul 22
On 22/07/2026 10:10 PM, Anton Pastukhov wrote:On Wednesday, 22 July 2026 at 09:28:59 UTC, Richard (Rikki) Andrew Cattermole wrote:The limited scope of this proposal isn't an issue. Its not far off from what I'd do, if I was to pursue it. See my comment a bit later on in that message: "This particular feature being proposed has limited uses outside of the TryGet pattern, so its correctness and program security must be considered and weighted quite heavily compared to other use cases."This particular feature being proposed has limited uses outside of the TryGet pattern.The limited scope of the proposal is intentional. I believe that being a small, low-risk change is the only possible way for it to see the light of day. user1234's idea, as interesting as it is, is unlikely to happen in D.This is really just a minor syntax sugar/ergonomic improvement. In 2026 D feels old-school and boxy sometimes.When Nic introduced variable declaration support to with statements, it broke code. This could be a lot worse depending upon implementation and exact grammar changes. The potential here is for it to infect non-function-argument expressions.
Jul 22
On Wednesday, 22 July 2026 at 09:28:59 UTC, Richard (Rikki) Andrew Cattermole wrote:You have misunderstood the purpose of this syntax, and its implications.I am saying, you are dismissing this idea on a premise, that something already allowed in the language is problematic. So I do not see how that as good argument.
Jul 22
On Wednesday, 22 July 2026 at 10:19:26 UTC, Juraj wrote:I am saying, you are dismissing this idea on a premise, that something already allowed in the language is problematic. So I do not see how that as good argument.That is backwards - adding special language support for something that is problematic is by definition problematic.
Jul 22
On 22/07/2026 10:19 PM, Juraj wrote:On Wednesday, 22 July 2026 at 09:28:59 UTC, Richard (Rikki) Andrew Cattermole wrote:I have not dismissed this based upon what is already existing in the language. I have dismissed it due to: 1. Interaction with other language features. mainstream language & ecosystem example of this. what classes of bugs we would be recommending people to adopt (which is something both me and Adam want to avoid, if not outright disallow). 4. Introduces new failure cases that require static analysis which I would be the one having to implement AND that static analysis requires attributes to model that people have to use AND there is a much simpler alternative that entirely eliminates that class of bug AND this other feature has been used in multiple mainstream languages & ecosystems without any problems AND this other features doesn't need any kind of static analysis. Workability of a new language feature is only the starting point, there are other concerns like fallibility, program security and if its modellable that must be considered especially if that feature is a quality of life one. I've had years to study this particular set of problems, hence my strong opinions. I do understand why this feature looks attractive.You have misunderstood the purpose of this syntax, and its implications.I am saying, you are dismissing this idea on a premise, that something already allowed in the language is problematic. So I do not see how that as good argument.
Jul 22
On Wednesday, 22 July 2026 at 11:19:07 UTC, Richard (Rikki) Andrew Cattermole wrote:influence and what classes of bugs we would be recommending people to adopt (which is something both me and Adam want to avoid, if not outright disallow).Fair and good luck4. Introduces new failure cases that require static analysis which I would be the one having to implement AND that static analysis requires attributes to model that people have to use AND there is a much simpler alternative that entirely eliminates that class of bug AND this other feature has been used in multiple mainstream languages & ecosystems without any problems AND this other features doesn't need any kind of static analysis.This is the thing that eludes me, what new failure cases? I can do all the problematic parts right now in D, they do not emerge from this proposal. Just to clarify my position. I would love to be able to limit the "scope" of vars in `if` statements, but I acknowledge all the shortcomings. And based of my POC implementation I myself would no go further with this. all ;-)
Jul 22









Anton Pastukhov <mail anton9.com> 