Related StackOverflow Q/A: http://stackoverflow.com/a/31888581/450913
The syntax of Test-Path
in conditional statements is unnecessarily verbose (specially in the negated case), and prone to logical errors if parenthesis are not used properly:
if (Test-Path $path) { ... }
if ($path | Test-Path) { ... }
if (-not (Test-Path $path)) { ... }
if (-not ($path | Test-Path)) { ... }
if (!(Test-Path $path)) { ... }
if (!($path | Test-Path)) { ... }
I would like to suggest the following aliases to be supported natively in PowerShell:
function not-exist { -not (Test-Path $args) }
Set-Alias !exist not-exist -Option "Constant, AllScope"
Set-Alias exist Test-Path -Option "Constant, AllScope"
With that, the conditional statements will change to:
if (exist $path) { ... }
and
if (not-exist $path) { ... }
if (!exist $path) { ... }
Much more readable and avoids logical errors that happen in statements such as: if (-not $path | Test-Path) { ... }
Another idea is to implement them natively as "-Exist" and "-NotExist" operators.
Also as suggested by Derp McDerp in UserVoice item:
An alternative way of fixing this is for powershell to alter the grammar to allow the following syntax sugar:
if !(expr) { statements* } if -not (expr) { statements* }
if !(expr) { statements* }
if -not (expr) { statements* }
I like Derp's idea at first blush. It would apply to many more cases than just Test-Path.
Combining them together, we'll have:
if -not (exist $path) { ... }
or if we get rid of the redundant dash:
if not (exist $path) { ... }
The exist
alias should work for any item, not just file paths, and never throw errors. Only return true or false.
The dash for
if -not (expr) {}
would likely remain. It's consistent with switch -regex
, etc., for example (i.e. there's already precedent for having argument-like things for statements). When implemented the same, this would automatically allow you to shorten it as long as it remains unambiguous:
if -n (expr) {}
Technically this doesn't save any keystrokes, though, but I think it stands out more than the version with !
.
As for the aliases, I don't think they are needed by default. People are free to define them if they feel Test-Path
is too complicated, but I know at least one PowerShell user who needs Test-Path
maybe once a year, and pretty much never interactively. Then there is the whole issue whether it should be exist
or exists
.
if -not (expr) { ... }
would indeed be consistent with the switch
statement grammar.
An alternative would be to introduce a negated if
statement like perl's unless
:
unless (expr) { ... } else { ... }
@omidkrad , good idea, I suggest writing this up as an RFC (https://github.com/powershell/powershell-rfc)
Congrats on PowerShell 7 release. I wanted to bump this up to be noticed. This is basically two different suggestions:
Support the "if not" syntax:
if !(expr) { statements* }
if -not (expr) { statements* }
Include the exist
alias by default:
Set-Alias exist Test-Path -Option "Constant, AllScope"
With these two we can do:
if (exist $path) { ... }
if !(exist $path) { ... }
if -not (exist $path) { ... }
Personally I don't see a ton of value in adding that as a default alias, but maybe that's just me. 馃檪
However, I do like the idea of an if !(condition)
/ if -not (condition)
syntax to simplify negated conditions. Another possible option would be a different keyword, like unless
, but I'd consider that probably a less clear alternative overall.
if -not (){}
seems preferable to me:
switch
stmts)I personally use the not-exist
alias, because it avoids the need for extra parentheses which if missed will silently cause logic bugs. (see first post 馃憜)
Yep, that's partly why we're considering ways to make them unnecessary.
There was a brief Twitter thread that has a little more discussion on the matter; myself and a couple other folks voiced support for the unless
keyword which we might want to consider a bit more here.
It is a new keyword, but IMO it's ultimately the clearest option. 馃し
While I don't see any reason both couldn't be implemented, if I had to choose one I vote for unless
mostly because you could make an alias to emulate the same behavior on 5.1 and keep your code relatively backwards compatible simply, whereas -not (expr)
won't be 5.1 compatible.
From a usability standpoint though I like -not (expr)
more, I find myself natively typing it all the time and then reminding myself I have to wrap it in parens :)
I quite like Unless it's like having while loops and do until loops; similar but convenient to have both. One would expect to be able to use else, elseUnless and elseIf with it
I would be more cautious about if not (something) {}
because the next question will be why not have if (something) and (something) {}
with the and
or or
on the outside
And it would mean IF
was the only place where the not
was "outside" without a - sign
No-one is proposing there should be
while not (something)
or Where not { something}
etc.
I would avoid changing the general language pattern of "Execute all/some/none of what's between {} based on on what's between ()" with minimal other switches (switch is IIRC special here)
ifnot
(no space) as alternative for unless would work.
Personally I don't see a lot of value for else
or any variant thereof in combination for unless
.
If you need that, it's probably more idiomatic to just use the if/elseif/else
statements as is.
unless ($condition) {
Do-Things
}
else {
Do-OtherThings
}
is the same as
if ($condition) {
Do-OtherThings
}
else {
Do-Things
}
I don't really see how adding else
/ elseUnless
or allowing them to be used in tandem with unless
is especially valuable tbh.
Personally I don't see a lot of value for
else
or any variant thereof in combination forunless
.
I don't really see how adding
else
/elseUnless
or allowing them to be used in tandem withunless
is especially valuable tbh.
(a) people will want it
(b) your examples are semantically equivalent.
However consider
If (Object is OK) {
200 lines of code
}
else {report error}
By the time someone looking at the code reads down to report error
they have forgotten what the if statement was... It's better, stylistically to write
If (Object is not OK) {report error}
else {
200 lines of code
}
It's the same reason why we have do {} while ()
or repeat
... until
loops (do something, then think about the condition for repeating it) but we don't have do {} if ()
there is nothing preventing that - but it would tax what we can hold on our mental stack for long than our 7 seconds of short term memory.
My only reservation about
Unless (Object is OK) {report error}
else {
200 lines of code
}
Is it suggests that error is usual and OK is the special case.
Most helpful comment
I like Derp's idea at first blush. It would apply to many more cases than just Test-Path.