locked
Question about -f formatting operator RRS feed

  • Question

  • Why would:

    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $H, $K[$I-1][1-1], $K[$I-1][2-1], $S

    Throw:

    Error formatting a string: Format specifier was invalid..
    At line:1 char:75
    + "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f <<<<  $H, $K[$I-1][1-1], $K[$I-1][2-1], $S
        + CategoryInfo          : InvalidOperation: (System.Object[]:Object[]) [], RuntimeException
        + FullyQualifiedErrorId : FormatError

    But:

    $H; $K[$I-1][1-1]; $K[$I-1][2-1]; $S
    31
    7
    7
    469
    $f1=31;$f2=7;$f3=7;$f4=469
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $f1,$f2,$f3,$f4
    0031 UNIT HIT ON ENTERPRISE AT SECTOR 7-7   (0469 LEFT)

    Doesn't?


    • Edited by LinhartR22 Friday, August 2, 2013 4:52 AM Clarification
    Friday, August 2, 2013 4:50 AM

Answers

  • Don't be ridiculous.  Arrays are a perfectly valid data structure, particularly for games which often have to represent a matrix of pixels, squares on a board, or whatever (which seems like what this post is about).  Also, if the problem were with array access, there would be a different exception.

    LinhartR22, your problem is that the "D" format specifier is only valid for integral types.  If the data you're passing in can't be implictly converted to something like System.Int32, you'll get that error. 

    Edit:  For reference, "integral types" means Byte, Char, Int16, Int32 and Int64, in their signed and unsigned versions. You can cast to whichever of these is most appropriate in your code before using the {D} formatting specifier.

    For example:

    # Simulating your data.  All of the data elements are stored as type Double
    
    $k = New-Object object[][](3)
    $k[1] = New-Object object[](3)
    $k[1][0] = 7.2
    $k[1][1] = 7.1
    $h = 31.0
    $s = 469.7
    
    $i = 2
    
    
    # Without casting these numbers to integers, you get an exception
    Write-Host 'Testing without [int] casts:'
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $h, $k[$i-1][1-1],$k[$i-1][2-1], $s
    Write-Host ""
    
    # Forcing casts to int makes it work.
    Write-Host 'Testing with [int] casts:'
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f [int]$h, [int]($k[$i-1][1-1]),[int]($k[$i-1][2-1]), [int]($s)
    #




    • Proposed as answer by David Wyatt Saturday, August 3, 2013 2:19 PM
    • Edited by David Wyatt Saturday, August 3, 2013 3:04 PM edit
    • Marked as answer by LinhartR22 Tuesday, August 6, 2013 5:04 AM
    Saturday, August 3, 2013 1:10 PM
  • In spite of what David is trying to sell the issue as posted is not with the formatter but with the array.  Look at the error message:

    "InvalidOperation: (System.Object[]:Object[]) [], RuntimeException"

    This is an array subscripting error.  It is likely because of using a null in subscripting. My proof was to ask to assign he values in an array first which still produced the error.

    If that were true, then you'd also see an exception in the OP's test code when he stated this:

    $H; $K[$I-1][1-1]; $K[$I-1][2-1]; $S
    31
    7
    7
    469

    But, as you can see, indexing into those arrays with the exact same code worked fine, and did not produce any exception.  However, I would be willing to bet here that if the OP ran this code:

    $H.GetType().FullName
    ($K[$I-1][1-1]).GetType().FullName
    ($K[$I-1][2-1]).GetType().FullName
    $S.GetType().FullName

    At least one of the values would come back as a non-integral type.
    • Marked as answer by LinhartR22 Tuesday, August 6, 2013 5:05 AM
    Saturday, August 3, 2013 3:02 PM

All replies

  • $H,$($K[$I-1][1-1]),$($K[$I-1][2-1]),$S

    OR

    $values=@($H,($K[$I-1][1-1]),($K[$I-1][2-1]),$S)
    '{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1} ({3:D4} LEFT)' -f $values 


    ¯\_(ツ)_/¯

    Friday, August 2, 2013 9:30 AM
  • Hey jrv. Thanks for getting back to me. I did try enclosing the two array references in parenthesis

    $H,($K[$I-1][1-1]),($K[$I-1][2-1]),$S

    thinking it would evaluate first so the format string would see the value instead of the array reference. It still threw an error.

    I'm not familiar with the $($K[$I-1][1-1]) syntax. I'm off to Google this but would you explain or point me to reference for the $(...) syntax? Thanks!

    Saturday, August 3, 2013 5:48 AM
  • I found the following reference: http://ss64.com/ps/syntax-operators.html

    I understand applying this to the following example:

    PS D:\> "The result of 2 + 3 = (2+3)"
    The result of 2 + 3 = (2+3)
    PS D:\> "The result of 2 + 3 = $(2+3)"
    The result of 2 + 3 = 5

    To evaluate the expression in a quoted string but I don't see the point of the other examples on the SS64 page. The only thing I'm coming up with is I could have used this syntax every time I ran into issues where I had to create a temporary variable because an expression was not allowed.


    • Edited by LinhartR22 Saturday, August 3, 2013 6:21 AM
    Saturday, August 3, 2013 6:08 AM
  • I tried the

    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $H, ($K[$I-1][1-1]), ($K[$I-1][2-1]), $S
    

    Syntax but it still throws the error.

    I even tried:

    $temp1 = $K[$I-1][1-1]
    $temp2 = $K[$I-1][2-1]
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $H, $temp1, $temp2, $S
    

    I'm wondering if this is a data type mismatch. I've tried casting the array references to [int] with no change. I've replaced each variable with a static value:

    -f 123, 1, 1, 123

    Which does not throw the error but any attempt to use a variable throws the error. I can't imagine it would make a difference but the statement is being executed in a Function context.

    Saturday, August 3, 2013 6:50 AM
  • Creating an array from the values threw the error too. Needing a break from this. Off to bed for now.
    Saturday, August 3, 2013 6:54 AM
  • Stop using arrays.  Yu are in an object world - use objects.

    You are insisting on try8ing to use an ancient and obsolete method and it is hiding from you the logic mistake.  The problem is not with the format method but is in your use of arrays.  You are trying to access an array with a null somewhere. 

    Always generate your final data into objects that cn be analyzed and formatted as objects using PowerShell methods.

    This is one of the hardest things to get non-programmers or non-OOP programmers to understand.  When it is finally understood then the task of designing code becomes much easier.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 9:38 AM
  • Don't be ridiculous.  Arrays are a perfectly valid data structure, particularly for games which often have to represent a matrix of pixels, squares on a board, or whatever (which seems like what this post is about).  Also, if the problem were with array access, there would be a different exception.

    LinhartR22, your problem is that the "D" format specifier is only valid for integral types.  If the data you're passing in can't be implictly converted to something like System.Int32, you'll get that error. 

    Edit:  For reference, "integral types" means Byte, Char, Int16, Int32 and Int64, in their signed and unsigned versions. You can cast to whichever of these is most appropriate in your code before using the {D} formatting specifier.

    For example:

    # Simulating your data.  All of the data elements are stored as type Double
    
    $k = New-Object object[][](3)
    $k[1] = New-Object object[](3)
    $k[1][0] = 7.2
    $k[1][1] = 7.1
    $h = 31.0
    $s = 469.7
    
    $i = 2
    
    
    # Without casting these numbers to integers, you get an exception
    Write-Host 'Testing without [int] casts:'
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $h, $k[$i-1][1-1],$k[$i-1][2-1], $s
    Write-Host ""
    
    # Forcing casts to int makes it work.
    Write-Host 'Testing with [int] casts:'
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f [int]$h, [int]($k[$i-1][1-1]),[int]($k[$i-1][2-1]), [int]($s)
    #




    • Proposed as answer by David Wyatt Saturday, August 3, 2013 2:19 PM
    • Edited by David Wyatt Saturday, August 3, 2013 3:04 PM edit
    • Marked as answer by LinhartR22 Tuesday, August 6, 2013 5:04 AM
    Saturday, August 3, 2013 1:10 PM
  • In this case the use of arrays hides the source of the problem.  It is a very weak data structure and makes it hard for the OP to see th esource of the problem.

    [object[]] or [array] is un-typed and any kind of components can sneak in.

    It is clear in the beginning that there is a mismatch.  The question is not 'what' but 'how'. There are a coupleof possible approaches to a solution:

    1.  Create objects and enforce type.
    2.  Step through with the debugger.
    3.  Put in trace statements.
    4.  Turn on tracing.

    Casting to an int will hide the error but it will also give you bad data which is not what you want. Remember that:

    [int]$null is zero.

    In spite of what David is trying to sell the issue as posted is not with the formatter but with the array.  Look at the error message:

    "InvalidOperation: (System.Object[]:Object[]) [], RuntimeException"

    This is an array subscripting error.  It is likely because of using a null in subscripting. My proof was to ask to assign he values in an array first which still produced the error.

    Arrays are useful to programmers who are well aware of the caviats of array use. For others they should be avoided so as to avoid difficult to find bugs.  Remember that in Net languages we now have 'SafeArray' which was designed to overcome some of the dangers and deficiencies in array use.

    I highly recommend avoiding designs that rely on arrays if at all possible. (simple arrays are OK as long as you understand what happens if you index outside of the array.

     


    ¯\_(ツ)_/¯

    • Proposed as answer by jrv Saturday, August 3, 2013 2:31 PM
    Saturday, August 3, 2013 2:28 PM
  • Here is a suggestion that can help avoid some array issues;

    $K=new-object int[][] 3,3
    $k[0][0]

    By explicitly creating a sized array of type you will not need to cast.  If the null shows up it is an indication that you have indexed incorrectly.  The array will also not allow assignment of bad values and it will not allow nulls even if you assign them. Assigning other type will throw an exception helping to find the cause of a problem.


    ¯\_(ツ)_/¯

    • Proposed as answer by jrv Saturday, August 3, 2013 2:42 PM
    Saturday, August 3, 2013 2:42 PM
  • That code was just a sample for me to simulate his data.  For all you know, some of his data actually needs to be stored as Float or Double.  If it needs to be displayed with the {D} formatting specifier, then it needs to be casted to an integral first.
    Saturday, August 3, 2013 2:58 PM
  • That code was just a sample for me to simulate his data.  For all you know, some of his data actually needs to be stored as Float or Double.  If it needs to be displayed with the {D} formatting specifier, then it needs to be casted to an integral first.

    The actual error message shows that that is not the problem.

    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 2:59 PM
  • In spite of what David is trying to sell the issue as posted is not with the formatter but with the array.  Look at the error message:

    "InvalidOperation: (System.Object[]:Object[]) [], RuntimeException"

    This is an array subscripting error.  It is likely because of using a null in subscripting. My proof was to ask to assign he values in an array first which still produced the error.

    If that were true, then you'd also see an exception in the OP's test code when he stated this:

    $H; $K[$I-1][1-1]; $K[$I-1][2-1]; $S
    31
    7
    7
    469

    But, as you can see, indexing into those arrays with the exact same code worked fine, and did not produce any exception.  However, I would be willing to bet here that if the OP ran this code:

    $H.GetType().FullName
    ($K[$I-1][1-1]).GetType().FullName
    ($K[$I-1][2-1]).GetType().FullName
    $S.GetType().FullName

    At least one of the values would come back as a non-integral type.
    • Marked as answer by LinhartR22 Tuesday, August 6, 2013 5:05 AM
    Saturday, August 3, 2013 3:02 PM
  • Here is the exception for a formatting error:
       + CategoryInfo          : InvalidOperation: ({0:D4} {1:D1} {2:D1} {3:D4}:String) [], RuntimeException
       + FullyQualifiedErrorId : FormatError

    The exact error has not always been specified.  It is also possible that there are both types of errors occurring.

    Avoiding use off multi-dimensional arrays can eliminate this.  Good object design eliminates much of the need to tricky code constructs which is one of the reasons for using OOP.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 3:08 PM
  • I'd love to see how you think object-oriented programming somehow makes arrays unnecessary.  You might hide the fact that a class is implemented with an underlying array from the user, or add bounds-checking code, etc (as most of the System.Collections classes do), but at the end of the day, the data is still in an array somewhere.

    Saturday, August 3, 2013 3:14 PM
  • I'd love to see how you think object-oriented programming somehow makes arrays unnecessary.  You might hide the fact that a class is implemented with an underlying array from the user, or add bounds-checking code, etc (as most of the System.Collections classes do), but at the end of the day, the data is still in an array somewhere.

    Not what I said.  Arrays are overused and incorrectly applied in many cases.  In PowerShell the generic array is not typed and has issues of addressing that lead to problems.  I recommend not using arrays in a design when an object representation with good structure and typing can be used.

    Too often Admins and techs who are trying to use PowerShell have learned a bit of basic in school.  Classic basic only has arrays to represent structures.  This tends to lead the tech to trying to represent everything as an array because this I what they were initially taught.  This just happens to be a poor way to make entry into PowerShell.

    This: $H; $K[$I-1][1-1]; $K[$I-1][2-1]; $S

    Shows one multi-dimensional array of "what?".

    $k[][]

    $I is an indexer.

    [1-1] is always zero and 2-1 is always 1.

    This leads me to believe that the OP is not a programmer and has little or no scripting experience.  It also shows the OP does not understand how an array is addressed. Where is the containment on $I?

    $H, $K[$I][0], $K[$I-1][1], $S

    This looks like an attempt to walk an array and select the nth element of two and index into each one.

    Assum an array of 'N' as

    $N=@(@(11,12),@(21,22),@(31,32))

    $N[0][0] would be 11 and $N[0][1] would be 12.

    We can index this as:

    $ix=0
    $N[$ix][0] and $N[$ix][1]

    What happens when $ix > ($N.Count - 1 )?

    If, as the OP has it, we use this:

    $N[$ix - 1][1-1] what happens on the first item.

    Testing this in the OPs scenario shows that if all array values are truly integers then there will never be an error.  If there is an error theN we are walking into un-initialized array elements.

    $K=@(@(11,12),@(21,22),@(31,32),@())
    $I=4
    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $h, $k[$i-1][1-1],$k[$i-1][2-], $s

    We can also have issues with aliasing an array to a hardware array which can have elements initialized to non values and not null.  This will also cause issues.  Casting to an int will hide all of this ugliness but it will only increase the magnitude of the problem.

    Using an array of ints is better.  Using objects is best.

    Here is another way to trap the cause of the error:

    $K=@(@(11,12),@(21,22),@(31,32),@())
    for($i=0;$i -lt 10;$i++){
         Try{
             "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f $h, $k[$i-1][1-1],$k[$i-1][2-1], $s
         }
         Catch{
             Write-Host ('ERROR: I={0} H={1} K={2} S={3}' -f $I, $h, $k, $s) -fore blue -back white
         }
    }

    This will tell you what values were seen when the error ocurred. This xan help to track down the cause of teh error wither in assumption,value or design.

     


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 4:09 PM
  • All very interesting, and even potentially good advice for programming in general.  Also, completely irrelevant to the question.

    The OP didn't give us very much code to look at, but what he did post clearly shows that all of his indeces are valid in his current array (though I agree that hard-coding "1-1" and "2-1" is weird, but still perfectly legal).  The error he received is due to trying to format a non-integral data type (probably Double) using the "{D}" specifier.

    Saturday, August 3, 2013 4:36 PM
  • All very interesting, and even potentially good advice for programming in general.  Also, completely irrelevant to the question.

    The OP didn't give us very much code to look at, but what he did post clearly shows that all of his indeces are valid in his current array (though I agree that hard-coding "1-1" and "2-1" is weird, but still perfectly legal).  The error he received is due to trying to format a non-integral data type (probably Double) using the "{D}" specifier.

    You are still skirting the real issue.  The game requires integer values.  If the array has non-integer values then something else is wrong.  Your solution gets rid of the error but does not address the real problem.

    I hope you are not programming medical devices or air plane auto-pilots.   Just eliminating an error message is not a good way to fix a program.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 4:47 PM
  • How do you know the game "requires integer values"?  The OP has made no such statement, and for all you know, one or more of these values might actually need to be represented as a Double.  Maybe the OP wants to display things as integers in the output line, or maybe he should be using a different formatting string that's appropriate for non-integral types.  Either way, you can't know that based on what little information we have so far.

    When you're programming those medical devices and auto-pilots you mentioned, maybe you shouldn't make false assumptions without getting clear requirements first.

    Saturday, August 3, 2013 5:05 PM
  • How do you know the game "requires integer values"?  The OP has made no such statement, and for all you know, one or more of these values might actually need to be represented as a Double.  Maybe the OP wants to display things as integers in the output line, or maybe he should be using a different formatting string that's appropriate for non-integral types.  Either way, you can't know that based on what little information we have so far.

    When you're programming those medical devices and auto-pilots you mentioned, maybe you shouldn't make false assumptions without getting clear requirements first.

    Star Trek uses integers. It is the coordinates of the sector where we are or where we suspect to find the bad guys.  Read the blurbs about the game.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 5:15 PM
  • For background on the BASIC version and other versions of the Star Trek game: http://en.wikipedia.org/wiki/Star_Trek_(text_game)

    The game is much easier to model with objects and has been used many times to demonstrate how objects make the designand logic of the game much easier and more reliable.

    I will  try and track down an example of a conversion.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 5:17 PM
  • Hey jrv and David. I've enjoyed reading your comments.

    Since this has grown to more than a discussion of how to use the -f operator I'm happy to explain the reasons for my approach to this project. I am in fact converting HP Basic source code written circa 1972 to PowerShell. Why? I have a nostaligic desire to play this game again.

    I often use projects like this to learn more about a particular programming language. Writing games motivates me to keep going when I would otherwise loose interest. I'm enjoying the challenge of finding ways to implement the old programming structures in a structured, object oriented programming language. I'm not sure how long my interest will last but once I've converted it in it's current form I will know all the game features and may re-write it, perhaps as a Java web app.

    I'm not sure why it was necessary for jrv to question my programming knowledge or pedigree.  Rest assured, I do have experience working with objects in modern programming languages, like Java and VB .Net. I've been programming since 1975.

    The purpose of my original post is to learn how to duplicate the PRINT USING feature in HP BASIC. The purpose of the strange indexing is that HP BASIC arrays are relative 1 instead of relative 0 as are many modern languages. Instead of adjusting all the array indexes and potentially missing something or increasing the size of the arrays to account for this I chose to just add a -1 to every array index. My goal is to make as few changes to the original code as possible. Figuring out how to implement a GOTO in the middle of a double nested FOR-NEXT loop gives one an appreciation for the "unique" programming structures used by early programmers and how confining modern, structured programming languages can be.

    Saturday, August 3, 2013 6:05 PM
  • All well and good but.

    Trying to do a linear conversion is a challenge.  It will require an intimate knowledge of how PowerShell handles primitive structures like arrays.

    The method used is OK but the array conversion to an int should not be an issue if you are sure the array is declared properly for PowerShell.

    If you intended the odd use of the array notation then I understand however it can lead you into od situations.

    As you can see by the discussions.  A linear translation will eventually devolve into a very difficult situation.

    Use the try/catch to detect where your error begins.  Once you see how the linear declaration is being handled you can design a technique to fix this.  Using David's cast may fix this as far as error go but will guarantee that you get the wrong data output.

    Good Luck.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 6:55 PM
  • Hey jrv and David. I've enjoyed reading your comments.

    Since this has grown to more than a discussion of how to use the -f operator I'm happy to explain the reasons for my approach to this project. I am in fact converting HP Basic source code written circa 1972 to PowerShell. Why? I have a nostaligic desire to play this game again.

    I often use projects like this to learn more about a particular programming language. Writing games motivates me to keep going when I would otherwise loose interest. I'm enjoying the challenge of finding ways to implement the old programming structures in a structured, object oriented programming language. I'm not sure how long my interest will last but once I've converted it in it's current form I will know all the game features and may re-write it, perhaps as a Java web app.

    I'm not sure why it was necessary for jrv to question my programming knowledge or pedigree.  Rest assured, I do have experience working with objects in modern programming languages, like Java and VB .Net. I've been programming since 1975.

    The purpose of my original post is to learn how to duplicate the PRINT USING feature in HP BASIC. The purpose of the strange indexing is that HP BASIC arrays are relative 1 instead of relative 0 as are many modern languages. Instead of adjusting all the array indexes and potentially missing something or increasing the size of the arrays to account for this I chose to just add a -1 to every array index. My goal is to make as few changes to the original code as possible. Figuring out how to implement a GOTO in the middle of a double nested FOR-NEXT loop gives one an appreciation for the "unique" programming structures used by early programmers and how confining modern, structured programming languages can be.

    If jrv was right in his assumption that the data in these arrays should be Integers, then part of his rambling is correct: it would be simpler to just declare the arrays as int[] , and PowerShell will take care of casting whatever values you assign to them to the proper type (which will then avoid little quirks like what you ran into with string formatting).  You wind up with the same numbers either way, but with less headache in your code.

    For example:

    $array1 = @(1,2,3)
    $array1[0] = (5/3)*3
    $array1[1] = 6/4
    
    [int[]] $array2 = @(1,2,3)
    $array2[0] = (5/3)*3
    $array2[1] = 6/4
    
    Write-Host "`$array1[0] ($($array1[0].GetType().FullName)): $($array1[0])"
    Write-Host "`$array1[1] ($($array1[1].GetType().FullName)): $($array1[1])"
    
    Write-Host "`$array2[0] ($($array2[0].GetType().FullName)): $($array2[0])"
    Write-Host "`$array2[1] ($($array2[1].GetType().FullName)): $($array2[1])"
    
    
    <#
    Output:
    
    $array1[0] (System.Double): 5
    $array1[1] (System.Double): 1.5
    $array2[0] (System.Int32): 5
    $array2[1] (System.Int32): 2
    #>


    Saturday, August 3, 2013 8:26 PM
  • Ass9igning the arrays as int does not find  the full problem it is only a layer protection. If you have nulls you will get zero when you may want something else.

    [int]$null is always zero.  Try it.

    [int]'123'  is 123

    [int]'123x'  will throw an exception.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 8:36 PM
  • Are you suggesting this needs to be an array of nullable integers?  What would be the point?

    Make up your mind on this, man.  You either think the data should always be stored as integers, or you don't.  If the data must be an integer, then implicitly casting things like numeric strings or doubles to [int] is a good thing.  If it throws an exception at some point, then the data validation code needs improved.

    Either way, who cares?  You always keep jumping from point to point in these discussions like you just have to find something to disagree with (even if it was one of your own previous points).

    Here is a suggestion that can help avoid some array issues;

    $K=new-object int[][] 3,3
    $k[0][0]

    By explicitly creating a sized array of type you will not need to cast.  If the null shows up it is an indication that you have indexed incorrectly.  The array will also not allow assignment of bad values and it will not allow nulls even if you assign them. Assigning other type will throw an exception helping to find the cause of a problem.


    ¯\_(ツ)_/¯

    <input id="42218238-e1d1-4780-95a1-9c2b697151b5_attachments" type="hidden" value="" />                
    7 hours 2 minutes ago

    • Edited by David Wyatt Saturday, August 3, 2013 9:50 PM edit
    Saturday, August 3, 2013 9:49 PM
  • Just because it is an int it does not mean it is a correct int.  Using an int array only fixes half of the problem and it cannot help us when an int is assigned with a null.

    PS>[int]$x = $null
    PS>$x
    0

    You cannot assign a null to an int.  You cannot assign a null to anything in PowerShell that is typed.

    [string]$null is an empty string.

    PS>[float]$null
    0

    While creating a type eliminates the errors it does not tell us when we have assigned something to the int that has no value.  This is an issue in all programming languages and systems.  Each handles I\t in its own way.  In PowerShell we need to be careful to not allow nulls into certain calculations or the result is meaningless.

    The errors received seem to indicate a bad assignment to the array somewhere earlier in the script.

    This is all I have been try8ing to get you to see from the beginning. 


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 10:25 PM
  • By the w3ay.  I am not just disagreeing. This is an issue in all programming.  How to detect when a value has not been assigned or has been assigned incorrectly.  In most languages and systems it has to be done explicitly.  In a database we can choose to set limits like 'NOT NULL' and RANGE or SET.  In PowerShell we can do it with custom objects.  It cannot be done with 'value' types like int, double, etc.


    ¯\_(ツ)_/¯

    Saturday, August 3, 2013 10:28 PM
  • I happen to know all elements of the array I'm indexing are not null:

    $K = @(
    	(0,0,0),
    	(0,0,0),
    	(0,0,0)
    )
    

    and the loop that iterates $I:

    for ($global:I = 1; $I -le 3; $global:I++) {...}

    Tuesday, August 6, 2013 4:49 AM
  • If that is the exact array then it cannot cause the error.

    I think you are missing some important pieces.  You need to inspect the values at the time of the error.  Only you can do that.


    ¯\_(ツ)_/¯

    Tuesday, August 6, 2013 5:02 AM
  • Hey David, I think you hit the nail on the head:

    [DBG]: PS D:> $H.GetType();($K[$I-1][1-1]).GetType();($K[$I-1][2-1]).GetType();$S.GetType()
    
    IsPublic IsSerial Name                                     BaseType                                                                                             
    -------- -------- ----                                     --------                                                                                             
    True     True     Double                                   System.ValueType                                                                                     
    True     True     Int32                                    System.ValueType                                                                                     
    True     True     Int32                                    System.ValueType                                                                                     
    True     True     Double                                   System.ValueType                                                                                     

    Thus:

    "{0:D4} UNIT HIT ON ENTERPRISE AT SECTOR {1:D1}-{2:D1}   ({3:D4} LEFT)" -f [int]$H, ($K[$I-1][1-1]), ($K[$I-1][2-1]), [int]$S

    Does not throw an error and displays:

    0042 UNIT HIT ON ENTERPRISE AT SECTOR 4-6   (0458 LEFT)

    YAY!

    I'm off to Google how to get leading spaces instead of leading zeroes but I think I'm back on track. Thanks!

    Tuesday, August 6, 2013 5:04 AM
  • I'm off to Google how to get leading spaces instead of leading zeroes but I think I'm back on track. Thanks!


    That's just {0,4:D} instead of {0:D4}.  If you wanted it to be right-justified (not in this case, since you said leading spaces, but for reference), it would be {0,-4:D}.
    • Proposed as answer by rlinhartpsu Tuesday, August 6, 2013 2:58 PM
    Tuesday, August 6, 2013 12:49 PM
  • Hey David, the reference I found suggested {0,4}. I tested it and it works as expected. I'm wondering if the {0,4:D} enforces a numeric type but when it comes to Powershell I've learned to not trust my assumptions. I will test this later but was wondering if you have any other insights here. Thanks for hanging in there with me and for all the professionally presented info! Am I the only one who feels the person behind the -f operator needs a swift kick in the pants? Talk about archaic, counter intuitive structures!?! ;)
    Tuesday, August 6, 2013 3:03 PM
  • Hey David, the reference I found suggested {0,4}. I tested it and it works as expected. I'm wondering if the {0,4:D} enforces a numeric type but when it comes to Powershell I've learned to not trust my assumptions. I will test this later but was wondering if you have any other insights here. Thanks for hanging in there with me and for all the professionally presented info! Am I the only one who feels the person behind the -f operator needs a swift kick in the pants? Talk about archaic, counter intuitive structures!?! ;)

    The -f operator is not an invention.  It is how formatting has been done in languages since it was introduced on Unix in the first version of the 'C' language.  It has evolved some but is a very well understood syntax for specifying the presentation of types in text. as well as a method for defining a field in text.  Most modern system use some variation of the (printf/sprintf) method.

    The following is the Net behind this.  '-f'  is just a shortcut to the Net methods: http://msdn.microsoft.com/en-us/library/system.string.format.aspx

    ([int]1000).ToString('C2')


    ¯\_(ツ)_/¯

    Tuesday, August 6, 2013 3:10 PM
  • See http://msdn.microsoft.com/en-us/library/txafckwd.aspx for more details on composite formatting in .NET (which also affects the PowerShell -f operator).  The String.Format method documentation JRV just linked is good as well (contains basically all the same information, plus a bunch more related to overloads of the function)

    Tuesday, August 6, 2013 3:16 PM
  • If you need a more linear explanation then start here: http://blogs.technet.com/b/heyscriptingguy/archive/2013/03/11/understanding-powershell-and-basic-string-formatting.aspx

    Also search for 'PowerShell string formatter' as there are hundreds of articles on how to use this.

    The PowerShell string formatter operator (-f) have been around for nearly a decade now.  The Net format classes have been around for almost two decades if we include pre-beta.

    Here is an article tracing the string formatter back to 1966: http://en.wikipedia.org/wiki/Printf_format_string

    2013-1966 = 47 years which is probably longer than you have been alive or. at least longer than you have been out of short pants.


    ¯\_(ツ)_/¯

    Tuesday, August 6, 2013 3:45 PM
  • Hey David, the reference I found suggested {0,4}. I tested it and it works as expected. I'm wondering if the {0,4:D} enforces a numeric type but when it comes to Powershell I've learned to not trust my assumptions.

    Sorry, I missed this question when I read your response the first time.

    Yes, the D specifier requires an integral, numeric type.  In this specific case (where you're passing in some Int32 and some Double values, but the Doubles happen to contain whole numbers anyway), {0,4} is sufficient, and doesn't require the cast to [int].

    {0,4} is the same as {0,4:G}, by the way.  See http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#GFormatString for details of how the G format specifier behaves on numeric types.

    Tuesday, August 6, 2013 4:08 PM
  • Just barely out of short pants and only a few years away from my first Radio Shack PBox Kits (http://my.core.com/~sparktron/pbox.html). The lie detector was my favorite. It didn't work that well but my subjects didn't know that. ::evil grin::
    Tuesday, August 6, 2013 4:34 PM
  • Just barely out of short pants and only a few years away from my first Radio Shack PBox Kits (http://my.core.com/~sparktron/pbox.html). The lie detector was my favorite. It didn't work that well but my subjects didn't know that. ::evil grin::

    But you didn't have the opportunity to shop in the very fist Radio Shack.  How about a Radio Shack in the Dominican Republic in 1983 to purchase transistors to fix an HP high speed page printer?

    I bought the antenna for my first crystal radio from Radio Shack.

    I pre-date 'p-box' and had to cobble together all of my own kits from the parts box.  Canal Street was a good spot to search for parts.  It took less than one year to go from crystal to a regen set.


    ¯\_(ツ)_/¯

    Tuesday, August 6, 2013 4:50 PM
  • The antenna for my first crystal radio was a hand wrapped Quaker Oats container (the round one made from paper/cardstock). Being able to hear radio broadcasts without the need for any batteries or external power amazed me!
    Tuesday, August 6, 2013 5:02 PM
  • The antenna for my first crystal radio was a hand wrapped Quaker Oats container (the round one made from paper/cardstock). Being able to hear radio broadcasts without the need for any batteries or external power amazed me!

    Not the antenna - that was the tuning coil where we ran a slider along to change the effective 'Q' of the antenna circuit.  It was a primitive tuner.  I added a air cap to further refine the tuning.  Connected it to a long wire in the attic that my Grandfather had strung in the 1930's.

    ¯\_(ツ)_/¯

    Tuesday, August 6, 2013 5:07 PM