Using array constants in excel vba function - vba

I have a function in VBA of the type
Function MyFunc(Indx As Integer, k As Long, Rho As Range, A As Range) As Variant
....
End Function
which is called as a user-defined function from within the Excel worksheet. When called with the last two arguments being a range
Result = MyFunc(1,98,A1:A2, B1:B2))
it works fine. However, when I try to directly use an array constant instead of a range
Result = MyFunc(1,98,{10,11}, {20,30})
it returns a #VALUE error.
I thought I could fix it by redefining the last two arguments as arrays of type double, but this didn't work either
Function MyFunc(Indx As Integer, k As Long, Rho() As Double, A() As Double) As Variant
....
End Function
Does someone have a suggestion for a flexible solution, which would permit either calling method: by range, as well as by an array constant?

You could declare your two parameters as Variant types, then in your function check what has been passed to them using the TypeName(varname) function.

Maybe you could convert your array in a range object while calling the function.
Result = MyFunc(1,98,Range(10,11), Range(20,30))

Related

Excel vba: constant expression required in for cycle

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.

Typecasting Variant Array into String or Boolean Array

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, ...

Passing variants/arrays as arguments for a function

Example code;
Sub functiontester()
Dim testdata As Variant
Dim answer As Long
Dim result1 As Long
testdata = Sheets("worksheet1").Range("E1:E2").Value
result1 = testfunction(testdata)
result2 = testfunction2(testdata(2, 1))
End Sub
Function testfunction(stuff As Variant) As Long
testfunction = stuff(2, 1)
End Function
Function testfunction2(num As Long) As Long
testfunction2 = num
End Function
So from my days in python I'd expect result1 & result2 to both run fine, however this is not the case in VBA and if you try to run this you get
"compile error: Byref argument type mismatch" from result2; which I assume has something to do with limits of calculating values inside arguments of functions
So my question is: is there an easy way to make result2 work so that the variant reference just resolves to the specified element?
testdata(2, 1) likely will be of type Double, not Long.
You can use
CLng(testdata(2, 1))
to cast it to a Long.
So:
result2 = testfunction2(CLng(testdata(2, 1)))
should be fine
"compile error: Byref argument type mismatch" Actually refers to the fact it won't implicitly convert the datatype for you, because ByRef arguments (the default) are expected to be writeable. If converted arguments are written to , it gets lost when you return from the function/subroutine because the converted values are only temporary, they're not in any variable outside of the called function.
You can get around this complaint by making the receiving parameter ByValwhich means that it shouldn't be writable anyway:
Function testfunction2(ByVal num As Long) As Long

VBA Excel: How to pass one parameter of different types to a function (or cast Int/String to Range)?

I'm writing some VBA functions in Excel that compute word values and cross sums of the input.
I'm passing the input as Public Function cross_sum(myRange As Range) As Integer to them so that they take cell references as input, e.g. =cross_sum(A1). Works fine.
However when I try to chain two functions like =cross_sum(word_value(A1)) I run into th VALUE error because word_value() returns an Integer value and not the Range cross_sum() is set to expect. However I did not find a way to cast an Integer (or String) into a Range.
As Excel's built-in functions support chaining as well as Range input I wonder how.
Unfortunately this is my first VBA project so I wonder if and how to cast or what type to choose to get this working both ways.
Any pointers appreciated!
TIA,
JBQ
You can pass Variant to a function and the function can determine the type of input:
Public Function Inputs(v As Variant) As String
If TypeName(v) = "Range" Then
MsgBox "you gave me a range"
Else
MsgBox "you gave me a string"
End If
Inputs = "done"
End Function
Sub MAIN()
Dim st As String
Dim rng As Range
st = "A1"
Set rng = Range(st)
x = Inputs(st)
x = Inputs(rng)
End Sub
Without your code, it is hard to know what you could change. That being said...
There is not a way to convert an integer to a range. You would have to create a function to do so if that is what you desired.
You could create a converter function, maybe titled IntegerToRange, that takes an integer and after some logic (maybe 1 = "A1", 2 = "A2" or something), will return a range. Your cell formula would then be =cross_sum(IntegerToRange(word_value(A1))
Alternatively, you could modify your word_value function to return a range instead of an integer. Your cell formula would then be =cross_sum(word_value(A1).

Converting a Variant (Integer) parameter to Variant (Long)

I have a Variant parameter passed to a function, and this parameter is essentially an Integer:
Function Foo(vNum As Variant) As Long
vNum = 50000
When I call this function using:
Dim A As Integer
A = 2000
Foo(A)
I get an Overflow error (6).
This seems to have something to do with vNum being 'classed' as an integer variant when I pass a number smaller than 32767 (the upper limit of integers), which then causes overflow when attempting to assign a number larger than 32767.
My question is, how do I cast or convert this 'Integer' Variant into one that will accept Longs?
I tried casting: vNum = CLng(50000) and vNum = CVar(50000),
and using dummy variables:
Function Foo(vNum As Variant) As Long
Dim vTest As Variant
vTest = 50000
vNum = vTest
All of these still generated an Overflow error (6).
Would appreciate any help thanks!
I think you should just define your function like this:
Function Foo(ByVal vNum As Variant) As Long
If you don't specify ByVal, your parameter is passed ByRef, and any operation you make to the parameter is made on the "original" variable, hence an integer.
If you just set vNum as a Long you dont get that problem.
Then it can contain a number to 2,147,483,648
Function Foo(vNum As Long) As Long
'do stuff
End Function