We need a new operator '..' to access to members of childitems of a collection #19787
Replies: 33 comments
-
If I understand you correctly, you want a dedicated operator named I don't quite understand how your 2nd example fits into this, however. Can you clarify by updating the original post, and, while you're at it, use code blocks ( Having a dedicated operator would potentially allows us to solve 3 existing problems:
|
Beta Was this translation helpful? Give feedback.
-
How does Powershell differentiate .. when used as the range operator from .. when used to access the members of a collection. not arguing against the need to access the collection member's properties just don't understand how the two uses of the same operator symbol will work |
Beta Was this translation helpful? Give feedback.
-
I was focusing on making the case for such an operator in the abstract, but you're right, the syntactic form needs careful consideration too.
Groovy uses But let's see if there is a fundamental willingness to introduce such an operator. |
Beta Was this translation helpful? Give feedback.
-
Sorry, my english is poor! 1..10 or(PowerShell 6.0+) 'a'..'z' or $from..$to and their mixed mode combination. But when we use the new operator as i said, it's like: $files..Length the second operand is a member name, it's not a variable which must starts with '$'. function one { 1 }
#3..one is error code
#we must write like this
3..(one)
#or
3..$(one) The second example is intend to use items of IDictionary object as elements of collection object, just like the 1st example. It's a extensional advice. |
Beta Was this translation helpful? Give feedback.
-
Thanks for updating the initial post, @nutix56. Re the 2nd example: I'm still not entirely clear what you expect the output of As for the syntax: I meant confusing to the user, not necessarily whether it technically works (syntactically):
PowerShell supports expressions as property names, so |
Beta Was this translation helpful? Give feedback.
-
The first issue example 1, work-around is The second example I don't think shows anything. There is no 'first' property that is getting overloaded. |
Beta Was this translation helpful? Give feedback.
-
Thanks, @msftrncs. There's a more concise workaround: Interesting that the logic is reversed with hashtables (entry keys shadowing the hashtable's own properties when using dot notation). Unfortunately, that precludes meaningful application of the potential new operator to hashtables, because If the logic weren't reversed, that is, if the behavior were consistent with member enumeration, |
Beta Was this translation helpful? Give feedback.
-
@mklement0 This is an aside, but WRT to assigning to a property on each member of a collection, you can do it with .foreach() as follows: PS[2] (8) > $l = @{a=1},@{a=2},@{a=3}
PS[2] (9) > $l.foreach("a", 13)
PS[2] (10) > $l
Name Value
---- -----
a 13
a 13
a 13 Now regarding what operator we might use (since '..' is definitly out for the reasons stated) Groovy uses '*' for spreading (=== "splatting") whereas PowerShell uses '@'. Consequently the corresponding operator in PowerShell would be "@."as in: $lengths = $list@.Length Now in a previous language I designed, I used '->' for a similar purpose (but slightly different semantics) $lengths = $list->Length I liked the fact that it was clearly visible in the code. Another possibility is to have a semantic such that if the RHS is a scriptblock, then it gets applied to each element, minifying the foreach scenario even further. (1..10)->{$_ * 2} (Early in PowerShell we spent a bunch of time talking to the folks in the languages group in MS Research. One of the researchers was very keen on having a minimal foreach/map/apply/select notation so this would probably make him happy :-) |
Beta Was this translation helpful? Give feedback.
-
Thanks, @BrucePay. Good point about Thanks for the reminder about Though
In the case of a script block, however, I feel that (1..10).ForEach({$_ * 2}) # I know you can omit the (...), but that seems fraught to me. Though, as I've proposed, I wish we had (1..10) -foreach {$_ * 2} Yes, getting carried away with abstract symbols is generally problematic, and there is an inherent tension between readability and concision. However, if the The use of symbols is less problematic for frequently used features, because seeing them often makes them second nature. Here, |
Beta Was this translation helpful? Give feedback.
-
I don't see the need for this. I find it rare that a property conflicts with a collection property, and for the other cases, you can easily do |
Beta Was this translation helpful? Give feedback.
-
As an aside: I suggest we use
|
Beta Was this translation helpful? Give feedback.
-
All your points except your second one can be made for |
Beta Was this translation helpful? Give feedback.
-
By that logic, member enumeration via The second point, performance, matters - member enumeration is fast, and you don't want to sacrifice speed just to work around its limitations. Additionally, re concision: Use of aliases is discouraged in scripts, so your alternative would really be |
Beta Was this translation helpful? Give feedback.
-
But whenever a new operator is introduced you have to consider that this is one additional thing for people to learn, one more thing that someone might not understand when they read a PowerShell script. |
Beta Was this translation helpful? Give feedback.
-
Yes, but one should have been introduced. As great a feature as member enumeration was to introduce in principle, conflating it with the regular member accessor, |
Beta Was this translation helpful? Give feedback.
-
Although that is also technically valid with numbers (it's not very often we do fractional modulo): $ten = 10; $ten%.2 PowerShell won't allow a |
Beta Was this translation helpful? Give feedback.
-
The operator focus on: But, maybe it's better to use '...' We can use it as a replacement for the simplest loop statement, like
=>
'...' means more enumerable elements, when we use it between a collection object and its element property name, it means enumerate the property on each element of the collection object. I think it's very informal. |
Beta Was this translation helpful? Give feedback.
-
If all you want is a single property why not use select-object PS> Get-ChildItem -File | select -ExpandProperty length |
Beta Was this translation helpful? Give feedback.
-
It's more convenient, doesn't it? |
Beta Was this translation helpful? Give feedback.
-
To recap the issue succinctly: Member enumeration with
Its only drawback is the inability to predictably target the elements' members rather than the collection object's in case of naming conflicts. Having a distinct syntax - next to The current workarounds fall short:
To my mind, the best candidate for the new syntax, after the discussion above, is $collection%.Length # Return the *elements'* .Length property values. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure we need it (since collections don't have many members), but that syntax seems clean, concise, and unambiguous. |
Beta Was this translation helpful? Give feedback.
-
Technically, isn't |
Beta Was this translation helpful? Give feedback.
-
@msftrncs: yes, though that is somewhat slower - and more verbose - than the aforementioned Speaking of which: # Assign the - invariably *same* - property value to all elements of the array.
(Get-Item *.txt)%.LastWriteTime = Get-Date @Jaykul, glad to hear you like the syntax; re the need for it:
# Predictably call .ToString() on the elements, not the collection itself.
((Get-date), (Get-Date).AddDays(1))%.ToString('dd')
# The above would be the concise equivalent of:
((Get-date), (Get-Date).AddDays(1)).ForEach('ToString', 'dd') |
Beta Was this translation helpful? Give feedback.
-
Yes, but I don't find this argument compelling at all:
I mean, that's obviously true. But most of the time, it doesn't matter. It's not that this is non-deterministic and might be different on different computers, so I can just write it and run it. Adding a longer syntax that's more explicit about what it's doing and therefore theoretically clearer about what will happen doesn't mean that anyone's going to use it, because while it's technically clearer, we can't go back in time and do this unambiguously (i.e. we won't remove the fact that So this will be a great in those specific but rare situations where we actually run into a duplicate -- but people will have to actually know about it, and be 100% sure they don't need their code to run in PowerShell 7 or earlier. Potentially this would just add an optional operator that's confusingly similar to several other operators and practically not used in the real world, and is therefore always confusing when people see it. |
Beta Was this translation helpful? Give feedback.
-
The point is: You shouldn't have to worry about when it does matter. When you write code, your intent is always clear: you'll know ahead of time whether you're looking for a property of the collection or properties of its elements. Currently, if you're not careful (and remember all member names of the collection you're dealing with), that intent can be thwarted in the latter case, with potentially confusing symptoms. Having a direct, unambiguous expression of one's intent in the form of Yes, the behavior of
That applies to any new feature; it's the price of progress. As for the concern about adding another, similar-looking operator: Let's make it easy to look up help for operators: #11339 |
Beta Was this translation helpful? Give feedback.
-
The problem is that this isn't true:
Even if we add this operator, only half of that is possible: you'll be able to specify that you're looking for a property of the elements. That's it. When you're looking at code that uses If we do add this feature, we should also add a script analyzer rule that recommends people use |
Beta Was this translation helpful? Give feedback.
-
That's all I ask for. You can't fix the past, but you can make things better in the future.
Great, if feasible - but it sounds like it isn't.
That would be great if you didn't have to worry about it, but the whole reason for this discussion is that you currently do (situationally, and you may not anticipate when it'll hit you), and |
Beta Was this translation helpful? Give feedback.
-
To compliment @mklement0 arguments:
My thoughts: it doesn't have to be a shorthand syntax, it just need to be consistent and easy readable. Why not adding a PowerShell property like member to each collection (e.g. using the Wishful thinking: Currently:
|
Beta Was this translation helpful? Give feedback.
-
@iRon7, with the caveat that you need to specify the member name as a quoted string, the $dates = , (Get-Date) * 3
$dates.ForEach('GetType').Name
$dates.ForEach('ToString', 'dddd') While your proposal of a
|
Beta Was this translation helpful? Give feedback.
-
P.S., @iRon7: having a member do double duty as both a method and a property would also be confusing and introduce an inconsistency, because invoking method members without |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
All reactions