Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select-Object hashtable syntax is long-winded, support a shorter version? #8107

Closed
HumanEquivalentUnit opened this issue Oct 23, 2018 · 18 comments
Labels
Issue-Discussion the issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif Issue-Enhancement the issue is more of a feature request than a bug Resolution-No Activity Issue has had no activity for 6 months or more WG-Cmdlets-Utility cmdlets in the Microsoft.PowerShell.Utility module

Comments

@HumanEquivalentUnit
Copy link
Contributor

HumanEquivalentUnit commented Oct 23, 2018

Select-Object's hashtable syntax - even with abbreviating the key names to one character, it's a lot of code and symbols, and feels like it could be cleaner. The simple case of taking one property value unchanged, but with a new name, could be a lot cleaner.

What if a single-key hashtable could be used, where the key is the new property name, and the value is either a string of the original property to rename, or a scriptblock calculation. e.g.

# property rename, and property calculation, shown in:
# Long form
# Short form - nicer, but not good for scripts because it's using abbreviations
# Suggested form

gci | select @{Label='ShortName'; Expression='BaseName'}, @{name='size'; expression={$_.Length / 1MB}}

gci | select @{L='ShortName'; E={$_.BaseName}}, @{N='size'; E={$_.Length / 1MB}}

gci | select @{ShortName='BaseName'}, @{Size={$_.Length / 1MB}}
@vexx32
Copy link
Collaborator

vexx32 commented Oct 23, 2018

I would actually recommend also supporting collapsing of the syntax into a single hashtable as well. Your last example could look like this instead:

gci | select @{ShortName='BaseName'; Size={$_.Length / 1MB}}
# or
Get-ChildItem | Select-Object -Property @{
    ShortName = 'BaseName'
    Size      = { $_.Length / 1MB }
}

@romero126
Copy link
Contributor

Wouldn't it be just as wise to change the Expression from a statically Calculated property, To a more fluid property such as a ScriptProperty.
$x = Get-Date | Add-Member -MemberType ScriptProperty -Name "TicksCalculated" -Value { $this.Ticks + 40 }
And you can change values fluidly and reflect the object's most current values.

$x.Ticks = 20
$x.TicksCalculated would display as 60 next time it is viewed.

@vexx32
Copy link
Collaborator

vexx32 commented Oct 23, 2018

If that is done then there becomes no way to actually use a static calculated property when you might want that, though. And I think in most cases a static noteproperty is all most folks want.


I'd think it would be more effective to implement that as a separate -DynamicProperty parameter if we did something like that.

@RichardSiddaway
Copy link

Using Add-Member seems to be a step into the past. Using a calculated field is a simpler operation.

simplifying the syntax of calculated fields (this affects format-table and sort-object as well) is a good idea as long as the original syntax is still available otherwise you're going to break a ton of code.

@RichardSiddaway
Copy link

I'd also want to retain the ability to mix the properties from the object with the calculated fields so something like

gci | select Mode, @{ShortName='BaseName'}, LastwriteTime, @{Size={$_.Length / 1MB}}, CreationTime

@SteveL-MSFT SteveL-MSFT added Issue-Enhancement the issue is more of a feature request than a bug Issue-Discussion the issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif WG-Cmdlets-Utility cmdlets in the Microsoft.PowerShell.Utility module labels Oct 24, 2018
@iSazonov
Copy link
Collaborator

This is useful for Format-* cmdlets too. Can/should we this in the same time?

@bstrautin
Copy link

I implemented this feature as a proof-of-concept for myself a few months ago, but haven't polished it or added tests. (Happy to contribute the changes, but they're definitely not PR-ready.)

Observations:

  • The most straightforward way to implement this request is to modify VerifyHashTable in MshParameter.cs, which affects Select-Object, Format-Table, Format-List, Format-Custom, Form. ("Yes" to @iSazonov re: Format-*, but needs some design decisions)
  • It feels much nicer to use than the current syntax, especially Select-Object and Sort-Object. (e.g. gci | sort [ordered]@{Extension='d'; Length='a'; {$_.Name[-1]}='d'})
  • Even more convenient would be syntax for KeyValuePair literals. (Almost certainly a breaking change though, and abbreviated hashtable syntax is better than what exists today.)

Complications:

  • It's necessary to use [ordered]@{...} instead of just @{...}. Otherwise the properties don't appear in the expected order, or even worse, sorting works unexpectedly.

  • The Format-* cmdlets have more than two useful parameters, and it's unclear how best to express more than Name & Expression in an abbreviated form. Some potential options:

    1. gci | ft @{SizeInBytes='Length', '#,0', 'right'; SecondsOld = {([datetime]::UtcNow-$_.LastWriteTimeUtc).TotalSeconds}, '#,0', 'right'; LastModified='LastWriteTime', 'yyyy-mm-dd'}
    2. Allow Name=Value and apply the other parameters across: gci | ft @{SizeInBytes='Length'; SecondsOld={([datetime]::UtcNow-$_.LastWriteTimeUtc).TotalSeconds}; f='#,0'; a='right'}, @{LastModified='LastWriteTime'; f='yyyy-mm-dd'}
    3. Only allow Name=Value: gci | ft @{SizeInBytes='Length'; SecondsOld={([datetime]::UtcNow-$_.LastWriteTimeUtc).TotalSeconds}}, @{LastModified='LastWriteTime'}
  • Error reporting is more difficult, because it's ambiguous which format was the user attempting to use. (My implementation doesn't try to analyze what went wrong with the short-form parameters, and just throws the error raised by the long-form interpretation.)

Related, helpful potential changes:

  • Implicitly parse hashtable arguments as ordered hashtables. (Otherwise sort will be unpredictable, and the others will have out-of-order properties)
  • Format-Html should use ExpressionEntryDefinition, AlignmentEntryDefinition, and WidthEntryDefinition instead of defining its own HashtableEntryDefinition.
  • Enhance CommandParameterDefinition and/or HashtableEntryDefinition to indicate mutually exclusive parameters and (optional) parameter validation. Otherwise the modifications to VerifyHashTable will be brittle / hard-coded / hackish, e.g. relying on the subclass of HashtableEntryDefinition. (Currently CommandParameterDefinition is just a light helper wrapper around list of parameters and their accepted types.)
  • Make the MshParameter mechanism public, to allow functions to use the functionality.

@iSazonov
Copy link
Collaborator

@lzybkr @BrucePay Could you please look the Issue? Have you thoughts what is a best design and how we can better implement this?

@HumanEquivalentUnit
Copy link
Contributor Author

It seems that propertly supporting the Format* cmdlets and having it collapse down to one hashtable with multiple properties makes it much harder. Those are things I don't really want, as much as the change to Select-Object. Would it be possible to handle select-object in one change and those later?

Implicitly parse hashtable arguments as ordered hashtables. (Otherwise sort will be unpredictable, and the others will have out-of-order properties)

It would be a breaking change if @{} became an ordered hashtable literal, the return type would change to OrderedDictionary; using [ordered]@{...} is probably less confusing than adding a new hashtable syntax for ordered literals, or parsing it differently in special cases.

@iSazonov
Copy link
Collaborator

Would it be possible to handle select-object in one change and those later?

Yes, of cause. I meant that there may be a common code.

@bstrautin
Copy link

Special-casing Select-Object would require that it abandons the common code that all the hashtable-parameter-using cmdlets share. Plus, the collapsed-hashtable-argument style is great for the other cmdlets too - but there are some corner cases.

Implicitly parse hashtable arguments as ordered hashtables. (Otherwise sort will be unpredictable, and the others will have out-of-order properties)

It would be a breaking change if @{} became an ordered hashtable literal, the return type would change to OrderedDictionary; using [ordered]@{...} is probably less confusing than adding a new hashtable syntax for ordered literals, or parsing it differently in special cases.

Requiring [ordered] to get proper results when using the short-form syntax will cause people to make mistakes, forever. KeyValuePair literals are probably the only clean-ish solution to this problem; all the other opitons involve introducing some quirky behavior.

@iRon7
Copy link

iRon7 commented Feb 20, 2020

@HumanEquivalentUnit, thanks for linking my issue.
(Although, I searched for an already similar request, I didn't came across this one.)
The idea is indeed almost the same, it slightly differs in a sense that it isn't relying on the order of the property attributes but on the (implicit) property attribute type. Meaning that e.g. a the calculated expression should be an explicit [Expression] type, or an implicit [ScriptBlock] (based constructor of the expression class):

Taking @bstrautin example:
(using the powershell wrappers from #11866)

Implicit syntax:

gci | ft2 @{
	SizeInBytes = {$_.Length}, '#,0', 'right'
	SecondsOld = {([datetime]::UtcNow-$_.LastWriteTimeUtc).TotalSeconds}, '#,0', 'right'
	LastModified = {$_.LastWriteTime}, 'yyyy-mm-dd'
}

Explicit syntax:

gci | ft2 @{
	SizeInBytes = [Expression]'Length', [FormatString]'#,0', [Alignment]'right'
	SecondsOld = [Expression]{([datetime]::UtcNow-$_.LastWriteTimeUtc).TotalSeconds}, [FormatString]'#,0', [Alignment]'right'
	LastModified = [Expression]'LastWriteTime', [FormatString]'yyyy-mm-dd'
}

The disadvantage is that the concerned property attribute classes need to be predefined. At the other hand, this could also be turned into an advantage if the properties attributes could be attached to the concerned object properties to be used as a default behavior for the related cmdlet as Format-Table and Sort-Object.

I am not sure what I should do with my request #11866, close it?

@vexx32
Copy link
Collaborator

vexx32 commented Feb 20, 2020

@iRon7 if your request is effectively a duplicate, probably best to close it and summarise any extra points you feel aren't covered in this issue already (a bit like you already did, but feel free to add on any extra points that haven't been covered yet) 🙂

Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

2 similar comments
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

@microsoft-github-policy-service microsoft-github-policy-service bot added Resolution-No Activity Issue has had no activity for 6 months or more labels Nov 16, 2023
@iRon7
Copy link

iRon7 commented Nov 16, 2023

This issue has an active linkage at mentioned this issue on Oct 2

Copy link
Contributor

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Discussion the issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif Issue-Enhancement the issue is more of a feature request than a bug Resolution-No Activity Issue has had no activity for 6 months or more WG-Cmdlets-Utility cmdlets in the Microsoft.PowerShell.Utility module
Projects
None yet
Development

No branches or pull requests

8 participants