GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Fix array expression to not return null or throw error by daxian-dbw · Pull Request #4296 · PowerShell/PowerShell Conversation
|
| It "@([object[]](1,2,3)) should return a 3-element array of object[]" { | ||
| $result = @([object[]](1,2,3)) | ||
| $result.GetType().FullName | Should Be "System.Object[]" | ||
| $result.Length | Should Be 3 |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I believe we should check $result.Length before $result.GetType() in all test here. This is not important in these tests, but it is a bad pattern for other tests in which the $result are calculated. (I mean that somebody can copy-paste the bad pattern).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by the $result are calculated? Can you please elaborate a bit and give an example?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
From Get-Content.Tests.ps1:
It "should Get-Content with a variety of -Tail and -ReadCount values" {#[DRT] set-content -path $testPath "Hello,World","Hello2,World2","Hello3,World3","Hello4,World4" $result=get-content -path $testPath -readcount:-1 -tail 5 $result.Length | Should Be 4
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Can we use Should BeOfType?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
To use Should BeOfType I need to wrap $result in a new array because it will be unraveled otherwise. I feel it's clearer to just use GetType().FullName in this case.
As for the bad pattern, I'm still confused. Why do you think putting $result.Length | Should Be 3 after the type check would be a bad pattern? More technically speaking, the length check should happen after we know $result is an array, otherwise we might (actually impossible) end up checking the Length property of some random type :)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
function foo {$null} $res = foo $res.GetType() You cannot call a method on a null-valued expression. At line:1 char:1 + $res.GetType() + ~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see your point. A Should Not BeNullOrEmpty check should be done in that case.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| } | ||
|
|
||
| It "@([int[]](1,2,3)) should return a 3-element array of object[]" { | ||
| $result = @([int[]](1,2,3)) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Should we test complex types? PSCustomObject?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
For any array type other than [object[]], it will fall in the code path of PSToObjectArrayBinder. I just use [int[]] as a simple validation.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I mean member types.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Oh, the member type doesn't matter for the scenario of this fix. It's OK as long as the conversion works.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Should we add tests for |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| values = values ?? CaptureAstResults(subExpr, CaptureAstContext.Enumerable); | ||
|
|
||
| if (values.Type.IsArray) | ||
| if (values.Type == typeof(object[]) || values.Type == typeof(List<object>)) |
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
The goal of the optimization was to cover @(1,2) - so maybe the original test was too general. This fix ends up adding unnecessary overhead to the optimization by cloning and adding an if test.
I think a better fix is to just constrain the optimization more - basically if (subExpr is ArrayLiteralAst).
I don't recall why I added the List<object> case.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
The clone was added to address a comment raised by PetSerAl about $a = 1,2,3; @([object[]]$a) doesn't return a new array. But if we only consider if (pureExpr is ArrayLiteralAst) then the clone and the null check are both not necessary anymore.
The List<object> case seems like an optimization for CaptureAstResults, because a List<object> instance will be created to hold the objects written to pipe in CaptureAstResults.
Are you suggesting to not cover the cases of values.Type == typeof(object[]) and values.Type == typeof(List<object>) here?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Replace the cases of values.Type.IsArray and values.Type == typeof(List<object>) with if (pureExprAst is ArrayLiteralAst). So the former cases will be handled by the dynamic site.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I think the change is fine.
I should add that the intent of @() is not to create a new array, but to ensure the result is an array, and not necessarily an object[].
In other words, I think we could be open to changing what the language specification says to allow for better performance.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
The last commit removed the |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
This change fixes 3 issues: - According to [PowerShell Language Specification Version 3.0](https://www.microsoft.com/en-us/download/details.aspx?id=36389), as quoted: "_The result is the (possibly empty) unconstrained 1-dimensional array_", `@(...)` should only return `object[]` array. - `@([object[]]$null).GetType()` fails with error `"You cannot call a method on a null-valued expression."` - `@([System.Collections.Generic.List[object]]$null)` fails with error `"Object reference not set to an instance of an object."`
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.