locked
Difference between declaring array with @{} and @() RRS feed

  • Question

  • I've seen countless tutorials show that arrays are declared in such a fashion: 

    $myArray = @("Hello","World")

    I know that hashtables can be created by using the brackets as follows:

    $myHashTable = @{key1 = "Helllo"; key2 = "World"}

    However, I've read that parenthesis are supposed to be used for code that is to be executed immediately whereas brackets are used for code that is not executed immediately. Therefore, why can't I declare an array using brackets?

    I've messed around with it in Powershell and changing from () to {} doesn't seem to have any effect on the functionality. 

    What's going on here? 

     
    Friday, January 18, 2019 3:15 AM

Answers

  • Because it assigns a single array element that is null.  But if you try this:

    [System.Collections.ArrayList]$arrayList = @{1,2,3}

    It won't work.

    The first creates a list of "1" with a null element.

    PS D:\scripts> [System.Collections.ArrayList]$a = [array]@{}
    PS D:\scripts> $a
    PS D:\scripts> $a.Count
    1
    PS D:\scripts> $a[0]
    PS D:\scripts>

    Because it casts the hash to an iCollection.

    This is what is happening under the covers:

    [System.Collections.ICollection]@{} # no error
    [System.Collections.ICollection]@{1,2,3}  # won't work causes error. 

    Of course we can force this by using a legal hash which will then become the first element of the list:

    PS D:\scripts> $x = [hashtable]::new()
    PS D:\scripts> $x = [hashtable]::new()
    PS D:\scripts> $x.Add('key1','value1')
    PS D:\scripts> [System.Collections.ICollection]$x
    
    Name                           Value
    ----                           -----
    key1                           value1
    
    
    PS D:\scripts> $a = [Collections.arraylist][System.Collections.ICollection]$x
    PS D:\scripts> $a
    
    Name                           Value
    ----                           -----
    key1                           value1
    
    
    PS D:\scripts> $a[0]
    
    Name                           Value
    ----                           -----
    key1                           value1
    
    
    PS D:\scripts>

    Or just do this:

    PS D:\scripts> [collections.arraylist]@{Key='hello'}
    
    Name                           Value
    ----                           -----
    Key                            hello
    
    
    PS D:\scripts> $a = [collections.arraylist]@{Key='hello'}
    PS D:\scripts> $a[0]
    
    Name                           Value
    ----                           -----
    Key                            hello
    
    
    PS D:\scripts>

    Now that is a real "cast".


    \_(ツ)_/

    Friday, January 18, 2019 5:13 AM

All replies

  • Makes no sense.

    () is used to group in an expression.  It is pretty much standard in most languages.

    In PowerShell @() is used to declare a dynamic array but that can also be done like this:

    $a = 1,2,3,4
    or
    $a = 'hello','world'

    In a declaration the array is assumed from the context. but this works the same:

    $a = @(1,2,3,4)
    or
    $a = @('hello','world')

    {} declares a script block a nd assigning I creates a variable that is a script block.

    $a = {1,2,3}
    $a

    When we enter $a at a prompt PS evaluates the script block and returns the results.  If we do this:

    $a.GetType()

    The returned type  is "ScriptBlock"

    @{} is syntax for declaring a hashtable.

    $a= @{key1 = "Helllo"; key2 = "World"}
    $a

    Typing the variable at a prompt causes the hash to be evaluated and it displays the contents as a table.

    All of this is normal but take the time to learn PowerShell and it will become clear.  Your confusion is normal for non-programmers because of the difference between syntax and execution context.  Also PowerShell has added a lot of "convenience" elements to make PS useful at a prompt.

    Also note that $() causes "subexpression evaluation and generates a result whenever it is presented to a pipeline or assigned to a variable.  It is called the "subexpression evaluator". Don't mix it up with the () which is called the "grouping operator".

    Run the following to learn more about operators in PowerShell. You will find many surprises and many useful methods.

    help operators

    Summary:

    All of these are different operator syntaxes with types.

    ()
    @()  # [array](1,2,3,4)
    $()
    {}  # [scriptblock]
    @{}  # [hashtable]


    \_(ツ)_/



    • Edited by jrv Friday, January 18, 2019 4:05 AM
    Friday, January 18, 2019 4:01 AM
  • By the way …

    You cannot declare an array like this:

    @{1,2,3}

    It will throw an exception.


    \_(ツ)_/

    Friday, January 18, 2019 4:09 AM
  • What happens if I typecast it as such: 

    [System.Collections.ArrayList]$myArray = @{}

    This doesn't throw any errors for me and it seems to work the same way as an array would. 

    Also, if I do a declaration like 

    $a = {1,2,3}

    What exactly is this? Since it's not an array, what use could it possibly serve (since I cannot access 1, 2, or 3 by themselves)? Could I use the 1, 2, and 3 from the script block as arguments in a function?

    Friday, January 18, 2019 4:29 AM
  • The second example is still a scriptblok and not an array:

    PS D:\scripts> $a = {1,2,3}
    PS D:\scripts> $a.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     ScriptBlock                              System.Object
    
    
    PS D:\scripts>

    The first one assigns a "null" hashtable to an arraylist which is still not an array.

    PS D:\scripts> [System.Collections.ArrayList]$a = @{}
    PS D:\scripts> $a.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     ArrayList                                System.Object
    
    
    PS D:\scripts> $a[0]
    PS D:\scripts> $a.Count
    0
    PS D:\scripts>

    This won't work:

    [System.Collections.ArrayList]$a = @{1,2,3}

    Try it.

    This does work:

    PS D:\scripts> [System.Collections.ArrayList]$a = @(1,2,3)
    PS D:\scripts> $a
    1
    2
    3
    PS D:\scripts>
    


    \_(ツ)_/

    Friday, January 18, 2019 4:36 AM
  • P.S. ---

    This is an assignment:

    [System.Collections.ArrayList]$a = @(1,2,3)

    This is a "cast" but not really. 

    $a = [System.Collections.ArrayList]@(1,2,3)

    The default constructor for [ArrayList] takes a an innumerable collection as an argument. An array is an enumerable collection.

    See: https://docs.microsoft.com/en-us/dotnet/api/system.collections.arraylist.-ctor?view=netframework-4.7.2#System_Collections_ArrayList__ctor_System_Collections_ICollection_


    \_(ツ)_/

    Friday, January 18, 2019 4:41 AM
  • First try to understand that PowerShell is called  a "scripting system" by its creators   It is not like a compiled language.   the following gives a bit of a view into how some of the magic is  done

    PS D:\scripts> $sb = [scriptblock]::Create('dir c:\') #'
    PS D:\scripts> $sb
    dir c:\
    PS D:\scripts> . $sb
    
    
        Directory: C:\
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----       12/26/2018   7:41 AM                AdwCleaner
    d-----       12/19/2018   1:50 PM                inetpub
    d-----       12/19/2018   8:31 PM                Intel
    d-----        9/15/2018   3:33 AM                PerfLogs
    d-r---       12/19/2018  11:29 PM                Program Files


    \_(ツ)_/


    • Edited by jrv Friday, January 18, 2019 4:46 AM
    Friday, January 18, 2019 4:46 AM
  • You are right, but when I do this it does work. Why is that?

    [System.Collections.ArrayList]$arrayList = @{}
    $arrayList.Add("hi")
    $arrayList.Add("hello")

    Friday, January 18, 2019 4:49 AM
  • Because it assigns a single array element that is null.  But if you try this:

    [System.Collections.ArrayList]$arrayList = @{1,2,3}

    It won't work.

    The first creates a list of "1" with a null element.

    PS D:\scripts> [System.Collections.ArrayList]$a = [array]@{}
    PS D:\scripts> $a
    PS D:\scripts> $a.Count
    1
    PS D:\scripts> $a[0]
    PS D:\scripts>

    Because it casts the hash to an iCollection.

    This is what is happening under the covers:

    [System.Collections.ICollection]@{} # no error
    [System.Collections.ICollection]@{1,2,3}  # won't work causes error. 

    Of course we can force this by using a legal hash which will then become the first element of the list:

    PS D:\scripts> $x = [hashtable]::new()
    PS D:\scripts> $x = [hashtable]::new()
    PS D:\scripts> $x.Add('key1','value1')
    PS D:\scripts> [System.Collections.ICollection]$x
    
    Name                           Value
    ----                           -----
    key1                           value1
    
    
    PS D:\scripts> $a = [Collections.arraylist][System.Collections.ICollection]$x
    PS D:\scripts> $a
    
    Name                           Value
    ----                           -----
    key1                           value1
    
    
    PS D:\scripts> $a[0]
    
    Name                           Value
    ----                           -----
    key1                           value1
    
    
    PS D:\scripts>

    Or just do this:

    PS D:\scripts> [collections.arraylist]@{Key='hello'}
    
    Name                           Value
    ----                           -----
    Key                            hello
    
    
    PS D:\scripts> $a = [collections.arraylist]@{Key='hello'}
    PS D:\scripts> $a[0]
    
    Name                           Value
    ----                           -----
    Key                            hello
    
    
    PS D:\scripts>

    Now that is a real "cast".


    \_(ツ)_/

    Friday, January 18, 2019 5:13 AM