Powershell: Adjusting the SideIndicator output of Compare-Object (Moved discussion from PR #12511)

Created on 29 May 2020  路  3Comments  路  Source: PowerShell/PowerShell

This started in PR #12511, in which, in the output field SideIndicator of Compare-Object, I wanted to change <= to <== and vice-versa to:

  1. Avoid confusion with <= with less-than-or-equal
  2. Avoid misrendering of <= by fonts that support coding ligatures (See image 1, uploaded by @rkeithhill here)

Several alternative solutions have been proposed:

  1. Introduce a new Enum type that represents the possible return values in the SideIndicator field more abstractly (idea by @vexx32 here)
  2. A parameter for Compare-Object that sets the output strings for the possible values that could then be set to a custom default value by the user (idea by @adityapatwardhan here)

Again, see PR #12511 for the exisiting discussion on this topic.

Image 1:

Postscriptum: Mentioning all participants in the PR conversation
@iSazonov @adityapatwardhan @rkeithhill @vexx32

Issue-Discussion Issue-Enhancement

Most helpful comment

How about keeping SideIndicator as a legacy field and using something new to store an Enum that would be more future-proof? I really like the idea of formalizing the side indicator.

We could call the new field Side

All 3 comments

This is the PSCustomObject output by Compare-Object:

PS> $r = Compare-Object (gc .\t1.ps1) (gc .\t2.ps1)
PS> $r[0] | fc

class PSCustomObject
{
  InputObject = Trap { 'Shame.'; exit 1 }
  SideIndicator = =>
}

PS> $r | gm


   TypeName: System.Management.Automation.PSCustomObject

Name          MemberType   Definition
----          ----------   ----------
Equals        Method       bool Equals(System.Object obj)
GetHashCode   Method       int GetHashCode()
GetType       Method       type GetType()
ToString      Method       string ToString()
InputObject   NoteProperty System.String InputObject=Trap { 'Shame.'; exit 1 }
SideIndicator NoteProperty string SideIndicator==>

In a script, a user could do a compare like so '=>' -eq $r[0].SideIndicator. Hence, simply changing strings for the various SideIndicators would be a breaking change. Converting this to an enum is one possible fix. However, I still think that would be a breaking change. Consider this code:

$r[0].SideIndicator.StartsWith('=')

An enum doesn't have a StartsWith() method and would throw.

What I propose is that we add a new field to the PSCustomObject called SideIndicatorDisplay (or something akin to that) which would hold the new side indicator strings that would get rendered. And rendered nicely in a console using a ligature font. :-)

This would require some tinkering with the PSCustomObject i.e., giving it a formal type name and then adding the appropriate formatting XML to render the InputObject and the SideIndicatorDisplay fields and not the SideIndicator field. The SideIndicator would remain unchanged - hence no breaking changes.

Then we could optionally add the -SideIndicator parameter that would allow the user to configure the strings they want to use in the SideIndicatorDisplay field.

How about keeping SideIndicator as a legacy field and using something new to store an Enum that would be more future-proof? I really like the idea of formalizing the side indicator.

We could call the new field Side

Yeah even if there's some duplication of data by maintaining a legacy field, I do think it's more useful to have an abstracted and more clear indicator.

Every time I use this cmdlet I _again_ have to look up which side refers to which to make sure I haven't confused them all over again. We don't have -LeftObject and -RightObject, we have -ReferenceObject and -DifferenceObject, which is innately confusing.

I'd ask that the property name and/or value via the enum naming be more indicative of which of the input sets is being referred to. I.e., should explicitly mention Reference /Difference/Both somewhere in the naming so it's clear which items are in which sets.

Aside: I kind of feel like it's a bit weird we _don't_ have a formal object type for this cmdlet. Most other PS-shipped cmdlets define their own class types. Might be a good opportunity to create a class type for it. If we do, we can define the SideIndicator property to be a faux-property that just checks the Side (or whatever we call it) enum property and emits the backwards-compatible string based on that only when you query it.

No point storing string data if we can easily generate it on the flip of a coin based on a couple string const values and the enum value.

Was this page helpful?
0 / 5 - 0 ratings