Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it not possible to assign a string to a strongly typed boolean variable?

Tags:

powershell

Let's say I try to assign a string to a strongly typed integer variable:

[int]$bar = '1'

This works, as PowerShell is able to cast the string '1' to an integer.

Now things are different if I attempt the same with a strongly typed boolean variable:

[boolean]$foo = 'foo'
Cannot convert value "System.String" to type "System.Boolean". Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 
or 0.

I find this confusing, as PowerShell at the same time allows an explicit cast from string to boolean:

[boolean]'foo'
True

Does anyone know the reason for this seemingly inconsistent behavior?

like image 986
Manuel Batsching Avatar asked Sep 26 '22 21:09

Manuel Batsching


1 Answers

Practical advice:

In most cases I would argue the following approach, rather than typed variables: Convert your values to the target type prior to assignment, and then let the type system infer the variable type:

$foo = [bool]"foo"
$foo = "foo" -as [bool]
$foo = $true -eq "foo"

The problem at hand:

(This is not an authoritative answer, but a best-guess)

Briefly mentioned in the about_Variables help file:

TYPES OF VARIABLES

You can store any type of object in a variable, [...]

Windows PowerShell variables are "loosely typed," which means that they are not limited to a particular type of object. [...]

[... section about value-inferred types bla bla bla ...]

You can use a type attribute and cast notation to ensure that a variable can contain only objects of the specified type or objects that can be converted to that type. If you try to assign a value of another type, Windows PowerShell tries to convert the value to its type. If it cannot, the assignment statement fails.

To use cast notation, enter a type name, enclosed in brackets, before the variable name (on the left side of the assignment statement).

Although "type attribute" and the distinct constraint that this applies only during assignment is used nowhere else in the documentation, but (to me at least) indicates that this is a special case of explicit casting.


What does this imply?

When you add an explicit cast notation to the variable, during assignment, as described above, PowerShell adds an ArgumentTypeConverterAttribute to the variable, and PowerShell's type conversion magic is suddenly overridden by a type-specific Transform() method:

PS C:\> $var = 5
PS C:\> Get-Variable var |fl *


Name        : var
Description :
Value       : 5
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}



PS C:\> [int]$var = 5
PS C:\> Get-Variable var |fl *


Name        : var
Description :
Value       : 5
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {System.Management.Automation.ArgumentTypeConverterAttribute}

If we repeat this experiment with a boolean type, you can see how the ArgumentTypeConverterAttribute transform is much more restrictive than the normal conversion "magic":

PS C:\> [bool]$foo = $true
PS C:\> (Get-Variable foo).Attributes[0].Transform($ExecutionContext,"foo")
Exception calling "Transform" with "2" argument(s): "Cannot convert value "System.String" to type "System.Boolean". Boolean parameters
accept only Boolean values and numbers, such as $True, $False, 1 or 0."
At line:1 char:1
+ (Get-Variable foo).Attributes[0].Transform($ExecutionContext,"foo")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentTransformationMetadataException

Again in this type of conversion Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0., whereas powershell itself generally interprets any non-empty, non-zero or non-null value to be $true when implicitly converted to [bool].

in other words:

Cast notations are context-sensitive:

[bool]$SomeVariable = [bool]"bar"
   ^                ^   ^
   |                |   |
   |  during assignment |
This is a type attribute|
         This is a cast notation

Even though they look just the same

like image 162
Mathias R. Jessen Avatar answered Sep 30 '22 07:09

Mathias R. Jessen