1

Sometime ago I found that this construct seemed to work nicely in lieu of a native ternary conditional operator in PowerShell:

$result = if ( $myBoolExpression ) { 'a' } else { 'b' }

But I recently found that its correctness is datatype-dependent: for certain data types, it will modify the data type it returns!

If you run the following test code, you will see that it works fine for strings: $t1 is 'a' and it is, in fact, a string. And it works fine for DateTime objects ($t2). But it fails for DataTable objects ($t3 and $t4). It seems to slice off the outermost container and return the next layer, after a fashion. With $t3, the operands are empty data tables so $t3 is getting a $null. With $t4, the operands are data tables populated with datarows, but $t4 is an object array containing datarows. Both $t3 and $t4 should have been DataTables, I would have thought.

Question 1: why does this construct morph certain data types but not others?

Question 2: why is the last line in GetDataTable() required? By which, I mean, if it was instead a simple "return $dataTable" instead of "return @(,($dataTable ))" then it also returns an object array instead of a DataTable! So perhaps this is another symptom of the same issue...?

(Note that I am aware there are other ways to emulate ternary behavior--notably Ternary operator in PowerShell--but I don't like leaving unexplained issues around :-)

function DoTest {

    $t1 = if ( $true) { 'a' } else { 'b' }
    $t1.GetType().Name # prints 'String'

    $obj1 = New-Object DateTime
    $obj2 = New-Object DateTime
    $t2 = if ( $true) { $obj1 } else { $obj2 }
    $t2.GetType().Name # prints 'DateTime'

    $obj1 = New-Object Data.DataTable
    $obj2 = New-Object Data.DataTable
    $t3 = if ( $true) { $obj1 } else { $obj2 }
    $t3 -eq $null # prints $true!
    # $t3.GetType().Name

    $obj1 = GetDataTable
    "obj1 is " + $obj1.GetType().Name
    $obj2 = GetDataTable
    $t4 = if ( $true) { $obj1 } else { $obj2 } # Question 1
    $t4.GetType().Name # prints 'Object[]'
    $t4[0].GetType().Name # prints 'DataRow'
}

DoTest 

The supplement GetDataTable function is shown here. It is only used as a convenience function to create a non-empty DataTable:

function GetDataTable {
    $dataTable = New-Object Data.DataTable
    $Col = New-Object Data.DataColumn
    $Col.ColumnName = 'stuff'
    $dataTable.Columns.Add($Col )
    $row = $dataTable.NewRow()
    $row['stuff' ] = 'abc'
    $dataTable.Rows.Add($row )
    $row = $dataTable.NewRow()
    $row['stuff' ] = 'xyz'
    $dataTable.Rows.Add($row )
    return @(,($dataTable )) # Question 2-- just "return $dataTable" is insufficient
}
Community
  • 1
  • 1
Michael Sorens
  • 35,361
  • 26
  • 116
  • 172

1 Answers1

0

The unrolling of the array type is something powershell does a lot and it can really bite you at the worst of times.

I suspect the interpretation to $null is a similar part of PowerShell's Extended Type System.

It's can get convoluted at times, unfortunately.

Community
  • 1
  • 1
briantist
  • 45,546
  • 6
  • 82
  • 127