VB.NET := Operator - vb.net

What does the following mean?
Class.Function(variable := 1 + 1)
What is this operator called, and what does it do?

It is used to assign optional variables, without assigning the previous ones.
sub test(optional a as string = "", optional b as string = "")
msgbox(a & b)
end sub
you can now do
test(b:= "blaat")
'in stead of
test("", "blaat")

It assigns the optional parameter "variable" the value 2.

VB.NET supports this syntax for named (optional) parameters in method calls. This particular syntax informs Class.Function that its parameter variable is to be set to 2 (1 + 1).

Related

Why does my function assume a missing argument is there?

I have a function which updates a form, "LoadingInterface". The function looks like this:
Private Sub updateLoadingBar(Optional tekst As String, Optional barOnePerc As Long, Optional barTwoPerc As Long)
If Not IsMissing(tekst) Then
LoadingInterface.Label1.Caption = tekst
End If
If Not IsMissing(barOnePerc) Then
LoadingInterface.Bar.Width = barOnePerc * 1.68
LoadingInterface.prosent.Caption = barOnePerc & "%"
LoadingInterface.prosent.Left = barOnePerc * 1.68 / 2 - 6
End If
If Not IsMissing(barTwoPerc) Then
LoadingInterface.SubBar.Width = barTwoPerc * 1.68
End If
LoadingInterface.Repaint
End Sub
I then call the function like this, expecting it to only update the textfield, since the other two arguments are missing.
Call updateLoadingBar(tekst:="Test")
This works fine for updating Label1, but unfortunately the other two values are updated too - it seems that not including any values in the function-call makes VBA assume the two variables values are 0. What's more, it appears that the IsMissing function does not detect that the two values are missing when the function is called, which is the bigger problem. Stepping through the code using F8 confirms that all the if-statements are indeed entered.
Is there any way to make the code skip the two lowermost if-statements in my function, if no values are provided for the parameters barOnePerc and barTwoPerc?
IsMissing only works if the argument is declared as a Variant.
I don't think you can validly distinguish between 0 and no passed parameter for the Long. In that case you would need to declare as Variant in the signature. You can later cast if required.
I guess you could put a default (unlikely number) and test for that. Note: I wouldn't advise this. This just screams "Bug".
IsMissing:
IsMissing returns a Boolean value indicating whether an optional Variant argument has been passed to a procedure.
Syntax: IsMissing(argname)
The required argname argument contains the name of an optional Variant
procedure argument.
Remarks: Use the IsMissing function to detect
whether or not optional Variant arguments have been provided in
calling a procedure. IsMissing returns True if no value has been
passed for the specified argument; otherwise, it returns False.
Both methods:
Option Explicit
Public Sub Test()
RetVal
RetVal2
End Sub
Public Function RetVal(Optional ByVal num As Long = 1000000) As Long
If num = 1000000 Then
MsgBox "No value passed"
RetVal = num
Else
MsgBox "Value passed " & num
RetVal = num
End If
End Function
Public Function RetVal2(Optional ByVal num As Variant) As Long
If IsMissing(num) Then
MsgBox "No value passed"
Else
MsgBox "Value passed " & num
RetVal2 = CLng(num)
End If
End Function

VBA Call method with optional parameters

I just figured out that setting optional parameters requires "Call" infront of the method.
Public Sub Test()
Call abc("aaa")
Call abc("aaa", 2)
abc("aaa") ' is fine
abc("aaa", 2) ' is a syntax error
End Sub
Function abc(a As String, Optional iCol As Long = 3)
MsgBox (iCol)
End Function
Can you add a "why does this make sense?" to my new information?
Greetings,
Peter
Edit: PS the function abc for no other use than to simplify the question.
Documentation
Call is an optional keyword, but the one caveat is that if you use it you must include the parentheses around the arguments, but if you omit it you must not include the parentheses.
Quote from MSDN:
You are not required to use the Call keyword when calling a procedure.
However, if you use the Call keyword to call a procedure that requires arguments, argumentlist must be enclosed in parentheses. If you omit the Call keyword, you also must omit the parentheses around argumentlist. If you use either Call syntax to call any intrinsic or user-defined function, the function's return value is discarded.
To pass a whole array to a procedure, use the array name followed by empty parentheses.
Link: https://msdn.microsoft.com/en-us/library/office/gg251710.aspx
In Practice
This means that the following syntaxes are allowed:
Call abc("aaa")
Call abc("aaa", 2)
abc "aaa", 2
abc("aaa") ' <- Parantheses here do not create an argument list
abc(((("aaa")))) ' <- Parantheses here do not create an argument list
The following syntaxes are not allowed:
Call abc "aaa", 2
abc("aaa", 2) ' <- Parantheses here create an argument list
Function Return Values
This doesn't take effect when using a function to get a return value, for example if you were to do the following you need parentheses:
Function abc(a As String, Optional iCol As Long = 3)
abc = iCol
End Function
'## IMMEDIATE WINDOW ##
?abc("aaa", 2) 'this works
?abc "aaa, 2 'this will not work
?Call abc "aaa", 2 'this will not work
?Call abc("aaa", 2) 'this will not work
If you are using Call on a Function then consider changing it to a Sub instead, functions are meant to return a value as in the cases above.
Something like this would work:
Option Explicit
Public Sub Test()
Dim strText As String
strText = "E"
Call Abc(strText, 3)
Call Abc(strText, 2)
Abc (strText)
' Abc (strtext,5)
Abc strText, 2
Abc strText
End Sub
Public Sub Abc(strText As String, Optional iCol As Long = 5)
Debug.Print iCol
End Sub
Absolutely no idea why the commented code does not work...
Call is an optional keyword, as already described in detailed in the answer above.
for your second option
abc("aaa", 2) ' is a syntax error
Just use:
abc "aaa", 2
Note: there is little use to have a Function if you don't return anything, you could have a regular Sub instead.
to have a Function that return a String for instance (just something made-up quick):
Function abc(a As String, Optional iCol As Long = 3) As String
abc = a & CStr(iCol)
End Function
and then call it:
Public Sub Test()
d = abc("aaa", 2)
MsgBox d
End Sub

Excel VBA: Failed to pass a string array to a Function

VBA Beginner here.
I am trying to pass an array of strings from a subroutine to a function which will then modify each string in the array. However I get the "Type:array or user-defined type expected" error message.
I have tried redefining different data types for the array so it is aligned with the data type entered in the function but to no avail.
Hope you can help! THank you so much!
Below is the dummy code:
Sub text()
Dim haha() As Variant
haha = Array("Tom", "Mary", "Adam")
testing (haha())
MsgBox Join(haha, " ")
End Sub
Function testing(ByRef check() As String) As String()
Dim track As Long
For track = LBound(check) To UBound(check)
check(track) = check(track) & " OMG"
Next
End Function
In orignial code, a string is not the same variant (I believe they both would need to be variant? someone can verify), you dont need the brackets after testing, only need brackets if you are setting to another value e.g.
haha2 = testing(haha())
Below code should be ok
Sub text()
Dim haha()
haha = Array("Tom", "Mary", "Adam")
testing haha()
MsgBox Join(haha, " ")
End Sub
Function testing(ByRef check()) As String
Dim track As Long
For track = LBound(check) To UBound(check)
check(track) = check(track) & " OMG"
Next
End Function
You have a few errors in your code:
There are two ways of invoking methods:
1) with Call keyword - in this case you must give all the parameters in brackets:
Call testing(haha)
2) without Call keyword - in this case you just give your parameters after the name of function:
testing haha
In your code you combined both of them and this is syntax error.
If you pass an array as a parameter to function you don't need to put brackets like that: testing (haha()).
The proper syntax is:
testing(haha)
Function testing requires as a parameter an array of String type, you cannot pass object of other type instead since it causes compile error Type mismatch. Currently you are trying to pass variable haha which is of Variant type.
You can change the type of haha variable to array of strings (to avoid the error described above):
Dim haha() As String
However, in this case you cannot assign the value of function Array to it, since the result of this function is of Variant type.
You would have to replace this code:
haha = Array("Tom", "Mary", "Adam")
with this:
ReDim haha(1 To 3)
haha(1) = "Tom"
haha(2) = "Mary"
haha(3) = "Adam"
A couple of suggestions to improve your code:
Dim haha() As String
You define the type of the entry in the array, not the array itself. Use the way mentioned by mielk to fill the array.
Function Testing(byref check as variant) As String
This will avoid problems with undefined variables. Not clear why you feel that the function should return a string though. Maybe even convert to a Sub instead.

Cannot use class object as argument in other class' method

I'm new to VBA and was surprised it didn't have an official dynamic array, so I tried to make a simple one that suits my needs:
Public count As Integer
Private max As Integer
Private storage(1 To 5) As DVprogram
Private Sub class_initialize()
count = 0
max = 5
End Sub
Public Sub add(data As DVprogram)
If (count + 1) > max Then
updateSize (max + 5)
End If
storage(count + 1) = data
count = count + 1
End Sub
'more code...
When I try to call add, I get the error "Object doesn't support this property or method."
Dim test As New DVprogram
Dim temp As New progDynArray
temp.add (test)
When I change the array type to Integers, everything works fine, but when I try to use one of my own classes, it always throws this error. I've tried switching between ByVal and ByRef and neither had any affect. I also found this: Passing objects to procedures in VBA, but the solution there doesn't appear to be my problem.
You need to use Set when assigning objects:
Set storage(count + 1) = data
and (as noted by Gopi) you need to drop the () when calling your add method:
temp.add test
You don't use parentheses unless you're calling a function or using the Call keyword
EDIT: parentheses (without Call) don't always cause a problem - what they do is cause the argument you're passing to be first evaluated as an expression, and the result of that evaluation then get passed. In the case of updateSize (max + 5) that's not a problem, because that's the behavior you want anyway - to add 5 to max and pass that value to updateSize. In the case of temp.add (test) you don't want test to be evaluated as an expression.
Try temp.add test
instead of temp.add(test)

Is there a VB.NET equivalent for C#'s '??' operator?

Is there a VB.NET equivalent for C#'s ?? operator?
Use the If() operator with two arguments (Microsoft documentation):
' Variable first is a nullable type.
Dim first? As Integer = 3
Dim second As Integer = 6
' Variable first <> Nothing, so its value, 3, is returned.
Console.WriteLine(If(first, second))
second = Nothing
' Variable first <> Nothing, so the value of first is returned again.
Console.WriteLine(If(first, second))
first = Nothing second = 6
' Variable first = Nothing, so 6 is returned.
Console.WriteLine(If(first, second))
The IF() operator should do the trick for you:
value = If(nullable, defaultValueIfNull)
http://visualstudiomagazine.com/listings/list.aspx?id=252
The accepted answer doesn't have any explanation whatsoever and is simply just a link.
Therefore, I thought I'd leave an answer that explains how the If operator works taken from MSDN:
If Operator (Visual Basic)
Uses short-circuit evaluation to conditionally return one of two
values. The If operator can be called with three arguments or with two
arguments.
If( [argument1,] argument2, argument3 )
If Operator Called with Two Arguments
The first argument to If can be omitted. This enables the operator
to be called by using only two arguments. The following list applies
only when the If operator is called with two arguments.
Parts
Term Definition
---- ----------
argument2 Required. Object. Must be a reference or nullable type.
Evaluated and returned when it evaluates to anything
other than Nothing.
argument3 Required. Object.
Evaluated and returned if argument2 evaluates to Nothing.
When the Boolean argument is omitted, the first argument must be a
reference or nullable type. If the first argument evaluates to
Nothing, the value of the second argument is returned. In all other cases, the value of the first argument is returned. The
following example illustrates how this evaluation works.
VB
' Variable first is a nullable type.
Dim first? As Integer = 3
Dim second As Integer = 6
' Variable first <> Nothing, so its value, 3, is returned.
Console.WriteLine(If(first, second))
second = Nothing
' Variable first <> Nothing, so the value of first is returned again.
Console.WriteLine(If(first, second))
first = Nothing
second = 6
' Variable first = Nothing, so 6 is returned.
Console.WriteLine(If(first, second))
An example of how to handle more than two values (nested ifs):
Dim first? As Integer = Nothing
Dim second? As Integer = Nothing
Dim third? As Integer = 6
' The LAST parameter doesn't have to be nullable.
'Alternative: Dim third As Integer = 6
' Writes "6", because the first two values are "Nothing".
Console.WriteLine(If(first, If(second, third)))
You can use an extension method. This one works like SQL COALESCE and is probably overkill for what you are trying to test, but it works.
''' <summary>
''' Returns the first non-null T based on a collection of the root object and the args.
''' </summary>
''' <param name="obj"></param>
''' <param name="args"></param>
''' <returns></returns>
''' <remarks>Usage
''' Dim val as String = "MyVal"
''' Dim result as String = val.Coalesce(String.Empty)
''' *** returns "MyVal"
'''
''' val = Nothing
''' result = val.Coalesce(String.Empty, "MyVal", "YourVal")
''' *** returns String.Empty
'''
''' </remarks>
<System.Runtime.CompilerServices.Extension()> _
Public Function Coalesce(Of T)(ByVal obj As T, ByVal ParamArray args() As T) As T
If obj IsNot Nothing Then
Return obj
End If
Dim arg As T
For Each arg In args
If arg IsNot Nothing Then
Return arg
End If
Next
Return Nothing
End Function
The built-in If(nullable, secondChoice) can only handle two nullable choices. Here, one can Coalesce as many parameters as desired. The first non-null one will be returned, and the rest of the parameters are not evaluated after that (short circuited, like AndAlso/&& and OrElse/|| )
The one significant limitation of most of these solutions is that they won't short-circuit. They are therefore not actually equivalent to ??.
The built-in If operator won't evaluate subsequent parameters unless the earlier parameter evaluates to nothing.
The following statements are equivalent:
C#
var value = expression1 ?? expression2 ?? expression3 ?? expression4;
VB
dim value = if(expression1,if(expression2,if(expression3,expression4)))
This will work in all cases where ?? works. Any of the other solutions would have to be used with extreme caution, as they could easily introduce run-time bugs.
Check Microsoft documentation about If Operator (Visual Basic) here: https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/if-operator
If( [argument1,] argument2, argument3 )
Here are some examples (VB.Net)
' This statement prints TruePart, because the first argument is true.
Console.WriteLine(If(True, "TruePart", "FalsePart"))
' This statement prints FalsePart, because the first argument is false.
Console.WriteLine(If(False, "TruePart", "FalsePart"))
Dim number = 3
' With number set to 3, this statement prints Positive.
Console.WriteLine(If(number >= 0, "Positive", "Negative"))
number = -1
' With number set to -1, this statement prints Negative.
Console.WriteLine(If(number >= 0, "Positive", "Negative"))