Skip to content

Common parameters -OutVariable, -ErrorVariable, -WarningVariable, and -InformationVariable always return a [System.Collections.ArrayList] instance, even with a single object #3773

Closed

Description

Note: The problem was first discovered with -OutVariable - see #3154.
The problem applies to all -*Variable common parameters, however, with the exception of -PipelineVariable (which inherently captures a single item at time).

To recap the problem:

  • Even if only a single value is captured by these parameters, an array list rather than a scalar is returned (the single-element collection isn't unwrapped - a deviation from PowerShell's normal collection handling).

  • Also - another deviation from usual PowerShell behavior - it is type [System.Collections.ArrayList] that is always used, in contrast with the [System.Object[]] instances you get with regular assignments.

Steps to reproduce

# Adv. function that outputs a single item of each type.
function foo {
  [CmdletBinding()]
  param()
  
  Write-Warning 'warn'
  Write-Information 'info'
  Write-Error 'err'
  'out'
}

foo -OutVariable ov -ErrorVariable ev -WarningVariable wv -InformationVariable iv  *>$null

$ov, $ev, $wv, $iv | % GetType | % Name

Expected behavior

String
ErrorRecord
WarningRecord
InformationRecord

Actual behavior

ArrayList
ArrayList
ArrayList
ArrayList

Environment data

PowerShell Core v6.0.0-beta (v6.0.0-beta.1)

Activity

  1. added
    WG-Cmdletsgeneral cmdlet issues
    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif
    on May 12, 2017
  2. changed the title [-]Common parameters -OutVariable, -InformationVariable, and -WarningVariable always return a [System.Collections.ArrayList] instance, even with a single object[/-] [+]Common parameters -OutVariable, -ErrorVariable, -WarningVariable, and -InformationVariable always return a [System.Collections.ArrayList] instance, even with a single object[/+] on Aug 21, 2017
  3. Jaykul commented on Mar 16, 2018

    @Jaykul
    Contributor

    While I agree that it's weird that this doesn't behave like pipeline output (and I insist that the only thing that PowerShell does this for is pipeline output) ...

    It has been like this since the beginning.

    Changing it at this point doesn't help much, and risks breaking all existing code that relies on these common parameters ...

  4. mklement0 commented on Mar 17, 2018

    @mklement0
    ContributorAuthor

    Joel Bennett (@Jaykul): If the consensus is that this change is too risky, so be it, and documenting the issue is the best we can do.
    Personally, I think it's a wart that warrants removal - it can trip up new users (as it did me).

    and I insist that the only thing that PowerShell does this for is pipeline output

    That is not much of a restriction, however, given the pervasive use of pipelines, even in places where it is not obvious:$(...), @(...), &, ., script-block arguments.

    To give a few examples, all of which output $True:

    $(, 1) -is [int]
    (. { , 1 }) -is [int]
    (& { , 1 }) -is [int]
    ('' | Select-Object @{ n='foo'; e = { , 1 } }).foo -is [int]

    There is no @(...) example, because @(...) by design ensures array-valued output - though it would still recreate any input collection as a [object[]] array.

  5. Jaykul commented on Mar 19, 2018

    @Jaykul
    Contributor

    The point is: you're saying you want to change 4 common parameters (two of which have been around since the beginning) to change their type after the end of the pipeline (they obviously still have to be an Arraylist within the pipeline). That's a serious breaking change.

    Your justification is just that you want it to be more like pipeline output.

    My point is that making these common parameters more like pipeline output doesn't seem like a useful goal. They are not like pipeline output -- they are output parameters. In fact, sometimes (when you use the +name syntax) they are actually reference parameters. Additionally, they exist within the pipeline. -- where they are more like streams than a finished output collection -- and changing them from the live stream type to something else at the end would just be confusing.

  6. mklement0 commented on Mar 19, 2018

    @mklement0
    ContributorAuthor

    Your justification is just that you want it to be more like pipeline output.
    They are not like pipeline output -- they are output parameters.

    In the case of -OutVariable the very purpose of the parameter is to capture pipeline output
    and my primary concern is over the lack of symmetry between $var = ... and ... -OutVariable var.

    I agree that the case is not clear-cut for the other -*Variable parameters in terms of unwrapping behavior, though my vote is for consistency.

    To avoid a distraction, I'll close this issue, so we can focus on the behavior of -OutVariable, and the outcome of that discussion can then inform treatment of the other -*Variable parameters.

    Let's continue the discussion here.

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-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifWG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions