Search
Joe Pruitt - A Software Architect's take on Network Security
You are here: DevCentral > Weblogs

posted on Monday, January 26, 2009 9:25 AM

PowerShell Welcome to this addition of the PowerShell ABC's where you'll find 26 posts detailing a component of the PowerShell scripting language, one letter at a time.  For today's letter of "W", I'll talk about PowerShell's type-promiscuous feature of numeric widening.

WideLoad PowerShell is a type-promiscuous language in that PowerShell will do it's best to try to convert whatever type of literal you are using into the type you need with as little work on your part as possible.  This means that if you want to multiple a number by a string representation of a number, it will behave as you would expect by auto-converting the string into it's numeric representation before the multiplication occurs.

When you ware working with numeric calculations, PowerShell converts everything as needed as long as there is no loss in precision.  In that case, specific guidance from the user is needed in the form of a cast or specific type conversion.

Widening

Part of this dynamic type feature, is the concept of widening.  Widening refers to the act of converting a value to a representation that can handle larger, or wider, numbers.  As an example, a [long] (64 bit) is wider than a [int] (32 bit). If the result of the operation cannot be exactly represented using the base types of the operation, then the next widest type that can hold the result will be used, within the limitations of the .NET numeric types.

This is likely best illustrated with some examples.

PS C:\> (1 + "2").GetType().FullName
System.Int32
PS C:\> (2/1).GetType().FullName
System.Int32
PS C:\> (1 + "2.0").GetType().FullName
System.Double
PS C:\> (3 / 2).GetType().FullName
System.Double

In the first two examples, type resulting types can be converted to [int]'s without loss of data, but in example 3 "2.0" would lose precision by converting to a Int32 so it is treated as a [double] and thus the resulting addition will be treated as a [double] as well.  In the last example the resulting value of "1.5" again would lose precision by being treated as an [int] so it is treated as a [double] as well.  PowerShell does not use the [single] type (single-precision floating point) unless you specifically request it.  There generally isn't a performance improvement by using a [single] over a [double] so it was decided that more precision was better.

Overflow

When you explicitly try to declare a type of a particular value and the resulting value is too wide (ie. too large) for the resulting value, a runtime error will occur.  This can be shown by trying to add a exponential number to a explicitly declared decimal.

PS C:\> 1e100 + 1d
Cannot convert value "1E+100" to type "System.Decimal". Error: "Value was either too large or too small for a Decimal."
At line:1 char:8
+ 1e100 + <<<<  1d
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : RuntimeException

In this example, the declaration to treat the right hand value as a decimal would require the left be converted to a decimal as well.  Since 1e100 is too large to be represented as a decimal, the runtime exception is raised indicating as much.

The Unexpected

When string conversions occur, you'll need to be careful that the auto-conversions happen that they are as you would expect.

PS C:\> [int]"123" -lt 123.4
True
PS C:\> [int]"123" -lt "123.4"
False
PS C:\> [double]"123" -lt "123.4"
True

The first example is pretty straightforward in that the string "123" is cast into an integer.  Since the right hand number is a decimal, the left value will get widened to a decimal and the comparison of 123.0 -lt 123.4 will occur and that will return True. 

For the second example, the left and right hand values are both strings.  The left hand value is converted to an [int] and since the right hand value is a string and does not have a numeric type, it is converted to the type of the left hand value and thus will be truncated to 123.  The resulting operation will be 123 -lt 123 will then return False.

For the last example, by forcing the type of the left hand value to a double, the resulting operation will be 123.0 -lt 123.4 which again will return True.

Debugging Type Conversions

This can be confusion but in most cases you won't have any issues.  But when type conversions are not going your way, you can use the Trace-Command Cmdlet to list out all the operations.  If you specify the TypeConversions value for the -Name parameter, you'll get a detailed step-by-step on how conversions occur.

PS D:\> Trace-Command -Name TypeConversion -pshost -Expression {[int]"123" -lt 123.4}
DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
DEBUG: TypeConversion Information: 0 : Converting "int" to "System.Type".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Conversion to System.Type
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
DEBUG: TypeConversion Information: 0 : Converting "123" to "System.Int32".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Converting to integer.
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
True
PS D:\> Trace-Command -Name TypeConversion -pshost -Expression {[int]"123" -lt "123.4"}
DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
DEBUG: TypeConversion Information: 0 : Converting "int" to "System.Type".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Conversion to System.Type
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
DEBUG: TypeConversion Information: 0 : Converting "123" to "System.Int32".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Converting to integer.
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
DEBUG: TypeConversion Information: 0 : Converting "123.4" to "System.Int32".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Converting to integer.
DEBUG: TypeConversion Information: 0 :     Exception converting to integer: "Input string was not in a correct
format.".
DEBUG: TypeConversion Information: 0 :     Converting to integer passing through double.
DEBUG: TypeConversion Information: 0 :     Numeric Conversion through Syustem.Double.
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
False
PS D:\> Trace-Command -Name TypeConversion -pshost -Expression {[double]"123" -lt "123.4"}
DEBUG: TypeConversion Information: 0 : Converting "System.Object[]" to "System.Object[]".
DEBUG: TypeConversion Information: 0 :     Result type is assignable from value to convert's type
DEBUG: TypeConversion Information: 0 : Converting "double" to "System.Type".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Conversion to System.Type
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
DEBUG: TypeConversion Information: 0 : Converting "123" to "System.Double".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Converting to double or single.
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
DEBUG: TypeConversion Information: 0 : Converting "123.4" to "System.Double".
DEBUG: TypeConversion Information: 0 :     Original type before getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Original type after getting BaseObject: "System.String".
DEBUG: TypeConversion Information: 0 :     Converting to double or single.
DEBUG: TypeConversion Information: 0 :     Cached conversion succeeded
True


Feedback

No comments posted yet.

Let Me Know What You Think


Please use the form below if you have any comments, questions, or suggestions.

Title:
 
Name:
 
Email: (so we can show your gravatar)
Website:
Comment: Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code
 
Please add 7 and 3 and type the answer here:

Blog Stats

Posts:379
Comments:1067
Stories:1
Trackbacks:301
  

Article Categories

  iRules
  

Image Galleries

  

Joe's bookshelf: read

The Lost Gate
4 of 5 stars
This one started slow but I got really got into it about 1/3 of the way through. If you are an Ender's Game fan, you'll probably like this one as well.

goodreads.com


82,243 Members in 102 Countries and Growing!

Join DevCentral Today!

About DevCentral

DevCentral has been a successful, thriving community for many years. We have always strived to bring you the best technical documentation, discussion forums, blogs, media and much more that we can.

So dive in, get familiar with DevCentral. We hope you like it, we hope it makes your job easier, and lets you get that much more power out of the community. To learn more, make sure to check out the Getting Started section. And if you have any problems, or think something could be easier to use, drop us a line to let us know.

Got It !

We've received your comment and transmitted it directly to DevCentral HQ.

Thanks for taking time to let us know what's on your mind. At DevCentral | Community Matters!

Get In Touch With Us

Have questions, suggestions or just want to get something off your chest?

Use our handy form below to Direct Connect with DevCentral Mission Control.

Send Us Feedback       or