Returning values from functions in structures in Visual Basic - vb.net

I hope the title of the post isn't too much of a mess. I'm reviewing some course material from last week, and there is just one thing I don't understand in regard to this particular structure and the add and subtract functions in it:
Structure ComNum
Dim Re As Double
Dim Im As Double
Function add(ByVal br As ComNum) As ComNum
add.Re = br.Re + Re
add.Im = br.Im + Im
End Function
Function subt(ByVal br As ComNum) As ComNum
subt.Re = br.Re - Re
subt.Im = br.Im - Im
End Function
End Structure
Sub Main()
Dim a, b, c As ComNum
a.Re = 2
a.Im = 3
b.Re = 4
b.Im = 5
c = a.add(b).add(b).subt(b)
Console.WriteLine("The second number added twice and subtracted once from the first number gives {0}+{1}i", c.Re, c.Im)
End Sub
Now, the way I understand functions is that once anything is returned from it, execution of the function stops at that exact line where the value is returned and nothing after it gets executed. According to that, it should add the real part and exit the function.
I know I'm missing a key thing here and I'd appreciate it if someone could explain this to me.

The way you have this setup those functions are creating a new, empty ComNum structure each time you call them (named either add or subt based on the function name). Unless you manually return them early it will just default to returning the function named structure.
Function add(ByVal br As ComNum) As ComNum
add.Re = br.Re + Re
add.Im = br.Im + Im
End Function
Is basically doing the equivalent of:
Dim add As New ComNum
add.Re = br.Re + Re
add.Im = br.Im + Im
Return add
Though like Lars pointed out I'm not sure why you'd want this to be a function vs a sub. Using it the way you have it setup now requires you to do something like this to get the add/subtract values because you need to capture the returned ComNum object.
Dim a As New ComNum With {.Im = 1, .Re = 1}
'Im = 6, Re = 6
a = a.add(New ComNum With {.Im = 5, .Re = 5})
Doing something like this makes more sense to me.
Structure ComNum
Dim Re As Double
Dim Im As Double
Sub add(ByVal br As ComNum)
Re += br.Re
Im += br.Im
End Sub
Sub subt(ByVal br As ComNum)
Re -= br.Re
Im -= br.Im
End Sub
End Structure
Then you could just call it this way to update the struct without having to capture the returned values.
a.add(New ComNum With {.Im = 5, .Re = 5})
Edit: Knowing more now how the exercise is supposed to be performed I'd suggest something like this for the struct:
Public Overrides Function ToString() As String
Return String.Format("Re: {0} Im: {1}", Re, Im)
End Function
Then you could call the .ToString() method like this. Though, just a thought.
Console.WriteLine("The second number added twice and subtracted once from the first number gives {0}", c.ToString())

Related

unable to add items to a list in VB.NET

Good morning,
so i have received this homework for the summer where i have to create a program to store a list of movies and display them, but the problem is that there isn't a defined number of movie so i can't use the constant method i've always used, so i tried doing that with variables instead, but whenever i press the input button twice the app crashes and i get the error "Index over the matrix limits"
Here's the code in the module
Module Module1
Public Structure Film
Public Titolo As String
Public Autore As String
Public Incasso As Integer
Public Nazionalita As String
End Structure
Public i As Integer = 0
Public Flm(i) As Film
End Module
And here's the input part
Public Class frmInput
Private Sub btnInserisci_Click(sender As Object, e As EventArgs) Handles btnInserisci.Click
If IsNumeric(txtIncasso.Text) = False Then
MsgBox("L'incasso deve essere un valore numerico", MsgBoxStyle.Exclamation, "Attenzione")
ElseIf txtTitolo.Text = "" Or txtAutore.Text = "" Or txtNazionalita.Text = "" Then
MsgBox("Uno o piĆ¹ valori sono vuoti", MsgBoxStyle.Exclamation, "Attenzione")
Else
Flm(i).Titolo = txtTitolo.Text
Flm(i).Autore = txtAutore.Text
Flm(i).Incasso = txtIncasso.Text
Flm(i).Nazionalita = txtNazionalita.Text
i += 1
End If
End Sub
End Class
You should use a List(Of Film) to store the inputs received.
A generic List like that has no practical limits and can grow while you add elements to it
Public Flm As List(Of Film) = new List(Of Film)
....
Else
Dim f as Film = new Film()
f.Titolo = txtTitolo.Text
f.Autore = txtAutore.Text
f.Incasso = txtIncasso.Text
f.Nazionalita = txtNazionalita.Text
Flm.Add(f)
End If
A List(Of Film) could be used like it was an array
For x As Integer = 0 To Flm.Count -1 Step 1
Console.WriteLine("Film #" & x+1)
Console.WriteLine("Titolo = " & Flm(x).Titolo)
.....
Next
And of course you can iterate over it using a simpler foreach
For Each Film f in Flm
Console.WriteLine("Film #" & x+1)
Console.WriteLine("Titolo = " & f.Titolo)
.....
Next
Although others have mentioned using List, which would probably be appropriate, you also mentioned it was a homework task, so maybe you need, or have to, use the more traditional arrays as you have shown. Bearing this in mind, and also to let you know what your problem is. You are incrementing i but not the array.
Public i As Integer = 0
Public Flm(i) As Film
Thus, Flm is 0 to 0, one element.
You add to this, all is OK.
You increment i, good, i += 1
However, you don't then increment the array, Flm(). Incrementing i doesn't automatically increment the array, Flm().
You need to use: ReDim Preserve
Thus... Change:
Else
Flm(i).Titolo = txtTitolo.Text
to:
Else
ReDim Preserve Flm(i)
Flm(i).Titolo = txtTitolo.Text
Lastly, IsNumeric and MsgBox are remnants of the VB6 days, there are vb.net equivalents. Also, using i as a global/public variable is really not good. It's very common, standard, to use i in all local subroutines and functions for little loops etc, it gets used and lost. If you look at almost all examples of code, you'll see i being used as the integer counter.

Issue with ByVal and Arrays in Functions (VB.NET)

I've ran into an issue with my code for the last week or so, and its been killing me trying to figure out what's wrong with it. I've extracted and isolated the issue from my main project, but the issue still isn't apparent.
Essentially, I have a function that usually does a lot of stuff, but in this example just changes 1 element in an array called FalseTable. Now, I have set this variable to be ByVal, meaning the original variable (ie: TrueTable) shouldn't change, however, it does! Here is the full code:
Dim TrueTable(7) As Char
Sub Main()
Dim FalseTable(7) As Char
For x = 0 To 7
TrueTable(x) = "T"
Next
For x = 0 To 7
FalseTable(x) = "F"
Next
Console.WriteLine("before")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
Test(TrueTable)
Console.WriteLine("result")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
Console.ReadLine()
End Sub
Function Test(ByVal FalseTable() As Char) As Char()
FalseTable(0) = "0"
Return FalseTable
End Function
Now, I used to think that it was the repetition of the name "FalseTable" in the function, however even if I change the function to:
Function Test(ByVal SomeTable() As Char) As Char()
SomeTable(0) = "0"
Return SomeTable
End Function
And not modify the rest, the issue still persists - for some reason, TrueTable is being updated when it shouldn't due to the ByVal status.
Any help with this would be greatly appreciated; it's probably something stupid that I've overlooked, but it's pulling my hair out!!
Many thanks,
Alfie :)
If you don't want to change the TrueTable, define another Array and copy TrueTable to it.
Here's the code you can refer to.
Dim TrueTable(7) As Char
Dim TrueTable2(7) As Char
Sub Main()
For x = 0 To 7
TrueTable(x) = "T"c
Next
Console.WriteLine("before")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
TrueTable.CopyTo(TrueTable2, 0)
Test(TrueTable2)
Console.WriteLine("result")
For x = 0 To 7
Console.Write(TrueTable(x))
Next
Console.WriteLine()
Console.ReadLine()
End Sub
Result:
To understand why that happens just imagine this scenario.
You have a regular TextBox1 (this will be your TrueTable), now you want to pass the object TextBox1 to a function, something like this:
Function Test(ByVal TextBoxAnything as TextBox) As String
TextBoxAnything.Text = "0"
Return ""
End Function
Do you understand that you're passing thru TextBox1 and once inside the function Test the object TextBoxAnything is just TextBox1, anything you do to TextBoxAnything you're just doing it to TextBox1. TextBoxAnything doesn't exist, it just points to Textbox1. That's why the value of your TrueTable is also changed.

vb.net function branching based on optional parameters performance

So I was coding a string search function and ended up with 4 since they needed to go forwards or backwards or be inclusive or exclusive. Then I needed even more functionality like ignoring certain specific things and blah blah.. I figured it would be easier to make a slightly bigger function with optional boolean parameters than to maintain the 8+ functions that would otherwise be required.
Since this is the main workhorse function though, performance is important so I devised a simple test to get a sense of how much I would lose from doing this. The code is as follows:
main window:
Private Sub testbutton_Click(sender As Object, e As RoutedEventArgs) Handles testbutton.Click
Dim rand As New Random
Dim ret As Integer
Dim count As Integer = 100000000
Dim t As Integer = Environment.TickCount
For i = 0 To count
ret = superfunction(rand.Next, False)
Next
t = Environment.TickCount - t
Dim t2 As Integer = Environment.TickCount
For i = 0 To count
ret = simplefunctionNeg(rand.Next)
Next
t2 = Environment.TickCount - t2
MsgBox(t & " " & t2)
End Sub
The functions:
Public Module testoptionality
Public Function superfunction(a As Integer, Optional b As Boolean = False) As Integer
If b Then
Return a
Else
Return -a
End If
End Function
Public Function simpleFunctionPos(a As Integer)
Return a
End Function
Public Function simplefunctionNeg(a As Integer)
Return -a
End Function
End Module
So pretty much as simple as it gets. The weird part is that the superfunction is consistently twice faster than either of the simple functions (my test results are "1076 2122"). This makes no sense.. I tried looking for what i might have done wrong but I cant see it. Can anybody explain this?
You didn't set a return type for simple function. So they return Object type.
So when you using simpleFunctionNeg function application convert Integer to Object type when returning value, and then back from Object to Integer when assigning returning value to your variable
After setting return value to Integer simpleFunctionNeg was little bid faster then superfunction

LINQ VB.net Return Single Type of Object Invalid Cast

Ok, just needing a 2nd set of eyes looking at this to make sure the error isn't something else other than my LINQ code here. Here's the function class itself:
Public Function GetJacketByPolicyID(ByVal jacketID As Int32) As tblPolicy
Dim db As New DEVDataContext()
Dim j As tblPolicy = db.tblPolicies.Single(Function(p) p.policyNumber = jacketID)
Return j
End Function
and here is the code which calls this class function in the web control form itself:
Dim p As tblPolicy
Dim j As New Jackets()
p = j.GetJacketByPolicyID(3000050)
For some reason it's flagging the 2nd line in the GetJacketByPolicyID function saying the specified cast is not valid. So I'm guessing it's something I'm doing wrong. I'm sure the tblPolicy/tblPolicies class works right since I can create a new instance of a tblPolicy and set a few variables by hand and return it, so that's not it. I've also checked the datarow I'm fetching and there's no null values in the record, so that shouldn't be it either.Any help much appreciated.
This would seem to get what you are looking for. Not sure why you are passing in a function for a simple query like this.
Public Function GetJacketByPolicyID(ByVal jacketID As Int32) As tblPolicy
Dim _jacket as tblPolicy
Using _db As New DEVDataContext()
_jacket = (From _j In db.tblPolicies Where _j.policyNumber.Equals(jacketID) Select _j).Single()
End Using
Return _jacket
End Function

VB.Net List.Find. Pass values to predicate

Having a bit of trouble using the List.Find with a custom predicate
i have a function that does this
private function test ()
Dim test As Integer = keys.Find(AddressOf FindByOldKeyAndName).NewKey
here's the function for the predicate
Private Shared Function FindByOldKeyAndName(ByVal k As KeyObj) As Boolean
If k.OldKey = currentKey.OldKey And k.KeyName = currentKey.KeyName Then
Return True
Else
Return False
End If
End Function
by doing it this way means i have to have a shared "currentKey" object in the class, and i know there has to be a way to pass in the values i'm interested in of CurrentKey (namely, keyname, and oldkey)
ideally i'd like to call it by something like
keys.Find(AddressOf FindByOldKeyAndName(Name,OldVal))
however when i do this i get compiler errors.
How do i call this method and pass in the values?
You can cleanly solve this with a lambda expression, available in VS2008 and up. A silly example:
Sub Main()
Dim lst As New List(Of Integer)
lst.Add(1)
lst.Add(2)
Dim toFind = 2
Dim found = lst.Find(Function(value As Integer) value = toFind)
Console.WriteLine(found)
Console.ReadLine()
End Sub
For earlier versions you'll have to make "currentKey" a private field of your class. Check my code in this thread for a cleaner solution.
I have an object that manages a list of Unique Property Types.
Example:
obj.AddProperty(new PropertyClass(PropertyTypeEnum.Location,value))
obj.AddProperty(new PropertyClass(PropertyTypeEnum.CallingCard,value))
obj.AddProperty(new PropertyClass(PropertyTypeEnum.CallingCard,value))
//throws exception because property of type CallingCard already exists
Here is some code to check if properties already exist
Public Sub AddProperty(ByVal prop As PropertyClass)
If Properties.Count < 50 Then
'Lets verify this property does not exist
Dim existingProperty As PropertyClass = _
Properties.Find(Function(value As PropertyClass)
Return value.PropertyType = prop.PropertyType
End Function)
'if it does not exist, add it otherwise throw exception
If existingProperty Is Nothing Then
Properties.Add(prop)
Else
Throw New DuplicatePropertyException("Duplicate Property: " + _
prop.PropertyType.ToString())
End If
End If
End Sub
I haven't needed to try this in newer versions of VB.Net which might have a nicer way, but in older versions the only way that I know of would be to have a shared member in your class to set with the value before the call.
There's various samples on the net of people creating small utility classes to wrap this up to make it a little nicer.
I've found a blog with a better "real world" context example, with good variable names.
The key bit of code to Find the object in the list is this:
' Instantiate a List(Of Invoice).
Dim invoiceList As New List(Of Invoice)
' Add some invoices to List(Of Invoice).
invoiceList.Add(New Invoice(1, DateTime.Now, 22))
invoiceList.Add(New Invoice(2, DateTime.Now.AddDays(10), 24))
invoiceList.Add(New Invoice(3, DateTime.Now.AddDays(30), 22))
invoiceList.Add(New Invoice(4, DateTime.Now.AddDays(60), 36))
' Use a Predicate(Of T) to find an invoice by its invoice number.
Dim invoiceNumber As Integer = 1
Dim foundInvoice = invoiceList.Find(Function(invoice) invoice.InvoiceNumber = invoiceNumber)
For more examples, including a date search, refer to Mike McIntyre's Blog Post