See the comments in #9794 for the full extent of the existing discussion, starting with https://github.com/PowerShell/PowerShell/pull/9794#issuecomment-504796781
AutomationNull.Value is sometimes detectable and distinguishable from $null in certain cases, for example:
using namespace System.Management.Automation.Internal
$null -is [psobject] # false
[AutomationNull]::Value -is [psobject] # true
@($null).Count # 1
@([AutomationNull]::Value).Count # 0
@SeeminglyScience mentioned a possible way we could have it be handled more closely like [dbnull]
and [nullstring]
are being handled as of #9794, without losing its current function in the pipeline internals, in https://github.com/PowerShell/PowerShell/pull/9794#issuecomment-505107426:
Ideally if this were to be fixed it would just be removed from assignment, e.g.
$obj = [AutomationNull]::Value
would populate$obj
with truenull
. The-is
operator is one of the few things that never "lie" on occasion and I think it would be a detriment to change that.You can also make
[AutomationNull]::Value -is [AutomationNull]
work by:
- Removing the
static
keyword from the class decl- Make it inherit
PSObject
- Change the singleton instance to
new AutomationNull()
That would allow
$autoNull -is [psobject]
to still work while enabling$autoNull -is [AutomationNull]
. Though I think there are a few places in the compiler where it uses a pattern likeif (expr.ExpressionType == typeof(PSObject) && expr.Value == AutomationNull.Value)
so that might need to change.
/cc @daxian-dbw @mklement0
I'm personally in favor of Patrick's solution, as it enables the very clear and concise $item -is [AutomationNull]
with few downsides (the biggest downside being potential implementation complications, but in my opinion these are probably worth tackling). Interested to hear any further discussion on this! 馃挅
using namespace System.Management.Automation.Internal
[AutomationNull]::Value -is [AutomationNull]
returning $true
makes perfect sense both intrinsically and for symmetry with [DbNull]::Value -is [DbNull]
and [NullString]::Value -is [NullString]
returning $true
.
The current workaround for detecting [System.Management.Automation.Internal.AutomationNull]::Value
actually requires _two_ tests (to also distinguish [AutomationNull]::Value
from an empty collection object).
$null -eq $someValue -and @($someValue).Count -eq 0
As for why there is an occasional need to distinguish between a true $null
and [System.Management.Automation.Internal.AutomationNull]::Value
:
A command that produces _no output_ technically outputs [System.Management.Automation.Internal.AutomationNull]::Value
, which is distinct from a command _explicitly returning $null
_.
While $null
and [System.Management.Automation.Internal.AutomationNull]::Value
are treated the same in an expression context, their behavior differs fundamentally in the pipeline:
# A true $null is sent through the pipeline.
PS> & { $null } | % { 'here' }
here
# A command with no output technically outputs [System.Management.Automation.Internal.AutomationNull]::Value, which is NOT sent through the pipeline - it is an empty enumeration.
PS> & { } | % { 'here' }
# NO output
Also, because the switch
statement treats its operand as an _enumeration_, a [System.Management.Automation.Internal.AutomationNull]::Value
value causes the statement to be skipped altogether; that is, it is effectively _ignored_:
$val = & {}
# Because $val contains [System.Management.Automation.Internal.AutomationNull]::Value,
# the switch statement is effectively ignored;
switch ($val) {
default { 'hi' }
}
Related issues:
You cannot pass [System.Management.Automation.Internal.AutomationNull]::Value
as an _argument_ - it is invariably converted to $null
, which @lzybkr surmised may have been an oversight - see https://github.com/PowerShell/PowerShell/issues/9150#issuecomment-474650803
The foreach
_statement_ does _not_ distinguish between $null
and [System.Management.Automation.Internal.AutomationNull]::Value
- _neither_ is enumerated.
The mystifying [AutomationNull]::Value -is [AutomationNull]
being $false
has echoes of [pscustomobject] @{ foo = 1 } -as [System.Management.Automation.PSCustomObject]
being $null
and -as [pscustomobject]
_always_ returning the LHS, with a true $null
LHS being the only exception - see #4343 and below.
Just like [AutomationNull]::Value -is [AutomationNull]
currently being $false
is a head-scratcher, so is [AutomationNull]::Value -is [psobject]
being $true
and - given the unfortunate identity of [psobject]
and [pscustomobject]
- [AutomationNull]::Value -is [pscustomobject]
being equally $true
.
[AutomationNull]::Value -is [psobject]
being $true
makes no sense from an end-user perspective, and looks like another case of [psobject]
peeking from behind the curtain - see #5579.
The AutomationNull is defined in System.Management.Automation.Internal namespace that implies only internal _non-public_ use. We free to change the internal AutomationNull but it make sense only if it is really needed for addressing important scenarios.
If it is purely for internal use it should never be leaking in the ways described above.
However, due to the way it's intended to behave, I'm not sure it can be purely internal and still provide the same utility.
@iSazonov is correct. AutomationNull is for internal use by the runtime. It exists to distinguish an empty stream from a stream containing null.
@vexx32
AutomationNull.Value is sometimes detectable and distinguishable ... for example...
All of your examples explicitly reference the type. I would hardly call that a "leak".
However, due to the way it's intended to behave, I'm not sure it can be purely internal and still provide the same utility
What do you think it should do that it currently doesn't do and why do you think that behaviour is useful? For example, this
using System.Management.Automation.Internal
[AutomationNull]::Value -is [AutomationNull]
does not qualify as useful because it's an internal class.
Sure, for simplicity of definition I opted to use the explicit class name. @mklement0 offered several other ways to obtain the value. Also, it's not internal. I can reference the type name from PS directly. It might be in the internal namespace, but it's public.
Here's another way to get an auto-null:
$a = if ($false) { Do-Thing }
Contrived? Yes. Easily found in a real application? Absolutely. Even more so in a pipeline which may not return any value.
@vexx32
It's in the internal namespace:
System.Management.Automation._Internal_
This namespace contains classes and interfaces that must be public for some reason but are not considered part of the public PowerShell API.
{master}PSCore (1:1) > $a = if ($false) { Do-Thing }
{master}PSCore (1:2) > $a -eq $null
True
{master}PSCore (1:3) > $a.GetType().FullName
You cannot call a method on a null-valued expression.
At line:1 char:1
+ $a.GetType().FullName
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
{master}PSCore (1:4) >
So where does AutomationNull show up in this?
As Dongbo mentioned in the linked PR, AutomationNull doesn't respect GetType(); it's special-cased in that instance to appear as $null
. However, compare $a
in that example with true $null
as follows:
$a -is [psobject] # true
$null -is [psobject] # false
@($a).Count # 0
@($null).Count # 1
If it's not meant to be part of the public API, then y'all need to figure out how to hide it better. 馃槈
@BrucePay I've had to account for it before with methods that have a parameter typed as object[]
. For example:
$a = if ($false) { Do-Thing }
[type]::GetTypeArray(@(0, $a, 1))
And to be fair, the documentation does not do a great job at explaining that it shouldn't be used (and by that I mean it says that it's imperative that you do use it). You also have to remember the audience, most PowerShell folks won't think twice about the namespace because they aren't familiar with that pattern. Granted, most folks who end up needing AutomationNull
will probably be pretty technical, but still.
Whether or not it was intended to be used, I'd still advise that care be taken when it comes to breaking changes.
Good points, @vexx32 and @SeeminglyScience.
I don't think [AutomationNull]
_can_ be hidden, because users need to _understand_ how it differs from $null
and need to be able to _inspect_ a given value to infer its pipeline behavior - and also more obscure differences such as @SeeminglyScience's method-argument example.
In other words: it is insufficient for PowerShell to pretend that a type('s singleton) is $null
when it actually _behaves differently_, situationally.
That difference must be _discoverable_, and having to resort to obscure and cumbersome workarounds to detect [AutomationNull]::Value
- which you'll never discover unless you know about this "internal" type - is obviously unsatisfactory.
So, yes,
$var = & {}
$var -is [AutomationNull]
_is_ useful - and that it currently returns $false
is self-contradictory.
Furthermore, the type must be _documented_ in the end-user docs.
@SeeminglyScience, stumbling upon this again I've noticed bizarre behavior around your example:
# This FAILS, as in your example.
$anull = & {}; [Type]::GetTypeArray(@(0, $anull)).Name | Should -Be 'Int32', 'PSObject'
# This SUCCEEDS - single-element array, with just AutomationNull.
$anull = & {}; [Type]::GetTypeArray(@(, $anull)).Name | Should -Be 'PSObject'
# RETRYING the ORIGINAL command NOW SUDDENLY SUCCEEDS.
$anull = & {}; [Type]::GetTypeArray(@(0, $anull)).Name | Should -Be 'Int32', 'PSObject'
Yeah, looks like a binder bug. There must be a difference in how it approaches converting single item arrays vs more populated arrays. That would explain why the third works, the binder would still be cached.
Thanks, @SeeminglyScience; I've created #11118.
It's only tangentially related, but another context where [System.Management.Automation.Internal.AutomationNull]::Value
behaves differently from $null
is the switch
statement, because switch
treats its operand as an _enumeration_, which in the case of true [System.Management.Automation.Internal.AutomationNull]::Value
causes the statement to be skipped altogether; that is, it is effectively _ignored_:
$val = & {}
# Because $val contains [System.Management.Automation.Internal.AutomationNull]::Value,
# the switch statement is effectively ignored;
switch ($val) {
default { 'hi' }
}
Are we still tracking anything in the issue or we can close?
Not sure, but I do want to clarify that my previous idea of:
Ideally if this were to be fixed it would just be removed from assignment, e.g.
$obj = [AutomationNull]::Value
would populate$obj
with truenull
.
isn't feasible because then these two examples would react differently:
$anull = $null | % {}
$anull | % { 'something' }
# vs
$null | % {} | % { 'something' }
@SeeminglyScience, do you still think the other part of the proposal - making -is [AutomationNull]
work - is feasible without breaking things?
If so, we'd also have to introduce [AutomationNull]
as a type accelerator to make this practical.
If the goal is to make -is [AutomationNull]
work, that's the way to do it imo. I don't know that it necessarily needs to work since well over 99% of the time you don't need to worry about auto null and the current methods work fine.
AutomationNull
is also still in sort of a gray area where it isn't "technically" supported. It may be worth while to either move AutomationNull
or make it internal (preferably the former) similar to what ASP.NET did with their pubternal API's.
Might even be able to get away without any breaking changes by doing this:
namespace System.Management.Automation
{
public sealed class AutomationNull : PSObject
{
private AutomationNull()
{
}
public static AutomationNull Value { get; } = new AutomationNull();
}
}
namespace System.Management.Automation.Internal
{
[Obsolete("Use System.Management.Automation.AutomationNull")]
public static class AutomationNull
{
public static PSObject Value => System.Management.Automation.AutomationNull.Value;
}
}
Auto null should probably be officially supported before any additional enhancements are made.
Thanks, @SeeminglyScience - my vote is definitely to do it, even if it's only needed 1% of the time, so users can solve the mysteries discussed above.
@mklement0 Do you ready to ask PowerShell committee?
I am, @iSazonov - thanks.
/cc @SteveL-MSFT for PowerShell Committee conclusion.
@SeeminglyScience
If the goal is to make
-is [AutomationNull]
work.
Why? If you want to check for AutomationNull
you should do $x == [AutomationNull]::Value.
because it's a singleton.
AutomationNull
is primarily designed for use in the pipeline to distinguish between the _value_ $null
and no value (the empty stream.) When a pipeline returns AutomationNull
it is converted into a $null
on variable assignment.
AutomationNull
needed to be publicly visible for various reasons. For example, a compiled cmdlet might want to explicitly return it. (Though generally, if the cmdlet doesn't call write, the pipeline processor will automatically return AutiomationNull
.)
Overall, when we introduced AutomationNull
in V1, sorting out when something was $null
versus AutomationNull
was extremely painfull. There were tons of related bugs that took a long time to fix properly. So any significant changes to AutomationNull
are likely to result in a whole bunch of new, obscure bugs so I would classify it as high risk change. Conversely, as far as I can see, the proposed changes don't actually add significant value. Why should we take a high-risk low-value change?
Why?
For the reasons outlined above.
If you want to check for AutomationNull you should do
$x == [AutomationNull]::Value
.
That doesn't help with _checking_, the awkwardness and obscurity of which has been outlined above, due to the non-distinction between $null
and $AutomationNull
in expressions; to recap:
# Awkward and obscure test whether $x contains [AutomationNull]::Value
$null -eq $x -and @($x).Count -eq 0
When a pipeline returns AutomationNull it is converted into a $null on variable assignment.
That was true up to v2; v3+ preserves the value, and that mustn't change.
PS> $x = & {}; $null -eq $x -and @($x).Count -eq 0
True
So any significant changes to AutomationNull are likely to result in a whole bunch of new, obscure bugs
I agree that making [AutomationNull]::Value
no longer a true singleton, as proposed above, is problematic.
However, what I think would be a low-risk change - if feasible (can't speak to that) - is to have _the -is
operator_ tell a _new white (useful) lie_ (actually: _truth_), the way it already does for PSCustomObject
, without the implementation of [AutomationNull]::Value
needing to change:
# Technically a PSObject, but presents as PSCustomObject
PS> [pscustomobject] @{} -is [System.Management.Automation.PSCustomObject]
True
Therefore, along with implementing [AutomationNull]
as a type accelerator, the following should then work:
PS> $x = & {}; $x -is [AutomationNull]
True # wishful thinking
I think that would be sufficient and makes for a nice complement to the pending implementation of -is $null
(#10704)
@SeeminglyScience
If the goal is to make
-is [AutomationNull]
work.Why?
I agree for the most part. I don't think it comes up anywhere near often enough to really touch it aside from maybe making a actual public version that just essentially points to the pubternal one.
The wording there was carefully chosen to convey that but it probably wasn't direct enough. My change proposal is more "if it's decided that it should be done for reason x, then this is how it should be done".
When a pipeline returns
AutomationNull
it is converted into a$null
on variable assignment.
It was at one point, but it's assigned to the variable now. Here's an example of what I assume is the reason why, copied from one of my comments above:
# If autonull wasn't saved, these two examples would act differently.
$anull = $null | % {}
$anull | % { 'something' }
# vs
$null | % {} | % { 'something' }
AutomationNull
needed to be publicly visible for various reasons. For example, a compiled cmdlet might want to explicitly return it. (Though generally, if the cmdlet doesn't call write, the pipeline processor will automatically returnAutiomationNull
.)
Why pubternal then? Why not just a normal public API?
So any significant changes to
AutomationNull
are likely to result in a whole bunch of new, obscure bugs so I would classify it as high risk change. Conversely, as far as I can see, the proposed changes don't actually add significant value. Why should we take a high-risk low-value change?
I'm not sure I necessarily agree with the risk assessment, but I'm not arguing the low value side of that. ~@mklement0 you're welcome to make a case for it.~ Hah you did as a pressed submit 馃檪
Point of clarity that seems to have been ever so slightly glossed over... you can't check $value -eq [automationnull]::Value
in PowerShell and expect the right result; $null -eq [automationnull]::Value
will always return $true
Good point, @vexx32, and, in a similar vein, to amend my previous comment:
While [pscustomobject] @{} -is [System.Management.Automation.PSCustomObject]
returning $true
is a - beneficial - _lie_, $x = & {}; $x -is [AutomationNull]
returning $true
would actually be _telling the truth_ - that the current conflation of [AutomationNull]::Value
with $null
gets in the way of.
@mklement0 That's actually not a lie. When you create a PSObject
without a base object, PSCustomObject
is used:
@SeeminglyScience, but it is still _wrapped in_ a PSObject
, isn't it?
PS> [type]::GetTypeArray(([pscustomobject] @{})).Name
PSObject
And speaking of conflation and lies: the conflation of [psobject]
and [pscustomobject]
, _both_ of which are PSObject
, makes the following virtually useless:
PS> [pscustomobject] @{} -is [pscustomobject]
True # OK, but ....
PS> (Get-Item /) -is [pscustomobject]
True # !! ALSO true, because [pscustomobject] is the SAME AS [psobject]
-is [pscustomobject]
working the same as -is [System.Management.Automation.PSCustomObject]
would be a _more_ beneficial lie, by far - the current behavior is both useless and confusing.
And let's not forget that with -as
even the verbose [pscustomobject] @{} -as [System.Management.Automation.PSCustomObject]
doesn't work, let alone -as [pscustomobject]
: #4343
Note that there is already precedent for situationally treating [psboject]
and [pscustomobject]
differently:
# `[pscustomobject] @{}` is *syntactic sugar* for constructing a PSCustomObject
PS> ([pscustomobject] @{}).GetType().Name
PSCustomObject
# `[psobject] @{}`, by contrast, confusingly creates a [hashtable] that is
# virtually invisibly and uselessly in a PSObject instance.
# This despite the fact that both `New-Object PSObject`
# and `[psobject]::new()` *do* create PSCustomObject instances.
PS> ([psobject] @{}).GetType().Name
HashTable
@SeeminglyScience, but it is still _wrapped in_ a
PSObject
, isn't it?
Well yeah sure but most things are, most of the time. PSObject
is the magic wrapper that makes the language functional (I know you know this, bear with me), so really it's lying in the same way that [psobject]'string' -is [string]
is lying.
The other stuff is probably better suited for a new issue.
My point is that it's not worth making -is
lie (aside from the single "lie" of evaluating a psobject's base object) to make $anull -is [automationnull]
work for the dozen of us that will use it once it year. If something was going to change, I really don't think my proposal is dangerous. I understand that when significantly more substantial changes were made in the past that there were understandably difficult to resolve bugs. My proposal is very small though, it's unlikely that any code outside of the class itself would need to be changed.
@mklement0 I missed this initially:
I agree that making
[AutomationNull]::Value
no longer a true singleton, as proposed above, is problematic.
In my proposal it's still a true singleton. The same exact object will be returned from both Internal.AutomationNull.Value
and AutomationNull.Value
, every single call. It will also still be a PSObject
since AutomationNull
would subclass PSObject
.
The only possible break I can think of is if there is an obscure branch of code where obj == AutomationNull.Value
is gated by an explicit type check like obj.GetType() == typeof(PSObject)
. For example:
// Would NOT catch auto null
if (obj.GetType() == typeof(PSObject))
{
return obj == AutomationNull.Value;
}
// This would still work
if (obj is PSObject)
{
return obj == AutomationNull.Value
}
If there are any instances of that (ideally there wouldn't be as PSObject
is not sealed), they should be pretty easy to find by following references of AutomationNull.Value
.
Thanks for the clarification, @SeeminglyScience, I had missed the nuances of your proposal; so it sounds like we needn't worry about the proposed change being _risky_ .
This leaves us with the question: _Why do it_?
make
$anull -is [automationnull]
work for the dozen of us that will use it once it year.
To me, it's not about how often the need arises, but about the need to provide a way to discover and make sense of a real-world behavioral difference that would otherwise be inexplicable without insider information (currently, the only high-profile source of this information that I'm aware of is this Stack Overflow question, where @PetSerAl has provided an in-depth answer).
As it stands, the conflation of $null
and AutomationNull
in terms of _conditionals_ and _reflection_ amounts to a _leaky abstraction_:
They are _not_ the same and in the contexts described above whether you're dealing with one or the other makes a fundamental difference - yet nothing in PowerShell currently tells you which one you're dealing with.
Making the following all work (meaningfully) would be a great enhancement in my estimation:
-is [AutomationNull]
(this proposal)
-is $null
- being worked on in #10704
-is [pscustomobject]
(not just -is [System.Management.Automation.PSCustomObject]
) and -as [pscustomobject]
- see #11921
Parting thought re:
PSObject is the magic wrapper that makes the language functional
Yes, but it's another leaky abstraction that occasionally peeks from behind the curtain to cause seemingly inexplicable behavioral differences: #5579
@vexx32
Point of clarity that seems to have been ever so slightly glossed over... you can't check $value -eq [automationnull]::Value in PowerShell and expect the right result; $null -eq [automationnull]::Value will always return $true
Correct and by design. The intent was to make AutomationNull
as invisible to script users as possible.
So again - why? What significant scenarios depend on actively working with AutomationNull
in script. Why would we take a significant risk to do this?
.
What risk? There isn't any significant risk whatsoever, unless you have some specific disagreements with @SeeminglyScience's assessments.
I think @mklement0 and prior points in this thread have addressed the _why_ of it quite well enough. 馃檪
@vexx32
What risk?
The significant risk of breaking all kinds of things in obscure ways because we've done something to make AutomationNull more visible rather than less visible. As I mentioned before, getting a usable system with AutomationNull took months of bug hunting.
And I have yet to hear a credible rational for changing the semanitcs of AutomationNull. In a value/expression content AutomationNull should work exactly like null. In a pipeline, it's purpose is to indicate that the pipeline returned no results which is not the same as null.
@BrucePay Sure, but it _doesn't_ work "exactly" like null in all cases. Therefore having a reliable and accessible way to distinguish the two is desirable so that you can properly handle it when you need to.
Your arguments are hypotheticals that we "might" break something, with very little information . The responses from @mklement0 and @SeeminglyScience as well as the occasional question that crops up on a fairly frequent basis in the community chat channels indicates that having a reliable way to distinguish $null from AutomationNull is worth implementing.
Unless you can demonstrate something that the proposed changes will actually break, I'm not sure your concerns can be tested in any way. An untestable hypothesis isn't especially useful as a talking point.
To add to @vexx32' s helpful comment: No one in this thread has advocated changing the _semantics_ of AutomationNull - the proposed change in no way modifies the existing _behavior_, it merely enables _reflection on_ a preexisting behavioral difference that has hitherto been undiscoverable without insider knowledge.
Anecdotal references to past struggles and insisting on not being _personally_ convinced are no substitutes for rational debate, especially if the points that have been made aren't being addressed.
We were sure that # 9794 is correct but it was reverted. This experience says that each application area can have its own 'null' and it is probably not worth crossing them as far as possible (even if it raises a lot of questions).
@iSazonov, #9794 was a different story altogether, and in a sense the _opposite_ (complement) of what is being proposed here: it tried to extend the set of types that are _conflated_ with $null
when compared it via -eq
(in keeping with -eq
's loose concept of equality); by contrast, here we're asking to _unambiguously identify_ a "specific flavor of $null
". Again, we're only talking about a _reflection_ feature here that makes real-world behavioral differences _discoverable_ - no existing behavior relating to _using_ these values will change.
we're only talking about a reflection feature here that makes real-world behavioral differences discoverable - no existing behavior relating to using these values will change.
@vexx32 @mklement0 The issue description is based on #9794 and mentioned dbnull
and stringnull
. This is misleading. I think you need to close this discussion and create a new one where you clearly indicate the desired changes as 1, 2, 3.
Please strongly take into account a history which Bruce revealed.
Also please take into account that AutomationNull is "public" mainly for SDK (see C# vs PowerShell - ~3000 vs ~0 results)
Please strongly take into account a history which Bruce revealed.
The history he revealed is that there were a lot of bugs when they made the change that allowed autonull to be saved to a variable. Nothing is revealed there, that's a huge change that pretty obviously increases risk.
It's sort of like saying that there was a lot of obscure bugs when PowerShell's parser switched from purely token based to AST based so we shouldn't consider adding an overload to Parser.ParseInput
.
If the argument was "this comes up so infrequently that it's not even worth discussing" I'd be with ya 100%. If instead the argument is "significantly more drastic and involved changes we made 10 years ago caused problems" then I have a hard time seeing that as anything other than off topic.
I mean mainly the old history and experience:
AutomationNull is primarily designed for use in the pipeline to distinguish between the value $null and no value (the empty stream.) When a pipeline returns AutomationNull it is converted into a $null on variable assignment.
AutomationNull needed to be publicly visible for various reasons. For example, a compiled cmdlet might want to explicitly return it. (Though generally, if the cmdlet doesn't call write, the pipeline processor will automatically return AutiomationNull.)
Our new history and experience is that in #9794 we got married [dbnull], [stringnull] and [null] and then stumbled upon AutiomationNull that was highlighted in the separate discussion. In the history no real scenario presents. So question is - what scenarios do we need to fix to help (1) script writers, (2) binary module developers? what can they not do? what can they not overcome? What annoys them and forces them to make bad workarounds?
Although Bruce mentioned only one scenario where AutiomationNull might be used (binary cmdlet), perhaps there are others. I would rather expect that these scenarios were discussed with the aim of hiding or getting rid of AutiomationNull because it is the visibility of AutiomationNull (knowledge that it exists) that causes questions for users, although most likely they do not need it and they can bypass the emerging problem easily.
@PowerShell/powershell-committee discussed this. We feel that using AutomationNull
directly comes up infrequently enough that it doesn't warrant the time spent on discussion already. We would also be concerned about potential breaking change as noted by @SeeminglyScience and @bpayette.
comes up infrequently enough
_How often this comes up_ isn't the point, as argued before.
using AutomationNull directly
That wasn't the point either; it's not about _using_, but about _discovering_ something that _you can't help but encounter in real life_, without the language giving you the ability to understand why not all apparent $null
values are created equal.
Recent case in point: https://stackoverflow.com/q/60515757/45375
concerned about potential breaking change
What the proposal _turned into_ would _not_ result in any breaking change (as @SeeminglyScience has conclusively argued, aside from his not being personally convinced of the need for a change).
@iSazonov:
I think you need to close this discussion and create a new one
Re-reading the OP, I agree; unfortunately I didn't get around to it in time.
it is the visibility of AutomationNull (knowledge that it exists) that causes questions for users
The exact opposite is the case: most users are _unaware_ of AutomationNull
, but they see its _effects_, which is why they need to be given a way to _discover_ this value.
with the aim of hiding or getting rid of AutomationNull
In light of the above: AutomationNull
must neither be hidden nor can it be gotten rid of.
Stack OverflowI am writing a Chef library to make writing a custom resource for managing Microsoft MSMQ resources on Windows Server easier. Chef interfaces with Windows using Powershell 5.1. I want to raise an...
@iSazonov, I finally got around to this suggestions of yours:
I think you need to close this discussion and create a new one
Please see #13465, which focuses just on -is [AutomationNull]
and hopefully avoids the confusion that arose in this discussion around non-existent breaking changes.
Most helpful comment
To add to @vexx32' s helpful comment: No one in this thread has advocated changing the _semantics_ of AutomationNull - the proposed change in no way modifies the existing _behavior_, it merely enables _reflection on_ a preexisting behavioral difference that has hitherto been undiscoverable without insider knowledge.
Anecdotal references to past struggles and insisting on not being _personally_ convinced are no substitutes for rational debate, especially if the points that have been made aren't being addressed.