Disposal of out parameter discards #3544
Replies: 23 comments
-
Definitely do not like this. If you don't need to use the value, provide an overload (or extension) that does this and just have all your camera call that instead |
Beta Was this translation helpful? Give feedback.
-
There have been a number of times (mostly with SafeHandles from p/invoke calls) that I would have liked to say |
Beta Was this translation helpful? Give feedback.
-
I realize this is niche. However, the more mature a language is, the less big improvements there are to make. Pretty much all that's left are rough edges here and there that increase friction for the programmer. Sure, you could write overloads for the situation I described in the proposal. But then again, every syntactic sugar feature that has been introduced into the language so far could have been worked around somehow. |
Beta Was this translation helpful? Give feedback.
-
I strongly disagree. There are many large areas of high interest for the team :)
Providing an entire language feature (which costs many thousands of man hours) to save a tiny group of people from writing a single simple overload just doesn't make sense. We would likely spend more time trying to change the language than the sum total of time saved by everyone using this feature. That's just not an effective use of language resources IMO. |
Beta Was this translation helpful? Give feedback.
-
I admit I have no experience designing or implementing languages, but as far as changes go, this one seems to fall on the simple side of the spectrum. Also, it's not a single overload, it's an overload for every method that has one
Firstly, I have to wonder how you arrived at this estimate. Secondly, even if it's true that the number of people affected by this are such a tiny minority as you say, I still think there's value in making deterministic disposal of resources more of a first-class citizen, just like |
Beta Was this translation helpful? Give feedback.
-
Which wuld be what? 0.0001% of all methods? It seems super super niche. :-/ |
Beta Was this translation helpful? Give feedback.
-
Experience. @CyrusNajmabadi works on the C# team. He's experienced first hand just how much work is involved in language changes, even seemingly simple ones like this. His comment of "many thousands of man hours" is almost certainly not hyperbole, but a simple statement of fact. |
Beta Was this translation helpful? Give feedback.
-
I'm sure he's able to estimate better than me how much work this would require, but my comment was directed more at his statement about how rarely It's also worth considering that something that's harder to use might drive people to a different approach, even though the first approach would be a better fit, if only it were easier to use. |
Beta Was this translation helpful? Give feedback.
-
The only solid data I have is my own experience. My single data point is this: I've never needed it, nor seen it, not in 17 years and ~3 million lines of C# code. There are people around who have datasets of code from GitHub (and elsewhere) and the ability to run semantic aware queries across them. I'd be interested to see their figures for this. |
Beta Was this translation helpful? Give feedback.
-
Niche or not, this is a breaking change. I'd be pretty annoyed if I stuck a bunch of values that happened to be |
Beta Was this translation helpful? Give feedback.
-
Isn't that what But also, please see the Alternate proposal section. |
Beta Was this translation helpful? Give feedback.
-
No. Even if i grab a value, i may not want to dispose it. This is actually much more common for me. i.e. i have a dictionary that pooled poolable objects. I use those object for some period of time, but only dispose at some much later point in time. |
Beta Was this translation helpful? Give feedback.
-
If you do |
Beta Was this translation helpful? Give feedback.
-
@mpolicki I believe TryGetValue was only used as an stand-in for the concept of methods with out parameters in general. I'm very used to discarding and would be surprised if |
Beta Was this translation helpful? Give feedback.
-
@jnm2 I understand if implicit disposing of discards is too much of a breaking change. I do think there should at least be an explicit shorthand way of doing that. |
Beta Was this translation helpful? Give feedback.
-
There isn't a shorthand way to declare a |
Beta Was this translation helpful? Give feedback.
-
@HaloFour var result = x.M(3, using out var outValue);
// rest of block could be rewritten as var result = x.M(3, out var outValue);
using(outValue)
{
// rest of block
} and var result = x.M(3, using out _); could be rewritten as var result = x.M(3, out var notNeeded);
notNeeded.Dispose(); My only problem with that is the use of the word "using" for the discard case, considering that the semantics of using and discarding something are in opposition, but I guess I can live with that. |
Beta Was this translation helpful? Give feedback.
-
Quick clarification: I didn't mention needing it, but it would make it nicer to work with SafeHandle out parameters in p/invoke and COM interop calls (a niche scenario). |
Beta Was this translation helpful? Give feedback.
-
It is not niche. |
Beta Was this translation helpful? Give feedback.
-
I would have used this feature today for p/invoking https://docs.microsoft.com/en-us/windows/win32/printdocs/openprinter. Instead of looking like this: Winspool.OpenPrinter(printerName, out using var hPrinter, pDefault: IntPtr.Zero).ThrowLastErrorIfFalse();
using (hPrinter)
{
Winspool.StartDocPrinter(hPrinter, Level: 1, new Winspool.DOC_INFO_1 { pDocName = documentName, pDataType = "RAW" }).ThrowLastErrorIfFalse();
Winspool.StartPagePrinter(hPrinter).ThrowLastErrorIfFalse();
// ...
}
} It would have ended up looking like this: Winspool.OpenPrinter(printerName, out using var hPrinter, pDefault: IntPtr.Zero).ThrowLastErrorIfFalse();
Winspool.StartDocPrinter(hPrinter, Level: 1, new Winspool.DOC_INFO_1 { pDocName = documentName, pDataType = "RAW" }).ThrowLastErrorIfFalse();
Winspool.StartPagePrinter(hPrinter).ThrowLastErrorIfFalse();
// ...
} |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
This isn't a typical p/invoke pattern. The typical way of writing a reliable p/invoke - especially p/invokes dealing with safe handles - is to split it into an internal helper function and the private p/invoke function, as shown below. internal static SafePrinterHandle OpenPrinter(string printerName)
{
if (!OpenPrinter(printerName, out SafePrinterHandle printerHandle, IntPtr.Zero)) { /* throw */ }
else { return printerHandle; }
}
[DllImport(...)]
private static extern bool OpenPrinter(...); This makes the call site(s) look nicer, since they more closely resemble consumption of natural managed object-oriented code. void SomeCaller()
{
using var printerHandle = Utility.OpenPrinter("printerName");
// use 'printerHandle' here
} Of course you're always free to use different conventions within your app / library. But the pattern I called out above is what the .NET team generally advocates. I don't see how this generally recommended pattern would benefit from the language feature proposed here. |
Beta Was this translation helpful? Give feedback.
-
This isn't always necessary, for example if you have In general, |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Motivation
Suppose I have
and some method
Sometimes, when I call
M
, I don't need the value ofb
. But sinceb
isIDisposable
, I can't just use a discard because thenb
doesn't get disposed of:Instead, I have to create a temporary variable to take the value of
b
and callDispose
on it:But this is noisy and (partially) defeats the purpose of having
out
parameter discards.Proposal
If an
out
parameter isIDisposable
and is discarded, automatically callDispose
on it. I.e. rewrite thisinto this
The only downside I can think of is that the behavior of the program might be altered in case the
Dispose
call has side effects. If this is unacceptable, then I have an alternate proposal.Alternate proposal
Introduce a mechanism for the programmer to signal that an
IDisposable
out
parameter discard should be disposed of. For example, a new keyworddispose
, used in the following way:which could get rewritten into:
Beta Was this translation helpful? Give feedback.
All reactions