Want to make a cache - vb.net

Here's the code for the problem I'm having. It's pretty simple but I'm still learning.
I want to cache the result so the function returns a few seconds quicker than it currently is. At the moment it is returning to the caller in 4 when it should be 2.
Sub Main
console.writeline(getmyresult(2)) 'takes a while'
console.writeline(getmyresult(3)) 'takes a while'
console.writeline(getmyresult(2)) 'Should be instant'
console.writeline(getMyresult(3)) 'Should be instant'
End Sub
function getMyresult(X as interger) as integer
dim Y as integer=LongCompute(X)
return Y
end function
function LongCompute(X as integer) as integer
system.threading.thread.sleep(1000)
return x^2
end function
Any help would be greatly appreciated.

Yep, this is called memo-ization.
You can read up on it here:
http://en.wikipedia.org/wiki/Memoization
A simple implementation in visual basic would look like:
Dim dict As New Dictionary(Of Integer, Integer)
Sub Main()
console.writeline(getmyresult(2)) 'takes a while'
console.writeline(getmyresult(3)) 'takes a while'
console.writeline(getmyresult(2)) 'Should be instant'
console.writeline(getMyresult(3)) 'Should be instant'
End Sub
Function getMyresult(ByVal X As Integer) As Integer
If dict.ContainsKey(X) Then
Return dict(X)
Else
Dim temp = LongCompute(X)
dict.Add(X, temp)
Return temp
End If
End Function
Function LongCompute(ByVal X As Integer) As Integer
System.Threading.Thread.Sleep(1000)
Return x ^ 2
End Function

For a simple exercise you can put the results into a Dictionary, as James Culshaw suggested. The key is the input, the value is the cached result.
If this was for serious work I would rather consider using System.Runtime.Caching.MemoryCache. The problem with a dictionary is that items never get out of it (in a way they leak, altough if the input domain is bounded it's not that bad). A production-ready cache would handle memory pressure or support items expiration (e.g. cache the result for 10 minutes). Those requirements are handled by MemoryCache.
Caching the result of a function that has no side-effect and depends only on its inputs is formally called Memoization. A nice extension to your programming exercise would be to write a generic memoization function that can wrap any regular (slow) function. E.g. FastCompute = Memoize(SlowCompute).

Simple option would be to use a Dictionary object and then check to see if the key has been set for the parameter passed into getmyresult. If it has, pass the value stored in the dictionary, if not process the result, add it to the dictionary, and then return the result. second call will be near instantaneous as its already cached in the dictionary.

Related

System.StackOverflowException intersection error

I want my program to take a variable, and find letters A-Z. I have made this section of my program in a module to be shared between 2 different forms.
variables are passed from form1 and are processed by the module and then sent back again to form1. the problem is I think some sort of bug in the code but I cant identify it.
Public Function UPCASES(ByRef password1, points) As Boolean
Dim intersection As IEnumerable(Of Char)
intersection = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Intersect(password1)
'System.StackOverflowException error ^^^^^^^^^^^^^^^^^^^^^^^^^
If intersection.Count() = 1 Then
points = 5
Else
points = 0
End If
Return UPCASES(password1, points)
End Function
You are calling the method itself at the method end, that causes the StackOverflowException:
Return UPCASES(password1, points)
I guess this method should check if the password contains uppercase letters, then use:
Dim containsUpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Intersect(password1).Any()
So no need to create a method just for this one-liner, if you need a method:
Public Function ContainsUpperCaseLetter(password1 As String) As Boolean
Return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Intersect(password1).Any()
End Function
Side-note: you should change your default project settings to use Option Strict ON(Off is default unfortunately). Then you will be able to write much more safe, robust and performant code after you have learned a lot about .NET types because you have to fix the compiler errors.

(Micro Optimisation) - Exit function or let it run through all code

I am curious if Exit Sub, Exit Function, among others should be avoided when coding? I have read in various places that it is a bad practice and that you should, if possible, avoid it.
I have provided a function below to demonstrate what I mean:
Function Test()
Dim X As Integer
X = 5
If X = 10 Then
Test = True
Exit Function
Else
Test = False
Exit Function
End If
End Function
In the case above, the Exit Function isn't necessary since the entire code will be able to finish the entire routine without an issue. But by adding it, will it cause some issues?
The style you're using is from the VB5 and VBA era, which didn't support Return statement and we needed to assign the return value directly to the function name. In VB.NET you should always use Return assignment. Return will do both the assignment and the exit call in one statement.
Regarding your particular example, my impression is that the Exit Function statement does nothing more than doing a GoTo to the nearest End Function line. So these statements in your case are redundant and might get striped off by the compiler (not sure about this one).
Note that Exit statements become a nightmare from code-readability point of view. I have recently been a victim of this particular problem. Visual Basic is such a verbose language and Exit statements go unnoticed by the reader. A structured If/Else block is FAR more readable.
This depends on the current context of your code. If you are within a block (be that a loop, Sub or function etc.) and are attempting to leave, the Exit Statement will do fine.
The Return Statement will also work the same as a Exit Function or Exit Sub, see the answer to this SO question. But personally I prefer the exit statement in a function when I wish to return control to the calling code, but have no value to return.
In practically every case, there's a "better" approach than using Exit Function.
The following example will give the same result, but is shorter, and in my opinion much clearer.
Function Test() As Boolean
Dim X As Integer
X = 5
Return (X = 10)
End Function
To clarify a little, as #dotNET said. This is pre .net code. In dot net, you would change your code slightly to
Function Test() As Boolean
Dim X As Integer
X = 5
If X = 10 Then
Return True
Else
Return False
End If
End Function
This defines test as a function that returns a Boolean result and you use the Return statement to err.. return the result back to the calling statement and exits the function immediately at the aforementioned Return statement
for example ..
Dim result As Boolean
result = test

Getting Duplicate Random Numbers

I'm doing basic random number generation using this Shared Function:
Public Shared Function RandomNumber(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
'initialize random number generator
Dim r As New Random(Date.Now.Ticks And &HFFFF)
If MinNumber > MaxNumber Then
Dim t As Integer = MinNumber
MinNumber = MaxNumber
MaxNumber = t
End If
Return r.Next(MinNumber, MaxNumber)
End Function
Called like this: dim x as integer = Random(2100000000)
Very simple, and the seed value comes straight from a MS example.
HERE'S THE PROBLEM: I'm getting duplicate numbers on occasion, but always created at times that are usually at least 5 or 10 minutes apart. I can see if I was calling the function multiple times per second or millisecond, because that'd kind of "breaks" the seed. But these are showing up at extended time spans. What else could be causing this?
Duplicate seed issue?
It might be better defining r as static so that it is initialised once when first invoked. Refer to this answer Random integer in VB.NET
The Random constructor takes an Integer as its parameter which is 32-bits. As spencer7593 said, with only 16 bits, you're repeating the sequence every 6.5ms. Try:
Dim r As New Random(Date.Now.Ticks And &HFFFFFFFF)
However, this will do the same thing:
Dim r As New Random()
Better yet, don't create a new Random object each time:
Private Static r As New Random()
Public Shared Function RandomNumber(MaxNumber As Integer, Optional MinNumber As Integer = 0) As Integer
...
Return r.Next(MinNumber, MaxNumber)
End Function
Q: What else could be causing this?
A: It could be happening purely by random. Random numbers are just that: random. At any point in time, whether its seconds or hours away from another point in time, its just as likely for a number to appear as any other number. There is no guarantee that a number won't be repeated.
On the other hand, it looks like your seed value is only on the order of 16 bits. And that's like a total of 65,536 possibilities. There's 10,000 ticks in a millisecond, so ever 6.5 milliseconds you have the possibility of reusing the same seed.
It's not at all clear whether the VB Random is using some other kind of entropy beyond that seed or not. (But gathering entropy for inclusion would slow down the initialization, so it may not be, as a performance consideration.)
According the docs, creating two Random objects using the same seed value results in Random objects that create duplicate sequences of unique numbers.
http://msdn.microsoft.com/en-us/library/ctssatww.aspx
I think that answers the question why it is happening.
I guess the next question is why do you need to instantiate a new Random object? If you need multiple objects, then instantiating several of them, but making sure you are using a different seed value for each one would be one approach.
But before you go there, I recommend you consider using just one Random. Calls to get random numbers can be serviced from an existing Random, rather than creating a new one every time you need a random number.
Try it another way:
Public Function RandomNumber2(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
' Initialize the random-number generator.
Randomize()
' Generate random value between MaxNumber and MinNumber.
Return CInt(Int((MaxNumber * Rnd()) + MinNumber))
End Function
See Randomize Function (Visual Basic) for more details. Hope this helps.

Looping Through Boolean Parameters

I have a generic question to see if anyone can help me with a better solution.
I have a .NET method that takes in 20+ boolean values, passed in individually.
For each parameter that is true I need to add a value to list.
Is there a more efficient way to add the values to the list besides have an if statement for each boolean?
Example:
Public Function Example(ByVal pblnBool1 as boolean, _
ByVal pblnBool2 as boolean, _
ByVal pblnBool3 as boolean)
If pblnBool1 then
list += "A"
End If
If pblnBool2 then
list += "B"
End If
End Function
Obviously this code isn't correct but it shows what I'm trying to do.
Anyone have any ideas?
Thanks
First off, having 20+ params sucks.
Secondly, you can use the ParamArray keyword to declare that you want the values passed to you in an array. (I don't think this is CLS compliant, meaning some languages won't be able to call your function without bundling the values into an array. But VB and C# can both easily work with each other's param arrays.) If you don't want to do that, you can always create the array yourself in your function. But i'd rather let the language and/or framework do that for me.
This is not optimized or anything; it's just an example.
sub Example(paramarray bools() as Boolean)
static vals() as String = {"A", "B", "C"}
if bools.Length > vals.Length then
throw new ArgumentException(String.Format( _
"Too many params! ({0} max, {1} passed)", _
vals.Length, bools.Length _
))
end if
for i as Integer = 0 to bools.Length - 1
if bools(i) then list += vals(i)
next
end sub
I assume that list is some member variable, since it's not defined in your code. If you intend for it to be the return value, then declare it in the function, and return it at the end. (And of course, turn sub Example(...) and end sub into function Example(...) as String and end function).
If you have 32 or fewer booleans to pass, you can use an instance of BitVector32. This allows to pass them all in a single integer. It provides methods for setting and retrieving the values.
Just make an array of boolean values and do a for...each loop through it. Or if you need to be selective, a 2-D array.

Return values with reference arguments or by structure

In what situtations is it best to use reference arguments to return values?
Sub Example(byref value as integer)
value = 3
End Sub
In what situations is it best to return the value (perhaps in a structure for more complex types)?
Function Example() as integer
return 3
End Function
In general, I'd avoid using reference arguments to return values.
THe design guidelines suggest avoiding this, which is why the Microsoft code analysis tools warn you when they find it.Do not pass types by reference.
It's nearly always more maintainable to return values instead of passing arguments by reference, unless there is a very specific need to do so. If you're generating a new value, return it.
when you want to return a state or status of an operation plus the result from the operation.
think of TryParse..it returns a conversion result as true or false and it returns the converted value by a ref variable.
Dim number As Integer
Dim result As Boolean = Int32.TryParse(value, number)
Public Shared Function TryParse ( _
s As String, _
<OutAttribute> ByRef result As Integer _
) As Boolean
but other than that, as others suggested i would not use by ref a lot, it can make code very hard to read and debug.
It really depends what the function's doing. Generally, though, if there's only one return, by value is easier for the caller. They can simply do:
int foo = Example(foo)
or:
int modifiedFoo = Example(foo)
as they prefer.