Skip to content

Enable simple detection of [AutomationNull]::Value with -is [AutomationNull] #13465

Open

Description

Summary of the new feature/enhancement

Enable the following -is test to allow for a PowerShell-idiomatic detection of the [System.Management.Automation.Internal.AutomationNull]::Value value that commands that output "nothing" technically output.

# `& {}` outputs "nothing", which is technically [System.Management.Automation.Internal.AutomationNull]::Value
PS> & {} -is [AutomationNull]   # WISHFUL THINKING
True

In expression contexts [System.Management.Automation.Internal.AutomationNull]::Value is treated like $null, but there are contexts where the distinction matters:

In the pipeline:

# A true $null is sent through the pipeline. 
PS> $null  | % { 'here' }
here

# [System.Management.Automation.Internal.AutomationNull]::Value 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' }
}

Operators behave inconsistently with AutomationNull as the LHS (see #3866):

PS> [System.Management.Automation.Internal.AutomationNull]::Value -match 'foo'
# NO OUTPUT - LHS was interpreted as *collection*

PS> [System.Management.Automation.Internal.AutomationNull]::Value -eq 'foo'
False # LHS was interpreted as a *scalar*

In short: Because [System.Management.Automation.Internal.AutomationNull]::Value causes observable differences in behavior from $null, it must be discoverable.

Proposed technical implementation details (optional)

Note: Strictly speaking, [System.Management.Automation.Internal.AutomationNull]::Value is of type [System.Management.Automation.PSObject], but treating it as an instance of AutomationNull would be a helpful "white lie", similar to the one -is already tells when it reports a [psobject] wrapper's .BaseObject value's type as the type.

However, Patrick Meinecke (@SeeminglyScience)'s proposed implementation here would actually resolve this issue, via a new, public System.Management.Automation.AutomationNull wrapper, for which an [AutomationNull] type accelerator would have to be defined.

Activity

  1. changed the title [-]Enable simple detention of [AutomationNull]::Value with -is [AutomationNull][/-] [+]Enable simple detection of [AutomationNull]::Value with -is [AutomationNull][/+] on Aug 17, 2020
  2. briantist commented on Dec 22, 2020

    @briantist

    I really like this proposal.

    The differences between $null and "nothing" confound users who inevitably run into it, and the ones who are curious enough to try to understand why and make clear comparisons end up disappointed and with a view of PowerShell as a "weird" language (or at worst one they can't trust).

    True story: I worked at a company where the team who used PowerShell the most had as their team's chat description:

    PowerShell obeys the principle of most surprise

    The concept of a $null result vs. "no result" is not difficult to understand, but only being able to reason about a result implicitly instead of being able to just ask the language is not a good UX.

    $value -is [AutomationNull] is clear and concise.

  3. CopaceticMeatbag commented on Oct 28, 2022

    @CopaceticMeatbag

    Any chance this is going to be looked at eventually? The current implementation makes zero intuitive sense, and I think the example below is a very a basic and common use case. What's the hold up 2 years on?

    $CurrentDevices = Get-AudioDevice -List | ? type -eq 'Playback' #no match so returns an Internal.AutomationNull instead of $null
    $CurrentDevices -eq $null #prints True
    switch($CurrentDevices){
        $null {write-host "gotcha! This won't run lol"}
        default {write-host "this will never run either because of some obscure non-public value returned that I can't inspect, even though I just compared the variable to $null directly above the switch and was told they were the same. And the official response 2 years later is still just 'lol'"}
    }
    
  4. SeeminglyScience commented on Oct 28, 2022

    @SeeminglyScience
    Contributor

    Mike (@CopaceticMeatbag) This issue is about an easier way to detect autonull, not a change in the behavior. That behavior in particular is relied upon heavily so I would not expect it to change.

    On an unrelated note, this issue is missing a needs triage tag, adding so the Engine WG can discuss it.

  5. CopaceticMeatbag commented on Nov 1, 2022

    @CopaceticMeatbag

    Patrick Meinecke (@SeeminglyScience) yes I'm sorry I should've been clearer; I think $value -is [AutomationNull] is a great halfway solution and would at least give me an option to work with.

    I read through issue #9997 and don't understand how Bruce Payette (@bpayette) 's comments make sense to nullify the whole discussion. E.g. "The intent was to make AutomationNull as invisible to script users as possible". Ok sure, but PS is returning an [AutomationNull] result to me, and I'm trying to confirm that, and the response is "you're not meant to use that"? So why return it then if I'm not meant to use it? Feels like the PS team is more than happy shifting the burden onto the end user as a 'fix' for this issue.

  6. SeeminglyScience commented on Jan 10, 2023

    @SeeminglyScience
    Contributor

    The Engine WG discussed this yesterday and agree to go forward with my proposal laid out in #9997 (comment) with the requirement that #18914 is implemented and the currently pubternal type is decorated with HiddenAttribute.

    It should also be noted that we decided that a type accelerator was not necessary as it's an uncommon scenario.

  7. added
    Up-for-GrabsUp-for-grabs issues are not high priorities, and may be opportunities for external contributors
    and removed
    WG-Enginecore PowerShell engine, interpreter, and runtime
    Needs-TriageThe issue is new and needs to be triaged by a work group.
    on Jan 10, 2023
  8. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
  9. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
  10. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
  11. microsoft-github-policy-service commented on Nov 23, 2023

    @microsoft-github-policy-service
  12. daxian-dbw commented on Jun 10, 2024

    @daxian-dbw
    Member

    Reopen this "up-for-grab" issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugKeepOpenThe bot will ignore these and not auto-closeUp-for-GrabsUp-for-grabs issues are not high priorities, and may be opportunities for external contributors

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions