This may sound trivial, but what is the difference between
Dim v As String()
and
Dim v() As String
in VB.NET?
No difference. From the VB.NET Language Specification on Arrays:
Array types are specified by adding a modifier to an existing type name. The modifier consists of a left parenthesis, a set of zero or more commas, and a right parenthesis.
...
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. In that case, the array element type is the type given in the declaration, and the array dimensions are determined by the variable name modifier. 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.
Originally, in Basic, you had to define arrays, but not variables. And the types of variables were defined by a suffix character: A$ was a string, while A% was an integer and A# was double precision. (and all three were distinct and could be used at the same time) (For single-precision, you could use A!, but that was the default if you just used A)
Eventually, programmers came to realize that those were incredibly bad design choices.
To rectify this, Microsoft added "Option Explicit" which required you to predefine every variable. To lessen the effect on the language, they hijack the "DIM" command, which was used to define arrays, to define scalar variables as well.
So originally:
DIM A(50) ' define 51-element single-precision array
Then
DIM A(50) ' define 51-element single-precision array
DIM A$ ' define a string
Then to get rid of the suffixes, they added the "As {type} syntax"
DIM A(50) ' define 51-element single-precision array
DIM B as String
DIM C(50) as String ' define 51-element string array.
Then they made array size variable.
DIM A() ' define single-precision array
DIM B as String
DIM C() as String ' define string array.
This left a conflict in definition style, so they allowed both:
DIM A() ' define single-precision array
DIM B as String
DIM C() as String ' define string array.
DIM D as String() ' define string array.
There is no difference.
Both Dim v As String() and Dim v() As String will create a string array
Traditionally, in Basic, you would put the parenthesis after the variable name. In VB.Net it is allowed to put them after the type instead if you wish. The result is the same so there is no difference using either syntax. The reason for this addition though is because how you can constuct an array. Consider the following code:
Public Sub MethodThatExpectsAnArray(ByVal arr() As String)
'...
End Sub
Public Sub Main()
Me.MethodThatExpectsAnArray(New String() {"Hello", "World"})
End Sub
In the call I construct the array "on the fly" without any assignment except directly to the method argument. Since there are no variable here I must set the paranthesis after the type. To allow this syntax Microsoft had the choice to either change how you traditionally declare arrays in Basic or allow for both syntaxes. They of course opted for the latter.
There is no difference.
It's mostly semantics. The first reads as create variable "v" of type string array and the 2nd reads as create array "v" of type string. Either way the result is the same array of strings.
There is no difference in the meaning of the two.
If you like to declare several variables in one dim statement, the second form provides more flexibility:
dim v(),v2 as string allows you to declare array types and non array types in the same statement.
Related
Why do I get a Type Mismatch error on the last line?
Dim LineArray()
Dim Line
Dim FilePath as String
FilePath = "X:\Path\To\File.txt"
Open FilePath For Input As #1
Line Input #1, Line
Close #1
LineArray = Split(Line, vbTab)
LineArray is a Variant/Variant()
Line is a Variant/String
If I Dim them both as Variants I still get the error
As written in the comments: Split returns an array of Strings.
So the correct syntax is
Dim LineArray() As String
LineArray = Split(Line, vbTab)
The VBA compiler knows that LineArray will be an array of Strings. However, as it is declared as dynamic array, it is not an array before you assign members to it. Usually, this is done using the ReDim-statement that reserves the necessary space for a certain number of variables of a specific type. When using the split-function, this ReDim (or something similar) is done inside the function.
Now Variant is a very special data type - it can hold any type of data. This can be an Integer, a String, a Date, an Object (reference), an Error, or the value Empty (which means nothing is assigned yet). And, it can even be an array of any datatype. You can get the information about what data it contains using the function VarType().
What you can`t do is assign the result to an static array:
Dim LineArray(0 to 3) As String
LineArray = Split(Line, vbTab)
This will throw a compile error: Can't assign to array. The variable is not only defined, the memory is already reserved (in this case 4 Strings).
What you also can't do is to assign the result to an array of Variant. Why? Because the Split creates an Array of Strings. Now if you would assign this to an array of Variant, it would be possible to assign, let's say, a Double to the first element. However, the memory was reserved by Split to hold an String, so horrible things would happen to the memory.
Dim LineArray(0) As Variant
LineArray = Split(Line, vbTab)
LineArray(0) = 3.1415926 ' Ouch!
What would be needed is an instance that
Reserve memory for n Variant variables and assign it to LineArray (n = number of strings returns by Split)
Loop over all elements of the string array and assign the strings one by one to the variant array.
Now while this is possible, no instance will do this for you. The Split-function creates and returns the String array. The assignment operator ("=") is capable to assign any value to a Variant, but is not capable to reserve an array and copy elements one by one.
i have a User defined type in VBA (Excel) and want to have a fixed memory layout for the members so that I can use pointers in a later step for accessing those members.
The user defined type is looking like the code provided and I need to pass on the adresses of the members to a different programm.
I expected VBA to structere the members in the order that they are initialized but somehow it doesn't.
If you have any idea on how to solve that problem I would be really grateful!
Best Regards,
Lars
Public Type ExampleSet
Example_P_Anteil As Single
Example_I_Anteil As Single
Example_D_Anteil As Single
Example_v0 As Double
Example_Gang0 As Integer
Example_Beschleunigung As Double
Example_Startzeit As Double
Example_int1 As Integer
Example_int2 As Integer
Example_int3 As Integer
End Type
I challenge your conclusions.
Public Type TestUDT
SomeInteger As Integer ' Int16 (I2) at offset 0, padded with 2 bytes
SomeLong As Long ' Int32 (I4) at offset 4, no padding
AnotherLong As Long ' Int32 (I4) at offset 8, no padding
End Type
Public Sub test()
Dim udt As TestUDT
Debug.Print VarPtr(udt) 'expected: X
Debug.Print VarPtr(udt.SomeInteger) 'expected: X+0
Debug.Print VarPtr(udt.SomeLong) 'expected: X+4
Debug.Print VarPtr(udt.AnotherLong) 'expected: X+8
End Sub
Output is as expected:
723094616
723094616
723094620
723094624
User-Defined Types (UDT) are defined in the language specifications as:
A linear concatenation of the aggregated data values possibly with implementation defined padding between data values.
The padding might be what's throwing you off, but a UDT is still a linear concatenation of its members.
Use the LenB function to determine the length of a member (or of the UDT as a whole):
Dim foo As ExampleSet
Debug.Print VarPtr(foo), LenB(foo)
If the UDT contains strings, define them as fixed-length if the offsets of the members that follow it need to be fixed:
Public Type TestUDT
SomeString As String * 10
'...
End Type
That said, good luck accessing these pointers out of process.
I am using windows 7, Excel 2010, VBA. I am getting an error
"ByRef Argument Type Mismatch". I am assuming it is a problem with my variable type. I found lots of questions like mine but I can't find anything that has helped me figure out my problem.
Variable Declarations
'Force explicit variable declaration
Option Explicit
Private dptData(8) As String
Private TSdata(8) As String
Private fiscalYear(8) As String
Calling Function
parseUserData fiscalYear, dptData, TSdata
Called function Prototype
Function parseUserData(fiscalYear As String, dptDataAs String, TSdata As String)
You're passing an array to a String. Change the function's signature to accept a Variant instead.
Public Function parseUserData(fiscalYear As Variant, dptDataAs Variant, TSdata As Variant)
Debug.Assert IsArray(fiscalYear) And IsArray(dptDataAs) And IsArray(TSdata)
A String parameter can only ever accept a String argument1. Variant on the other hand, can accept anything - including an array - but then you'll want to Assert that you're dealing with an array, so that you halt execution (and prevent a bug) if that's not the case.
Why use a Variant over a typed array?
Using a typed array would work, but a typed array can't be coerced from a Variant parameter - which means this:
Public Sub DoSomething(ByRef args() As String)
...can't be invoked with this otherwise perfectly valid array of strings:
DoSomething Array("string1", "string2", "string3") ' can't pass a variant array!
Changing the signature to DoSomething(ByRef args As Variant) makes it work. All you need to do is to use a meaningful, descriptive, pluralized name to your variant array parameters, so that when IntelliSense is shown when you invoke that procedure, the name tells you everything you need to know.
But... 'Variant' is evil!
No different than many other languages, type safety in VBA is essentially smokes and mirrors. Variant is a very powerful tool and does have its uses - avoid it when you can doesn't mean unlearn its existence. Using it to pass array references around between procedures doesn't hurt the code's readability, maintainability, or stability. Variant enables duck typing and late-binding, and is a legitimate COM type.
It's a hammer. Just make sure not everything becomes a nail, and you'll do great.
1VBA will implicitly convert other value types to a String, but an array can't be coerced into a string, implicitly or explicitly.
It seems you wanted a string array after all but it may be worth mentioning that you can declare a fixed width string var.
Dim dptData As String * 8
dptData = "abc"
Debug.Print Len(dptData) & "|" & dptData & "|"
'result from Immediate window
'8|abc |
dptData = "abcdefghijk"
Debug.Print Len(dptData) & "|" & dptData & "|"
'result from Immediate window
'8|abcdefgh|
I wondering how I can use a variable to call another variable. For example Apple1, Apple2, Apple3, Apple4, Apple5, Apple6 and AppleNum.
Let us say AppleNum is 4. How can I use AppleNum to call for the code to use Apple4?
Also, What if Apple1, Apple2...ect are objects?
My first thought on how to solve this was by using some sort of Array?
Note: Using Select Case here will work but doesn't simply the code I have and would require each case to be written out individually (a lot of work)
Just out of interest, ts there a way to define AppleNum number of variables in the code?
If you can help, Thanks!
It is possible to have an array of variable size in VBA, using the following (for example):
Dim myArray() as Double
Dim AppleNum as Integer, arraySize as Integer
AppleNum = 4
arraySize = 6
ReDim myArray(1 to arraySize)
this would create an array myArray, and change its size to be 6 elements long (with index starting at 1). You can declare the entire array in one statement (without redimensioning) with
myArray = Array(Apple1, Apple2, Apple3, Apple4, Apple5, Apple6)
Assuming that Apple1 etc. have been previously declared.
If you declare myArray as Variant rather than Integer (or don't give a type - defaults to Variant) then your array can contain anything you want.
You can also use
ReDim Preserve myArray(1 to arraySize * 2)
if at a later point you want the array to be twice as large, but you don't want to lose the first six elements you had assigned.
I hope these things will get you moving with your problem.
I have a piece of Excel-VBA code of which the following behavior escapes my understanding
option explicit
....
private sub XYZ()
dim s as string
dim ser as series
dim diagram as chart
...
s = function_returning_string(....)
' Following line throws runtime exception 13
set ser = diagram.seriesCollection.item(s)
....
end sub
If I try to get a named item in the seriesCollection of the chart object as outlined above, it throws (the german) errors laufzeitfehler '13' typen unverträglich which would be Run-time error 13: Type mismatch in english.
Changing the offending line to
set ser = diagram.seriesCollection.item(CStr(s))
makes to error go away.
I have no idea why that is. CStr() is supposed to convert something (here: s) into a string, but s is already a string.
CStr converts the type of a variable into a String data type.
If you have a function s = function_returning_string(....) where s is already typed a string, doing for example this:
dim s as string
dim sString as string
sString = cstr(s)
would be meaningless.
In other cases, this may be useful.
Sometimes people use it for example to convert a string to a date, using cDate.
Or to take string, cut off some parts and use cDbl or cInt to convert towards a Double or Integer datatype.
Check your function "function_returning_string" if it is defined as :
Public Function function_returning_string() as string
In this case, the seriesCollection only allows String typed variables to be added in the collection.