powershellcollectionsterminologydefinitionscalar

What is a "Scalar" in PowerShell


The term scalar is often used in PowerShell issues and documentation along with e.g. the about_Comparison_Operators document. I think, I do have an abstract understanding of its meaning (in fact I am using the word myself quite often) but I am unsure about the concrete PowerShell definition.

Scalar data type (Wikipedia):

A scalar data type, or just scalar, is any non-composite value.

Converting from scalar types (about_Booleans)

A scalar type is an atomic quantity that can hold only one value at a time.

But how exactly would I (script wise) check for a scalar in PowerShell?
E.g. should a DateTime Struct and a collection with single item (as [Int[]]1) considered a scalar?
There is no concrete scalar type or interface definition, to do something like:

If ($Something -is [Scalar]) { ...

So, I guess the concrete PowerShell definition is something like:

$IsScalar =
    ($_ -isnot [Management.Automation.PSCustomObject]) -and
    ($_ -isnot [ComponentModel.Component]) -and           
    ($_ -isnot [Collections.IDictionary]) -and  # Probably covered by ICollection
    ($_ -isnot [Collections.ICollection])         

But not sure if that actually covers it.


Solution

  • To add to the helpful information in your question and in the comments:

    There are two, context-dependent definitions of what you might loosely call "scalar" in PowerShell, and while they technically differ, the difference typically doesn't matter:

    The - comparatively rare - scenarios where the two definitions of "scalar" do make a difference:


    "Scalars" in enumeration contexts:

    Enumeration contexts are:

    In any such enumeration context, a "scalar" is any object that cannot be or isn't auto-enumerated.

    Auto-enumeration means:

    That is:

    The following function encapsulates the exact logic PowerShell uses to determine automatic enumerability;[4] it accepts any object and indicates whether PowerShell would auto-enumerate it in enumeration contexts.

    function Test-Enumerability {
      [CmdletBinding()]
      param (
        [Parameter(Mandatory)]
        [object] $InputObject
      )
    
      (
        $InputObject -is    [System.Collections.IEnumerable] -and
        $InputObject -isnot [System.Collections.IDictionary] -and
        $InputObject -isnot [string]                         -and 
        $InputObject -isnot [System.Xml.XmlNode]
      ) -or
        $InputObject -is    [System.Data.DataTable]          -or
        $InputObject -is    [System.Collections.IEnumerator]
      
    }
    

    An informal summary of the above:


    [1] Here's the link to the source code, as of this writing (this logic is highly unlikely to change, however).

    [2] This special singleton is [System.Management.Automation.Internal.AutomationNull]::Value]; for more information, see this answer.

    [3] The same applies to types implementing the generic counterparts of these interface, IEnumerator`1 and IEnumerable1`, given that these derive from their non-generic cousins.

    [4] Here's the link to the source code, as of this writing (this logic is highly unlikely to change, however).

    [5] Note that PowerShell only tests for the non-generic dictionary interface, System.Collections.IDictionary, not also for its generic counterpart, System.Collections.Generic.IDictionary`2. Since the latter does not derive from the former - unlike in the IEnumerable / IEnumerable`1 pair - types that implement only the generic interface unexpectedly are auto-enumerated; a prominent example is System.Dynamic.ExpandoObject; see GitHub issue #15204 for a discussion of this problematic behavior.