When declaring a byte array, what is the difference between the following? Is there one, or are these just two different ways of going about the same thing?
Dim var1 As Byte()
Dim var2() As Byte
There's no difference.
Quotes from the spec (2003 spec, but same in the 2010 spec as can be downloaded here):
Array types are specified by adding a modifier to an existing type name.
A variable may also be declared to be of an array type by putting an array type modifier or an array initialization modifier on the variable name.
For clarity, it is not valid to have an array type modifier on both a variable name and a type name in the same declaration.
And below is the sample from the spec that shows all the options:
Module Test
Sub Main()
Dim a1() As Integer ' Declares 1-dimensional array of integers.
Dim a2(,) As Integer ' Declares 2-dimensional array of integers.
Dim a3(,,) As Integer ' Declares 3-dimensional array of integers.
Dim a4 As Integer() ' Declares 1-dimensional array of integers.
Dim a5 As Integer(,) ' Declares 2-dimensional array of integers.
Dim a6 As Integer(,,) ' Declares 3-dimensional array of integers.
' Declare 1-dimensional array of 2-dimensional arrays of integers
Dim a7()(,) As Integer
' Declare 2-dimensional array of 1-dimensional arrays of integers.
Dim a8(,)() As Integer
Dim a9() As Integer() ' Not allowed.
End Sub
End Module
And as can be seen in the comments, a1 and a4 does the same thing.
They're the same thing. You can verify by looking at the compiled code in reflector, or by writing that code in the IDE, then hovering your mouse over each.
They're reported as "var1() as byte" and "var2() as byte"
even though the first was declared with the alternate syntax.
Related
Is there any difference in the two methods of declaring an array (see below code).
In the first method, I have declared the field nos as an Array Class type. Then I use it to point towards the memory space allocated for any type of array with 5 elements. Is this understanding correct?
Can a similar understanding not be applied to the second case also? That is because numbers has bee declared as numbers(), it becomes field of array type and thus can point towards any array that is being created. If that is so then is there any difference in these two ways of declaring the arrays??
Dim nos As Array
'Console.WriteLine(nos.GetType()) '>> Error: Object not set to reference
nos = New Integer(4) {}
Console.WriteLine(nos.GetType()) ' System.Int32[]
Dim numbers = New Integer(4) {}
Dim digits() = New Integer(4) {}
Console.WriteLine(numbers.GetType()) ' System.Int32[]
Console.WriteLine(digits.GetType()) ' System.Int32[]
Dim myArray(4) As Object
Console.WriteLine(myArray.GetType()) 'System.Object[]
I have a function that returns a Dictionary with pairs key-value. Then I proceed to use on such pair to create an array: I get a value for key "DATA_ITEMS_NUMBER" to determine arrays' max length. However it results in an error...
Function getGlobalVariables()
Dim resultDict As Object
Set resultDict = CreateObject("Scripting.Dictionary")
resultDict.Add "DATA_ITEMS_NUMBER", _
ThisWorkbook.Worksheets("setup").Cells(25, 5).value
Set getGlobalVariables = resultDict
End Function
Function getBudgetItemInfos(infoType As String, year As Integer)
Dim globals As Object
Set globals = getGlobalVariables()
Dim DATA_ITEMS_NUMBER As Integer
DATA_ITEMS_NUMBER = globals("DATA_ITEMS_NUMBER")
Dim resultArray(1 To DATA_ITEMS_NUMBER) As String
...
End Function
The Dim statement isn't executable; you can't put a breakpoint on a Dim statement, it "runs" as soon as the local scope is entered, in "static context", i.e. it doesn't (and can't) know about anything that lives in "execution context", like other local variables' values.
Hence, Dim foo(1 To SomeVariable) is illegal, because SomeVariable is not a constant expression that's known at compile-time: without the execution context, SomeVariable has no value and the array can't be statically sized.
If you want a dynamically-sized array, you need to declare a dynamic array - the ReDim statement is executable:
ReDim resultArray(1 To DATA_ITEMS_NUMBER) As String
Note that a Dim resultArray() statement isn't necessary, since ReDim is going to perform the allocation anyway: you won't get a "variable not declared" compile-time error with a ReDim foo(...) without a preceding Dim foo and Option Explicit specified.
For good form your Function procedures should have an explicit return type though:
'returns a Scripting.Dictionary instance
Function getGlobalVariables() As Object
And
'returns a Variant array
Function getBudgetItemInfos(infoType As String, year As Integer) As Variant
Otherwise (especially for the Object-returning function), you're wrapping your functions' return values in a Variant, and VBA needs to work harder than it should, at the call sites.
I have a Sub with an array of strings as parameter:
Private Sub des(ByVal array() As String)
Dim i As Integer
For i = 0 To UBound(array)
array(i) = "hy"
Next
End Sub
When I call the function inside my main function, the value of str changes even if the array is passed to the function ByVal:
Dim str() As String
str = {"11111", "22222", "33333", "44444", "5555", "66666"}
des(str)
I tried making a copy of the array in the Sub, but it still changes in the main function.
Private Sub des(ByVal array() As String)
Dim i As Integer
Dim array2() As String
array2 = array
For i = 0 To UBound(array)
array(i) = "hy"
Next
End Sub
I read on a site that you cannot pass arrays ByVal. Is this true? If so, how should I proceed?
Try this:
Dim i As Integer
Dim array2() As String
array2 = array.Clone()
For i = 0 To UBound(array2)
array2(i) = "hy"
Next
The key difference is the .Clone(), that actually makes a shallow copy of array, and changing the values in array2 will no longer affect your str value in the main code.
Arrays are reference types. That means that when you pass an Array to your function, what is passed is always a reference, not a copy of the array. The Array in your function refers to the same array object as the Array in your calling code.
The same thing happens when you do the assign (it is not a copy!) in your second example: all you've done is make yet another reference to the same object. That is why Boeckm's solution works -- the Clone() call does make a new array and assign it values which are copies of the values in the original array.
In Visual Basic .NET, regarding arrays as parameters, there are two important rules you have to be aware of:
Arrays themselves can be passed as ByVal and ByRef.
Arrays' elements can always be modified from the function or subroutine.
You already know that you can modify the elements of an array inside a subprocess (subroutine or function), no matter how that array is defined as parameter inside that subprocess.
So, given these two subroutines:
Private Sub desval(ByVal array() As String)
array = {}
End Sub
Private Sub desref(ByRef array() As String)
array = {}
End Sub
And this very simple auxiliary subroutine (here I'll use the Console):
Private Sub printArr(ByVal array() As String)
For Each str In array
Console.WriteLine(str)
Next
End Sub
you can do these simple tests:
Dim arr1() as String = {"abc", "xyz", "asdf"}
Console.WriteLine("Original array:")
printArr(arr1)
Console.WriteLine()
Console.WriteLine("After desval:")
desval(arr1)
printArr(arr1)
Console.WriteLine()
Console.WriteLine("After desref:")
desref(arr1)
printArr(arr1)
I read on a site that you cannot pass arrays ByVal. Is this true?
No, that is not true.
An array in the .NET framework is a reference type. When you create an array, an object of System.Array will be created and its reference is assigned to the reference variable.
When you call a des method, the reference of the array object will be passed. In des method, ByVal parameter is a reference parameter variable of type System.Array, and it receive a copy of reference of an array object.
MSDN article - Passing Arguments by Value and by Reference (Visual Basic)
I have several named ranges inside my Excel sheet where I store data for VBA Macros between sessions. When loading I need to get that data into multiple arrays (String and Booleans).
Dim arr() As Variant
Dim rg As Range
Set rg = Sheets("Calc").Range("myRange")
arr = rg.Value2
How can I typecast arr() into a String or Boolean array for use in my macro?
If I try and use Variant arrays instead I get ByRef argument mismatch errors on function calls.
Or Is there maybe another way to get the contents of the ranges into an array of other type than Variant?
Searching did not yield a result on the latter question.
Easiest way is to declare your array as an array of Strings or Booleans, simply like this :
Dim arr() as String
Dim arr() as Boolean
It works also for functions btw.
And if you can't load the whole range because of a type mismatch, load this in an temporary Variant Array and then ReDim your String or Boolean array to match and loop on everything and use conversion functions : CBool, CStr, CInt, CDbl, ...
I have a Sub with an array of strings as parameter:
Private Sub des(ByVal array() As String)
Dim i As Integer
For i = 0 To UBound(array)
array(i) = "hy"
Next
End Sub
When I call the function inside my main function, the value of str changes even if the array is passed to the function ByVal:
Dim str() As String
str = {"11111", "22222", "33333", "44444", "5555", "66666"}
des(str)
I tried making a copy of the array in the Sub, but it still changes in the main function.
Private Sub des(ByVal array() As String)
Dim i As Integer
Dim array2() As String
array2 = array
For i = 0 To UBound(array)
array(i) = "hy"
Next
End Sub
I read on a site that you cannot pass arrays ByVal. Is this true? If so, how should I proceed?
Try this:
Dim i As Integer
Dim array2() As String
array2 = array.Clone()
For i = 0 To UBound(array2)
array2(i) = "hy"
Next
The key difference is the .Clone(), that actually makes a shallow copy of array, and changing the values in array2 will no longer affect your str value in the main code.
Arrays are reference types. That means that when you pass an Array to your function, what is passed is always a reference, not a copy of the array. The Array in your function refers to the same array object as the Array in your calling code.
The same thing happens when you do the assign (it is not a copy!) in your second example: all you've done is make yet another reference to the same object. That is why Boeckm's solution works -- the Clone() call does make a new array and assign it values which are copies of the values in the original array.
In Visual Basic .NET, regarding arrays as parameters, there are two important rules you have to be aware of:
Arrays themselves can be passed as ByVal and ByRef.
Arrays' elements can always be modified from the function or subroutine.
You already know that you can modify the elements of an array inside a subprocess (subroutine or function), no matter how that array is defined as parameter inside that subprocess.
So, given these two subroutines:
Private Sub desval(ByVal array() As String)
array = {}
End Sub
Private Sub desref(ByRef array() As String)
array = {}
End Sub
And this very simple auxiliary subroutine (here I'll use the Console):
Private Sub printArr(ByVal array() As String)
For Each str In array
Console.WriteLine(str)
Next
End Sub
you can do these simple tests:
Dim arr1() as String = {"abc", "xyz", "asdf"}
Console.WriteLine("Original array:")
printArr(arr1)
Console.WriteLine()
Console.WriteLine("After desval:")
desval(arr1)
printArr(arr1)
Console.WriteLine()
Console.WriteLine("After desref:")
desref(arr1)
printArr(arr1)
I read on a site that you cannot pass arrays ByVal. Is this true?
No, that is not true.
An array in the .NET framework is a reference type. When you create an array, an object of System.Array will be created and its reference is assigned to the reference variable.
When you call a des method, the reference of the array object will be passed. In des method, ByVal parameter is a reference parameter variable of type System.Array, and it receive a copy of reference of an array object.
MSDN article - Passing Arguments by Value and by Reference (Visual Basic)