I am trying to learn more about programming language.
I am using the following code using Recursion.
I cause it to run until a stack exception is thrown.
Without traping the error and/or defensively coding to prevent
such a deep recursion: - Are there adjustments I can make
to free any stack space when this routine runs?
Module Module1
Private var As Integer = 1
Sub Main()
Take1(var)
End Sub
Public Function Take1(p1 As Integer) As Integer
p1 = p1 + 1
Console.Write(p1 & vbCrLf)
Take1 = Nothing
Call Take2(p1)
End Function
Public Function Take2(p1 As Integer) As Integer
p1 = p1 + 1
Console.Write(p1 & vbCrLf)
Take2 = Nothing
Call Take1(p1)
End Function
End Module
Your code is resulting in unbounded recursion. See link here that describes this: http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx
The link is saying that starting from .NET 2.0 you can't catch this type of exception with try-catch block and gives good reasons why not.
Related
Recently I was going through several small exercises in development. In one of them I was asked to convert a string to a number in VB .NET respecting the current locale. So I did :
Imports System
Public Module Aplicacion
Public Sub Main()
Console.WriteLine(Numero("Hello World"))
Console.WriteLine(Numero(2))
Console.WriteLine(Numero(.24))
Console.WriteLine(Numero(2.4))
End Sub
Function Numero(input as String) AS Double
Try
return Convert.ToDouble(input)
Catch Ex AS Exception
return 0
End Try
End Function
End Module
The teacher corrected this by telling me that "although it works, the right way is to declare a variable with the same type I am going to return, calculate its value in the body of the function and at the end return this variable".
Is there really any gain in doing that against doing it directly as I did?
Maybe some compilation bonus or an improvement in performance?
Function Numero(input As Object)
If input.GetType Is GetType(String) Then
Return 0
Else
Return input
End If
End Function
Sub Main()
Console.WriteLine(Numero("$$$$325FK-.,ASL$$$"))
Console.WriteLine(Numero(1))
Console.WriteLine(Numero(1.5))
Console.ReadKey()
End Sub
I am running a loop that evaluates input given by the user over more than 150k objects. The user sets the info to read like "obj.Name", "obj.Path", "obj.Date"... which may contain also logic evaluations such as "IIf(obj.Params>5,1,0)". It is then provided into the programm as a string.
I used the Evaluate() functions and it does work well, just that it is slow. It takes almost 6h to go over all elements. I was thinking if there is a way in which I can take the requested info and turn it into a straight-forward executable somehow, and avoid using the Evaluate expression in the whole loop (it runs for the number of requested data by the user * 150k).
This is a schematic of the loop I am running:
For Each Object in ObjectsList
For Each UserRequest in Requests
ResultsMatrix(i,j) = Evaluate(Requests(i))
j += 1
Next
i += 1
Next
I store then the results in a Matrix which is pasted in an Excel file at the end. Is there a way in which I can do sort of working the string to be evaluated into a function's return? I'd like to avoid usig the Eval function and parse directly the string in an executable and dont evaluate it for each object. Any tips on speeding up the loop?
It might be worth considering writing the requests into a set of functions and using the .NET CodeDom compilers to build it into a DLL. You can then load the assembly, find the right functions using reflection and put them into an array, then call them using reflection - that way you'll be calling .NET code and it should be far faster. Some (incomplete) code to get you started from a project where I have done this...
Private Function CombineCode() As String
Dim ret As New System.Text.StringBuilder
ret.AppendLine("Imports System")
ret.AppendLine("Imports Microsoft.VisualBasic")
ret.AppendLine()
ret.AppendLine("Namespace " & MainNamespace)
ret.AppendLine("Public Class " & MainClassName)
For Each e In _Entries
ret.AppendLine(e.Value.Code)
Next
ret.AppendLine("End Class")
ret.AppendLine("End Namespace")
Return ret.ToString
End Function
Private Function Compile(Code As String) As Assembly
'Dim d As New Dictionary(Of String, String)
'd.Add("langversion", "14")
Dim VBP As New Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider()
Dim PM As New System.CodeDom.Compiler.CompilerParameters
'PM.GenerateInMemory = True
PM.GenerateExecutable = False
PM.OutputAssembly = IO.Path.Combine(_Path, GenerateFileName() & ".dll") ' "Generated.dll"
PM.MainClass = MainClassName
PM.IncludeDebugInformation = True
Dim ASM As System.Reflection.Assembly
For Each ASM In AppDomain.CurrentDomain.GetAssemblies()
Try
If ASM.Location <> "" Then PM.ReferencedAssemblies.Add(ASM.Location)
Catch
End Try
Next
PM.ReferencedAssemblies.Add("System.Web.dll")
'Get compilation results
Dim Results As System.CodeDom.Compiler.CompilerResults
Results = VBP.CompileAssemblyFromSource(PM, Code)
'Show possible compilation errors
Dim Err As System.CodeDom.Compiler.CompilerError
For Each Err In Results.Errors
Throw New SyntaxErrorException("Error N. " & Err.ErrorNumber &
" Message: " & Err.ErrorText & " Line " & Err.Line & " in code " & vbCrLf & Code)
Next
Return Results.CompiledAssembly
End Function
Private Sub FindMethods()
Dim dt = (From t In _LatestAssembly.GetTypes() Where t.Name = MainClassName).Single
For Each e In _Entries.Values
e.Method = dt.GetMethod(e.MethodName)
Next
End Sub
Assembly = Assembly.LoadFrom(System.IO.Path.Combine(Path, sd.LatestAssemblyFile))
The Evaluate function is just resources on the computer itself. It's a great candidate for using Parallel.For.
In this case, j is the implied index.
For Each Object in ObjectsList
Parallel.For(0, Requests.Length, New ParallelOptions(), Sub(j, loopState)
ResultsMatrix(i,j) = Evaluate(Requests(j))
End Sub
)
i += 1
Next
Note, that Requests(i) is getting called repeatedly and produces the same result, so I assume you mean Requests(j).
I have a function where the intention is to return either a string to signify that the function has completed and retrieved the required value or an error to indicate there has been an issue.
To see whether I could do this, I bashed together the following:
Private Function one()
Debug.Print TypeName(two(False))
End Function
Private Function two(b As Boolean) As Variant
Dim e As New ErrObject
If (b) Then
two = True
Else
two = e.number
End If
End Function
Now, this fails at two = e.number because you don't appear to be able to set an error number in this way - the syntax is incorrect.
I could use err.raise but then the intention is to pass the whole error object back as I can then have a custom number and fill in my own description etc...
How do you actually pass the err object back? Can you actually do it and is this the most effective way in achieving what I am setting out to do?
Thanks
You don't. Err is a globally-scoped Function from the standard library VBA.Information module, that returns an ErrObject instance.
the intention is to pass the whole error object back as I can then have a custom number and fill in my own description
You don't need to pass the whole error object back to throw custom errors.
Const ERR_SomethingBad = vbObjectError + 42
Err.Raise ERR_SomethingBad, "MyModule.MyProcedure", "Uh-oh"
Err is already in global scope - you don't need to pass error objects around... and in fact, you simply can't. Because the ErrObject class isn't creatable. This:
Dim e As ErrObject
Set e = New ErrObject
Throws run-time error 429 "ActiveX can't create object".
The very idea behind errors (and exceptions, if you're any familiar with languages that feature exceptions), is that they replace the old archaic "return status code" way, e.g.:
''' DON'T DO THIS, IT's 2017!!!
Public Function DoSomething(ByVal p1 As Double, ByRef outResult As Double) As Long
If p1 = 0 Then
DoSomething = 11 'return code for division by zero error
Exit Function
End If
outResult = 42 / p1
DoSomething = 0 'return code for OK - everything went well!
End Function
With this pattern every procedure is a Function that returns an error code; the actual return value is passed as a ByRef / out parameter, and the caller would have to do this before they can trust the result:
Dim result As Double
Dim e As Long
e = DoSomething(42, result)
If e = 0 Then
' happy path
Else
MsgBox Error$(e) ' error path
End If
The On Error statement streamlines the code by taking most error-handling concerns out of the "happy path".
I have a question about life cycle for vb.net object
what's the difference about there two functions:
function 1:
Private Function MyF() As Integer
Using c As New cMyclass
If c.somework() = 1 Then Return 1
End Using
Return 0
End Function
function 2:
Private Function MyF() As Integer
Dim c As New myClass
If c.somework() = 1 Then Return 1
Return 0
End Function
what is the better solution?
The documentation gives you a really good explanation. Even with examples.
This
Using resource As New resourceType
' Insert code to work with resource.
End Using
Is the same as this
' For the acquisition and disposal of resource, the following
' Try construction is equivalent to the Using block.
Dim resource As New resourceType
Try
' Insert code to work with resource.
Finally
If resource IsNot Nothing Then
resource.Dispose()
End If
End Try
Disposing objects is something that always need to be done when possible.
I´m trying to utilize CUDAFy 1.29 in VB.NET using VS2013.
I´m trying to translate the samples of C# from CUDAFy and I´m having two type of errors, like explained below:
My Variables
Shared cs_CC As String = "adiciona"
Shared MyGPU As GPGPU = Nothing
Shared Arch As eArchitecture = Nothing
My Code:
Shared Executa()
if Loader = true
Dim Modulo = CudafyModule.TryDeserialize(cs_cc)
If IsNothing(Modulo) OrElse (Not Modulo.TryVerifyChecksums) Then
Modulo = CudafyTranslator.Cudafy(ePlatform.All, Arch, cs_CC.GetType)
Modulo.Serialize()
End If
MyGPU.Loadmodule(Modulo)
Dim a As Integer() = New Integer(N - 1) {}
Dim b As Integer() = New Integer(N - 1) {}
Dim c As Integer() = New Integer(N - 1) {}
' allocate the memory on the GPU
Dim dev_a As Integer() = MyGPU.Allocate(Of Integer)(a)
Dim dev_b As Integer() = MyGPU.Allocate(Of Integer)(b)
Dim dev_c As Integer() = MyGPU.Allocate(Of Integer)(c)
' fill the arrays 'a' and 'b' on the CPU
For i As Integer = 0 To N - 1
a(i) = i
b(i) = 2 * i
Next
' copy the arrays 'a' and 'b' to the GPU
MyGPU.CopyToDevice(a, dev_a)
MyGPU.CopyToDevice(b, dev_b)
For i As Integer = 0 To 128
MyGPU.Launch(1, 1).adiciona(dev_a, dev_b, dev_c)
Next
end if
End Sub
The function ADICIONA which would run on CUDA
<Cudafy()> _
Shared Sub adiciona(thread As GThread, a As Integer(), b As Integer(), c As Integer())
Dim tid As Integer = thread.blockIdx.x
While tid < N
c(tid) = a(tid) + b(tid)
tid += thread.gridDim.x
End While
End Sub
LOADER: try to identify card and CUDA (successfully running):
Public Shared Function Loader() As Boolean
DeviceType = eGPUType.Cuda
CudafyModes.Target = DeviceType
CudafyTranslator.Language = If(CudafyModes.Target = eGPUType.Cuda, eLanguage.Cuda, eLanguage.OpenCL)
Dim CompatibleDevice As GPGPUProperties() = CudafyHost.GetDeviceProperties(CudafyModes.Target, True).ToArray
If Not CompatibleDevice.Any Then ' não possui um full-CUDA device
MsgBox("I do not found any OpenCL or CUDA compatible device")
Return False
End If
Dim selectedDevice As GPGPUProperties = CompatibleDevice(0)
If IsNothing(selectedDevice) Then
MsgBox("I cannot allocate a compatible device")
Return False
End If
CudafyModes.DeviceId = selectedDevice.DeviceId
Thread_per_Block = selectedDevice.MaxThreadsPerBlock
Blocks_per_Grid = selectedDevice.MaxThreadsSize.x
Shared_Mem_per_Block = selectedDevice.SharedMemoryPerBlock
MyGPU = CudafyHost.GetDevice(CudafyModes.Target, CudafyModes.DeviceId)
Arch = MyGPU.GetArchitecture
Return True
End Function
The problems:
Problem 1: If I utilize just dim Modulo as CudafyModule = CudafyTranslator.Cudafy() I get the following error: Checked Statements are not supported. It´s weird! All documentation of Cudafy shows this line exactly as it!
Problem 2: So, I try to check the existence of a written module (.CDFY) and, if does not exist, I call the Serialize() function. The problem is the function creates a file called STRING.CDFY in my folder, but not the ADICIONA.CDFY nor ADD_LONG_LOOP.CDFY, which would be correct. Since I would like to avoid compilation at every run of this code, how to correctly make CUDAFy to write it?
Problem 3: When VS runs, everything goes OK until the point of calling ADICIONA (MyGPU.Launch)! VS stops the execution with a message "COULD NOT FIND FUNCTION 'ADICIONA' IN MODULE".
Interesting to notice that:
1- both temporary files are created (.CU, .PTX) and also the .CDFY file. It evidences the NVCC compiler is running well and creating the CUDA modules. So, why the code is NOT finding the function ADICIONA?
2- All samples written in C# run here 100%. And the conversion from C# and VB seems to be OK (I had utilized TELERIK to do it). I don´t guess the problem may be related to this, but I may be wrong.
3- The problem is NOT related to neither with NVCC compiler nor some reference into VB.NET, since the code compiles.
I tried to write in CODEPLEX for an answer. No answers at all...
I tried to see a lot of samples in Internet, but ALL OF THEM are created to CUDAFy C# and none of them are utilizing version 1.29 and CUDA 7.5.
Also, I would like to understand WHY the basic function (CudafyTranslator.Cudafy()) get an error in VB but not in C#.
So, does anyone here had successfully created a CUDAFy code using VB.NET?
Thank you VERY much for any help.
To solve Problem 1, check "Remove integer overflow checks" under Project Properties > Compile > Advanced Compile Options > Optimizations. More info: http://forums.asp.net/post/715302.aspx
Try this simple example:
Imports Cudafy
Imports Cudafy.Host
Imports Cudafy.Translator
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim GPU As GPGPU = CudafyHost.GetDevice(eGPUType.OpenCL, CudafyModes.DeviceId)
Dim Modulo As CudafyModule = CudafyTranslator.Cudafy(ePlatform.All, GPU.GetArchitecture())
GPU.LoadModule(Modulo)
Dim Resultado As Integer
Dim ResultadoGPU As Integer() = gpu.Allocate(Of Integer)()
GPU.Launch().Adicionar(2, 7, ResultadoGPU)
GPU.CopyFromDevice(ResultadoGPU, Resultado)
MessageBox.Show("2 + 7 = " & Resultado)
GPU.Launch().Subtrair(2, 7, ResultadoGPU)
GPU.CopyFromDevice(ResultadoGPU, Resultado)
MessageBox.Show("2 - 7 = " & Resultado)
GPU.Free(ResultadoGPU)
End Sub
<Cudafy()>
Private Shared Sub Adicionar(a As Integer, b As Integer, c As Integer())
c(0) = a + b
End Sub
<Cudafy()>
Private Shared Sub Subtrair(a As Integer, b As Integer, c As Integer())
c(0) = a - b
End Sub
End Class