3

I'm finding it very hard to google the answer to what the difference is between these two way of executing method calls in :

$member = "1.2.3.4:567" # IPaddress + port for demonstration
$vals1 = $member.Split(":") # typical .NET way of executing String.Split
$vals2 = $member.Split( (,":") ) # something else which ive seen in examples which I dont understand

In the above, both $vals1 and $vals2 appear to have the same result (an array with 2 elements). I would typically use the first way, but in examples (of using both Split and other method calls) I see the second used.

My question is what is the second one doing which is different, and is there any advantages to using it which I may not understand?


Edit: Please don't focus on the Split method - I'm not asking about overloads of Split!

Jamiec
  • 133,658
  • 13
  • 134
  • 193

3 Answers3

5

The comma operator used as a unary is what you are seeing. It is a shorthand way to create an array. PowerShell will unroll array in pipelines which is usually desired and standard behavior. Where I see this commonly used is to mitigate that feature of PowerShell

What you would then do in some cases though you do not want PowerShell to unroll the complete array is through the comma unary operator in front of that array. Consider the difference in outputs

Using regular array notation

$array = 1,2,3
$array.Count
$array | ForEach-Object{$_.GetType().FullName}

3
System.Int32
System.Int32
System.Int32

Using the unary operator to create a jagged array

$commaArray = ,@(1,2,3)
$commaArray.Count
$commaArray | ForEach-Object{$_.GetType().FullName}

1
System.Object[]

In the second example the array gets passed as a whole. PowerShell still unrolled it from a single array with one element that was itself an array to that single array 1,2,3.

There are other cases for its use as well. I would more commonly see regular arrays declared statically with 1,2,3 or sometimes the @() is needed depending. Result is the same for both of those.

mklement0
  • 382,024
  • 64
  • 607
  • 775
Matt
  • 45,022
  • 8
  • 78
  • 119
1

,";" is a trick/shorthand to create an array (try (,";").GetType()). Why would you need this? Well, let's try calling Split with a list of values directly:

"abc".Split('a','b')

Cannot convert argument "count", with value: "b", for "Split" to type "System.Int32": "Cannot convert value "b" to type "System.Int32". Error: "Input string was not in a correct format.""

Doesn't work because the parameters are passed separately, rather than as a char[]. So could we use the comma trick to fix this?

"abc".Split((,'a','b'))

Cannot convert argument "separator", with value: "System.Object[]", for "Split" to type "System.Char[]": "Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Char"."

No, because we still have a type mismatch. That's because this approach is too clever for its own good. A much more readable way to create an array is the @() operator:

"abc".Split(@('a', 'b'))

And this calls the desired overload of Split.

Jeroen Mostert
  • 27,176
  • 2
  • 52
  • 85
  • Ok, so i'm partially following you - I tried `(,";").GetType()` and get an `object[]`. But to be honest this answer has lost me when it starts focusing on overloads of `Split`. I'm trying to understand why someone would use that method `(,$someParam)` in a method call *in general* – Jamiec Sep 28 '16 at 11:28
  • @Jamiec: To prevent [unrolling](http://stackoverflow.com/questions/1827862/what-determines-whether-the-powershell-pipeline-will-unroll-a-collection). You wouldn't (shouldn't) do this *in general*, because, well, that's a silly habit to get into. But unrolling is a real thing that can interfere at times, and sticking a comma in front is a quick and dirty way of preventing it. (Or rather, adding another level to the unrolling.) – Jeroen Mostert Sep 28 '16 at 11:33
  • I wouldn't call it a trick per sei. Its using the unary operator to mitigate PowerShells unrolling of arrays. https://technet.microsoft.com/en-us/library/hh847732.aspx – Matt Sep 28 '16 at 11:35
  • I guess I'm missing something fundamental here about how powershell works. I'm very used to .NET development, but there is some bit of this im not getting. ie, `("a","b")` also gives me an array. Whats special about a blank first element? – Jamiec Sep 28 '16 at 11:36
  • Looks like it's someone's idea of kewl haxorz speedup. Actually there's no difference. – wOxxOm Sep 28 '16 at 11:38
  • @Jamiec: the difference is that `("a")` will not give you an array since it's just a parenthesized string. `,"a"` will give you an array with exactly one element. But so will `@("a")`, and that's a lot more readable. – Jeroen Mostert Sep 28 '16 at 11:39
  • @wOxxOm so what's the *right* way to call a method which takes a string array parameter if this is the hack? – Jamiec Sep 28 '16 at 11:39
  • @JeroenMostert - thanks - thats the bit I was missing – Jamiec Sep 28 '16 at 11:40
  • In case of one element just use a literal string. – wOxxOm Sep 28 '16 at 11:40
0

The Split method has multiple overloads. The second example will create an array of string which will be convertet to an char[] because its only one character in the double quotes. However if you want to split by two characters, the second example won't work thus I wouldn't use it.

However, the PowerShell way to split is using -split:

$vals1 = $member -split ':'
Martin Brandl
  • 56,134
  • 13
  • 133
  • 172
  • Thanks for the answer but this wasnt about the method `Split` - that was just used as an example of where I saw this syntax used `(,"x")` – Jamiec Sep 28 '16 at 11:25