Skip to content

Why is [pscustomobject] the same as [psobject], even though a distinct [System.Management.Automation.PSCustomObject] type exists? #4344

Closed

Description

Surprisingly, [pscustomobject] is the same as [psobject]: both these type accelerators point to type [System.Management.Automation.PSObject], even though there is a distinct [System.Management.Automation.PSCustomObject] type.

Mostly, this conflation goes unnoticed (and has come up before - see #2295), but:

  • what is the rationale for it?

  • it makes for surprising behavior on occasion - see below.

# Even though their names strongly suggest identity, they are different types.
> [pscustomobject] -eq [System.Management.Automation.PSCustomObject]
False

# Any object returned by a *command* (as opposed to an expression)
# returns $True for -is [psobject], and therefore also [pscustomobject]
> (Get-Item /) -is [pscustomobject]
True

# Casting anything other than a hashtable literal to [psobject] is a no-op, 
# and therefore also with [pscustomobject]
> ([pscustomobject] 666).GetType().Name
Int32

Environment data

PowerShell Core v6.0.0-beta.4

Activity

  1. added
    WG-Enginecore PowerShell engine, interpreter, and runtime
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Jul 26, 2017
  2. lzybkr commented on Jul 26, 2017

    @lzybkr
    Contributor

    I'm not aware of a good reason other than legacy reasons and concerns over breaking existing scripts.

  3. mklement0 commented on Jul 26, 2017

    @mklement0
    ContributorAuthor

    Thanks, Jason Shirk (@lzybkr).

    On a meta note:

    While I will certainly add that information to my personal notes, my concern is that these nuggets of information - sprinkled throughout the issues reported (#4347 is another recent example) - are not documented in an easily discoverable fashion.

    I've seen the Documentation Needed label, but it is (a) used sparingly and (b) is perhaps too broad, given that the information in question is often too esoteric / advanced for the standard help topics.

    I do wish we kept track of such issues, however, perhaps with something like an Advanced-Topic Documentation Needed label.

  4. SteveL-MSFT commented on Jul 26, 2017

    @SteveL-MSFT
    Member

    For now, I suggest using Documentation Needed as a way to review issues later to determine where we need to add documentation (and not just for PRs where a doc change is also needed).

    Thanks for your continued depth of research into these advanced topics.

  5. iSazonov commented on Aug 3, 2017

    @iSazonov
    Collaborator

    Michael Klement (@mklement0) I marked the Issues. Could you please add there that we need document or open Issues in Doc repo?

  6. mklement0 commented on Aug 3, 2017

    @mklement0
    ContributorAuthor

    Ilya (@iSazonov):

    Thank you.

    add there that we need document

    Do you mean I should also add a comment stating that documentation is needed? What would that gain us beyond the label?

    I think I'll hold off on creating documentation issues until it's clearer in what format and to what extent these advanced issues will be documented.

  7. iSazonov commented on Aug 4, 2017

    @iSazonov
    Collaborator

    Do you mean I should also add a comment stating that documentation is needed?

    Yes, we'll keep the time of who's going to document if it's not you.

  8. mklement0 commented on Aug 4, 2017

    @mklement0
    ContributorAuthor

    Yes, we'll keep the time of who's going to document if it's not you.

    I don't know what you mean by that.

  9. iSazonov commented on Aug 4, 2017

    @iSazonov
    Collaborator

    Sorry, I meant that we need clear conclusion so that anyone can document it.

  10. mklement0 commented on Aug 4, 2017

    @mklement0
    ContributorAuthor

    Ilya (@iSazonov): I see, good point. I'll see what I can do, but I hope that if I don't get around to it, others will still be able to glean from the existing comments what is documentation-worthy.

  11. mklement0 commented on Dec 2, 2017

    @mklement0
    ContributorAuthor

    A concrete example of where the identity of [pscustomobject] and [psobject] is problematic: the -as type operator - see #4343 (comment)

  12. AikenBM commented on Mar 7, 2018

    @AikenBM

    Personally, I've always found this behavior extremely confusing:

    PS> (New-Object -TypeName System.Management.Automation.PSObject -Property @{Property = 'Value'}).GetType().FullName
    System.Management.Automation.PSCustomObject
    
    PS> (New-Object -TypeName System.Management.Automation.PSCustomObject -Property @{Property = 'Value'}).GetType().FullName
    New-Object : A constructor was not found. Cannot find an appropriate constructor for type System.Management.Automation.PSCustomObject.
    
    PS> ([PSCustomObject]@{Property = 'Value'}).GetType().FullName
    System.Management.Automation.PSCustomObject
    
    PS> ([PSObject]@{Property = 'Value'}).GetType().FullName
    System.Collections.Hashtable
    
  13. mklement0 commented on Mar 7, 2018

    @mklement0
    ContributorAuthor

    AikenBM:

    Agreed - that's a nice demonstration of the issues.

    The sense I'm getting is that [System.Automation.PSObject], as an implementation detail, should be hidden - see #5551; hiding it completely - i.e., taking away the availability of [psobject] as a type available to the user, is unfortunately no longer an option for reasons of backward compatibility.

    Note that a [psobject] cast to anything is seemingly quietly ignored, but in reality you're creating a benign-for-the-most-part-but-not-always extra, hidden [psobject] wrapper (see #5579):

    > @{ Property = 'Value' } -is [psobject]
    False
    
    > ([psobject] @{ Property = 'Value'} ) -is [psobject]
    True  # !! Extra [psobject] wrapper was created.

    On a related note, #4343 shows that "know thyself" doesn't apply to custom objects with respect to the -as operator:

    # Sample custom object.
    > $co = [pscustomobject] @{ one = 1 }
    
    > $co -is [pscustomobject]  
    True  # OK
    # Same with `$co -is [psobject]` due to the identity of [psobject] and [pscustombject]
    
    > $co -is [System.Management.Automation.PSCustomObject]
    True  # OK
    
    # Now try -as
    > $co -as [System.Management.Automation.PSCustomObject]
    # !! $null - $co doesn't know its own type
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-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aResolution-AnsweredThe question is answered.WG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions