To dimension an incoming variable or to not - vb.net

What is the difference between doing this:
Public Sub MySub(ByVal MyString as String)
Dim TheString as String = MyString
myFunction(TheString)
'Some more code...
End Sub
Compared to this:
Public Sub MySub(ByVal MyString as String)
MyFunction(MyString)
'Some more code
End Sub
That is, is there a good reason to dimension a variable in a function/sub again before using it from the argument line? Or does it not matter?
Hope this makes sense, I wasn't sure how to word this question.

If it's a value based Type (e.g: string or integer, double etc.), unless it's passed using the reference (ByRef) instead of the value (ByVal), you shouldn't need to worry about storing it in another variable (unless you wish to have 2 copies)

If the function required a modified string, so you were changing it to fit that, the first code block would make some sense.
However--since it's equal, the only case I can think of you needing the first block of code is if you're needing to keep myString the same within that sub...but I would think if you were doing something like that, most of the time you would just have a totally different sub.
Because you used ByVal-- once you exit that sub, myString will once again be whatever it was initially set to before you entered the sub, because the mystring you're working with inside of the sub is just a copy of the value.
In contrast, if you used ByRef the changes made to the variable would be taken back to the main code and actually change the value of mystring.
You can read about the difference between ByVal and ByRef here: http://social.msdn.microsoft.com/Forums/vstudio/en-US/07b9d3b9-5658-49ed-9218-005564e8209e/what-is-the-difference-between-byval-and-byref
You can take all these concepts and play with how it works in a simple console program to further your understanding. That's what I did, here's some of the code I toyed with to double check what I was saying. Try changing where ByVal & ByRef is used, and maybe printing to the screen after you make a change to see what sticks and what doesn't.
Sub Main()
Dim someString As String = "This is some string."
MySub(someString)
Console.WriteLine(someString)
MyOtherSub(someString)
Console.WriteLine(someString)
Console.ReadLine()
End Sub
Public Sub MySub(ByVal myString As String)
Dim theString As String = myString
MyFunction(theString)
' First line printed in console.
Console.WriteLine(theString)
theString = "Hello."
Console.WriteLine(theString)
Console.WriteLine(myString)
myString = "I'm mystring."
Console.WriteLine(myString)
End Sub
Public Sub MyOtherSub(ByVal MyString As String)
MyFunction(MyString)
End Sub
Public Function MyFunction(ByRef mystring As String)
mystring += "myFunction is acting on this string."
End Function

Related

VB dynamic parameters for functions

Is there any way to get the parameters of a function dynamic?
Like:
Function(text As String, If text = "yes" text2 As String)
End Function
So the second one just gets asked, when the first is filled or a certain value?
Optional is no way, cause for example the third needs to be filled when the second one is already.
No, you can't do that. But you might accomplish something similar via Currying.
Currying takes a function that needs multiple arguments, and converts into a set of functions that each need a single argument, where prior functions in the set return the next function in the set.
Where this will still be problematic for your situation is .Net likes strongly-typed delegates. If the initial function needs to return a method with one argument for any case, it must do that for all cases.
However, that doesn't mean it returns the same function. You can still vary which function is returned based on the initial input argument.
So instead of this:
Function test(text As String, a As String) As String
If text = "yes" Then
Return text & a
Else
Return a & text
End If
End Function
test("yes", "foo") ' produces "yesfoo"
test("no", "foo") ' produces "foono"
We have this:
Function test(text As String) As Func(Of String, String)
If text = "Yes" Then
Return Function(a) text & a
Else
Return Function(a) a & text
End If
End Function
test("yes")("foo") ' produces "yesfoo"
test("no")("foo") ' produces "foono"
This won't do exactly what you want; it still requires the additional argument or not in every situation. But it might give you enough new flexibility to accomplish your ultimate goal. For example, perhaps you could combine this with a closure, where you never use the additional argument, but in the case where you need it the additional value is still available. Exactly how this will look or whether it's really possible or helpful will depend on the details of what you're trying to accomplish beyond the simple test code in the question.
You could handle what to pass in the button code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim paramValue As String
If MyTestText = "yes" Then
paramValue = TextBox2.Text
Else
paramValue = TextBox1.Text
End If
End Sub
Private Function SomeFunction(text As String) As String
Dim ReturnValue As String = ""
'your code here
Return ReturnValue
End Function
Or you could pass both values and test in your Function code
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ReturnedValue = SomeFunction(TextBox1.Text, TextBox2.Text)
End Sub
Private Function SomeFunction(text1 As String, text2 As String) As String
Dim ReturnValue As String = ""
If MyTestText = "yes" Then
'process text2
Else
'process text1
End If
Return ReturnValue
End Function
I am sure there are other ways to handle this.

What is the & operating doing in this situation

In the function below, what is the meaning of the & character? I'm not aware how it's valid syntax or how this would be used normally.
Normally using &= together would do a concatenation and assignment, resulting in "Hello world". However in this "typo" the code actually compiles but the result is just an assignment of " world" to the MyStr variable. Also if you define MyStr in the function rather than at the class level, the result is that it will not compile and interprets the & as a Type Character and fails because MyStr is a string and not of type Long.
Public Class MyClassName
Private MyStr As String
Public Sub New()
End Sub
Public Function MyFunction() As String
MyStr = "Hello"
MyStr& = " World"
Return MyStr
End Function
End Class
Microsoft admits it's a bug in the compiler.
It is not going to be fixed because that would be a breaking change.
As you mention, the & is acting as a type character. Type characters are essentially just a shorthand for declaring the type of a variable. For example, you could use
dim value& = 100 rather than dim value as Long = 100
They are generally used when defining a value on the fly, such as when passing a value to a function:
dim result = funcThatTakesALong(100&)
You can also see in the link that you posted there are also type characters for integers (%), decimals (#), singles (!), doubles (#), and strings ($).
Edit: formatting
I think this may explain the purpose of the operators
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
XYZ(9&) ' Long values
XYZ(9L)
XYZ(9I) ' Int32 values
XYZ(9%)
XYZ(9S) 'Int16 value
XYZ("9"c) ' a single charcter
XYZ("9") ' a string
End Sub
Sub XYZ(ByVal arg As Object)
Debug.Print("arg type is " & arg.GetType.ToString)
'do some stuff depends on the type of arg
End Sub
.

How can I assign a value to a number of different variables in a collection using loops?

I have a problem that has been bugging me for a while now. Consider this code:
Public Class Class1
Dim VariableList as New List(of Object) From {MainForm.X, MainForm.Y,
SettingsForm.Z, SettingsForm.Textbox1.Text} '...etc.
Sub SetToZero()
For Each Element in VariableList
Element = 0
Next
End Sub
Sub SetToCustomValue(value As Double)
For Each Element in VariableList
Element = value
Next
End Sub
Sub LoadValuesFromFile()
Dim path As String = MainForm.GetPath()
For Each Element in VariableList
Element = File.Readline()
Next
End Sub
Sub SaveValuesToFile()
Dim path As String = MainForm.GetPath()
For Each Element in VariableList
Element = File.Writeline()
Next
End Sub
'and more similar functions/subs
As you can see, what this class does is that it takes lot of different variables from different places into a collection, and then various functions read or write values to every variable in that collection using loops. In this example, I have just a few variables, but most of the time there are dozens.
Reading the values is not a problem. Writing them, is, because when I declare that VariableList at the top of my class, that List just makes a copy of each variable, rather than maintaining a reference to it. Meaning that if, say, one of the functions modifies the MainForm.X in that List, the actual variable MainForm.X is not modified. To work with references, I would have to forgo loops, and assign every single variable manually, in every function. Which is obviously a lot of bad code. I want to declare that list of variables only once, and then use loops, like in this example code that I wrote above. My question is, how can I make such a container (List, Array, whatever) that would retain the references to the original variables in it, and make the code above possible?
There is no easy way to store pointers to variables in VB.NET. As a workaround, you can use a class to store your variables, as a class is always used as a pointer.
Here's an example of a way to achieve this with a ContainerClass which own a Dictionary of integers. One interest of this method would be that you can declare and name "variables" dynamically. In reality, they will be managed KeyValuePair. Once you have instantiated a copy of this class, you can use it to "manage" your variables by using this class as your pointer.
I included a loop which set all the integers to the same number just for fun, and to demonstrate the kind of manipulation which would end up having an effect similar to one of those described in your question.
Public Class Form2
'This is the container class which will be used to bypass the lack of pointers
'if you wanted to change a property, like the window width, it would be more difficult, but simples variables will be no trouble
Private variableContainer As New VariableContainer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
variableContainer.AddVar("X", 5)
variableContainer.AddVar("Y", 15)
Debug.Print(variableContainer.GetVar("X"))
Debug.Print(variableContainer.GetVar("Y"))
variableContainer.SetAllVar(42)
Debug.Print("Next line will print 42")
Debug.Print(variableContainer.GetVar("X"))
End Sub
End Class
Public Class VariableContainer
'I know a public variable wouldn't need the fancy functions down there, but it's usually better to encapsulate, especially if you're working with a team
'and "future you" count as a teammate, never forget that...
Private list As New Dictionary(Of String, Integer)
Public Sub AddVar(ByVal name As String, ByVal value As Integer)
list.Add(name, value)
End Sub
Public Function GetVar(ByVal name As String) As Integer
If list.ContainsKey(name) Then
Return list(name)
Else
'I choose -1 arbitrarily, don't put too much thinking into this detail
Return -1
End If
End Function
Public Sub SetVar(ByVal name As String, ByVal num As Integer)
If list.ContainsKey(name) Then
list(name) = num
End If
End Sub
Public Sub SetAllVar(ByVal num As Integer)
Dim dict As New Dictionary(Of String, Integer)
For Each item As KeyValuePair(Of String, Integer) In list
dict.Add(item.Key, num)
Next
list = dict
End Sub
End Class
Have fun!

VBA Encryption Method

I have written a very simple Ceaser Cipher encryption algorithm on VBA. It takes a string value and applies x shift.
Quite happy with it. However, would like to take it to the next step, but I am not sure if it is doable.
I would like to call this encryption function in another module and pass a string value to encrypt.
I.e. What I am trying to do is something like this
Private Sub Encryption()
'Encryption method of string Var
End Sub
---- and in another sub ----
Private Sub function()
Dim Text as String
Text = "Hello"
Encryption(Text)
End Sub
So in this example, I have defined a method to encrypt any string variable. In the other function, I defined a string and initialised it as "Hello". Then called Encryption function on it... Not sure if this is doable in VBA?
I am not sure how I could pass in a variable when I am calling a function within a function. Any advise please?
You would need to change the Sub Routine to a Function. Also, get rid of the Private keyword as this will not allow you to call it across different modules.
So Change this:
Private Sub Encryption()
'Encryption method of string Var
End Sub
to this:
Function Encryption(ByVal inputString as String) As String
'Encryption method of string Var
End Sub
Now, inside your function you need to change whatever variable holds the first string (the one to be encrypted) to the newly created variable, inputString. It's hard to help you in this area as you did not provide the full code for Sub Encryption().
Also, ensure that you set the Function name itself to the newly encrypted text within the function. So your function would essentially look as follows:
Function Encryption(ByVal inputString as String) As String
'Encryption method of string Var
Encryption = 'the value to return from this function
End Sub
Now, your second sub would look like this:
Private Sub test()
Dim Text as String, encryptedText as String
Text = "Hello"
encryptedText = Encryption(Text)
End Sub
You will just make the new variable encryptedText equal to the new function, Encryption.
So, the major difference between a Sub and a Function is that a Function will return values. They both essentially process code the same way.
METHOD 2 (Edit)
After rethinking your question, I believe that you were using your Sub to obtain your encrypted text from passing the variable as ByRef, and you may just be having difficulties with calling the Sub because of the Private keyword.
If this what was going on, then you can simply remove the Private keyword and it should work as intended.
So your Sub should look like:
Sub Encryption() '<-- Notice, no Private scope
'Encryption method of string Var
End Sub
or
Public Sub Encryption()
'Encryption method of string Var
End Sub
You should take a look at this for additional reading regarding scope.

What are delegates, how are they used?

After being alerted by a user that the basis of my question was based on erroneous knowledge I have edited the title of this question with what should have been my original question and have erased the previous content. Below is, what I think, an excellent explanation of delegates.
From what you are saying, your ideas regarding delegates do not seem to be completely clear. Thus, the whole point of this answer is clarifying what delegates actually are such that you can apply this knowledge to understand the code you propose or any other delegate-related situation.
Delegates are a way to treat functions as variables. That is, instead of doing Dim myString as String = "this", substituting "this" with a function.
Simple code to clarify what a delegate is and how it has to be treated:
Public Class Form1
Public Delegate Sub subDelegate(arg1 As String, arg2 As String)
Public subDelegateVar As subDelegate
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
subDelegateVar = New subDelegate(AddressOf origSub)
subDelegateVar.Invoke("this", "that")
End Sub
Public Sub origSub(arg1 As String, arg2 As String)
MsgBox("I want to write " & arg1 & " and " & arg2)
End Sub
End Class
You have the function (Sub) origSub and you want to treat it as a variable. First thing you have to do is declaring a delegate matching its structure:
Public Delegate Sub subDelegate(arg1 As String, arg2 As String)
This is like defining a type (the string type in the example above). Next step is declaring a variable associated with this type (myString in the example above), what is done with the following code:
Public subDelegateVar As subDelegate
And the third step is assigning this variable to the value you want (myString = "this") what is done via:
subDelegateVar = New subDelegate(AddressOf origSub)
What is Invoke here for? Just for calling the given function. Why creating a new variable (delegate), assigning a function to it and using Invoke to call the function instead of calling this function directly? Because some times you need the function to be treated as a variable; for example: when you want to pass it (the whole function) as an argument to another function -> this is one of the reasons why delegates are required, not the only one (not even close).