When is it OK to use the GoTo statement in VB.Net? - vb.net

I have process that needs to create a bunch of records in the database and roll everything back if anything goes wrong. What I want to do is this:
Public Structure Result
Public Success as Boolean
Public Message as String
End Structure
Private _Repository as IEntityRepository
Public Function SaveOrganization( _
ByVal organization As rv_o_Organization) As Result
Dim result = Result.Empty
_Repository.Connection.Open()
_Repository.Transaction = _Repository.Connection.BeginTransaction()
''//Performs validation then saves it to the database
''// using the current transaction
result = SaveMasterOrganization(organization.MasterOrganization)
If (Not result.Success) Then
GoTo somethingBadHappenedButNotAnException
End If
''//Performs validation then saves it to the database
''//using the current transaction
result = SaveOrganziation(dbOrg, organization)
If (Not result.Success) Then GoTo somethingBadHappenedButNotAnException
somethingBadHappenedButNotAnException:
_Repository.Transaction.Commit()
_Repository.Connection.Close()
Return result
End Sub
Is this an ok use of the GoTo statement, or just really bad design? Is there a more elegant solution? Hopefully this sample is able to get the point across

If you have to ask, don't do it.
For your specific code, you could do it like this:
Public Function SaveOrganization(ByVal organization As rv_o_Organization) As Result
Dim result As Result = Result.Empty
_Repository.Connection.Open()
_Repository.Transaction = _Repository.Connection.BeginTransaction()
'Performs validation then saves it to the database
'using the current transaction
result = SaveMasterOrganization(organization.MasterOrganization)
'Performs validation then saves it to the database
'using the current transaction
If result.Success Then result = SaveOrganziation(dbOrg, organization)
_Repository.Transaction.Commit()
_Repository.Connection.Close()
Return result
End Sub

Goto has such a terrible reputation that it will cause other developers to instantly think poorly of your code. Even if you can demonstrate that using a goto was the best design choice - you'll have to explain it again and again to anyone who sees your code.
For the sake of your own reputation, just don't do it.

Really bad design. Yes.

There might be some extreme edge cases where it is applicable, but almost unequivocally, no, do not use it.
In this specific case, you should be using the Using statement to handle this in a better manner. Generally, you would create a class which would implement IDisposable (or use one that already does) and then handle cleanup in the Dispose method. In this case, you would close the connection to the database (apparently, it is reopened again from your design).
Also, I would suggest using the TransactionScope class here as well, you can use that to scope your transaction and then commit it, as well as auto-abort in the face of exceptions.

The only time you should use a goto, is when there is no other alternative.
The only way to find out if there are no other alternatives is to try them all.
In your particular example, you should use try...finally instead, like this (sorry, I only know C#)
void DoStuff()
{
Connection connection = new Connection();
try
{
connection.Open()
if( SomethingBadHappened )
return;
}
finally
{
connection.Close();
}
}

I would say extremely sparingly. Anytime I have had to think about using a GOTO statement, I try and refactor the code. The only exception I can think of was in vb with the statement On Error Goto.

There is nothing inherently wrong with goto, but this isn't a very ideal use of it. I think you are putting too fine a point on the definition of an exception.
Just throw a custom exception and put your rollback code in there. I would assume you would also want to rollback anyway if a REAL exception occured, so you get double duty out of it that way too.

Gotos are simply an implementation detail. A try/catch is much like a goto (an inter-stack goto at that!) A while loop (or any construct) can be written with gotos if you want. Break and early return statements are the most thinly disguised gotos of them all--they are blatant(and some people dislike them because of the similarity)
So technically there is nothing really WRONG with them, but they do make for more difficult code. When you use the looping structures, you are bound to the area of your braces. There is no wondering where you are actually going to, searching or criss-crossing.
On top of that, they have a REALLY BAD rep. If you do decide to use one, even in the best of possible cases, you'll have to defend your decision against everyone who ever reads your code--and many of those people you'll be defending against won't have the capability to make the judgment call themselves, so you're encouraging bad code all around.
One solution for your case might be to use the fact that an early return is the same as a goto (ps. Worst psuedocode ever):
dbMethod() {
start transaction
if(doWriteWorks())
end Transaction success
else
rollback transaction
}
doWriteWorks() {
validate crap
try Write crap
if Fail
return false
validate other crap
try Write other crap
if Fail
return false
return true
}
I think this pattern would work in VB, but I haven't used it since VB 3 (around the time MS bought it) so if transactions are somehow bound to the executing method context or something, then I dunno. I know MS tends to bind the database very closely to the structure of the code or else I wouldn't even consider the possibility of this not working...

I use goto's all the time in particular places, for example right above a Try Catch, in case a you prompt the user, "Retry?, Cancel", if retry then Goto StartMyTask: and increment the Current Try of Maximum retries depending on the scenario.
They're also handy in for each loops.
For each Items in MyList
If VaidationCheck1(Item) = false then goto SkipLine
If ValidationCheck(Item) = false then goto skipline
'Do some logic here, that can be avoided by skipping it to get better performance.
'I use then like short circuit operands, why evaluate more than you actually have to?
SkipLine:
Next
I wouldn't substitute them for functions and make really huge blocks of long code, just in little places where they can really help, mostly to skip over things.

Everytime I've seen a goto used, simple refactoring could have handle it. I'd reccomend never using it unless you "know" that you have to use it

I'm tempted to say never, but I suppose there is always one case where it may be the best solution. However, I've programmed for the last 20 years or so without using a Goto statement and can't foresee needing one any time soon.

Why not wrap each function call in a try catch block and when that is done, if one of your exceptions are thrown, you can catch it and close the connection. This way, you avoid the GOTO statement altogether.
In short, the GOTO statement is NOT a good thing, except in unusual situations, and even then it is usually a matter of refactoring to avoid it. Don't forget, it is a leftover from early languages, in this case BASIC.

I'd say use very sparingly as it's generally associated with introducing spagetti code. Try using methods instead of Labels.
A good case I think for using GOTO is to create a flow through select which is available in C# but not VB.

The go to statement has a tendency to make the program flow difficult to understand. I cannot remember using it during the last ten years, except in visual basic 6 in combination with "on error".
Your use of the go to is acceptable as far as I am concerned, because the program flow is very clear. I don't think using try ... catch would improve things much, because you would need to throw the exceptions on the locations where the go tos are now.
The formatting, however, is not very appealing:-)
I would change the name of the go to label to something else, because this location is also reached when everything is successful. clean_up: would be nice.

Eh, there was a decent use for it in VBscript/ASP for handling errors. We used it to return error handling back to ASP once we were done using on error resume next.
in .net? Heavens, no!

Everyone says avoid it but why.
The GOTO syntax is a jump statement in assembly - very efficient.
Main reason to avoid it is code readability. You need to find the GOTO label in the code which is hard to eyeball.
Some people think that it might cause memory leaks but I've seen that experts say that this is not true in .NET.

Related

SqlException Try-Catch with vb.net

I'm trying to wrap my head around Try-Catch statements in vb.net. I am trying to handle a SQL exception error that occurs, but I'm not sure what to do with it? The particular method that contains the code sample below is also expecting a return value.
Try
Dim records As DataRecordCollection = Sql Insert SP call
Catch sqlEx As SqlException
Select Case sqlEx.Number
Case 547
*****What goes here?*****
Case Else
Throw
End Select
End Try
You can put whatever you want there. We can't give you the answer to this question, because it could be anything. It could also be nothing; you don't have to put anything at all in that place, though it's usually poor practice to just swallow an exception like that.
The point is what you put there depends entirely on your application. You might make a log entry, or clean up the error to show something nicer to the user, or put other code there to recover or try again, or even all of the above. Whatever you want. But we can't know what you want to do. That's up to you and your design specification.
Also, you can simplify this code using a conditional exception:
Try
Dim records As DataRecordCollection = Sql Insert SP call
Catch sqlEx As SqlException When sqlEx.Number = 547
// Put whatever you want here
End Try
Finally, in my experience the best option is usually to skip the Try/Catch block at this level entirely.
If you have a well-designed application, your database access is abstracted away into it's own class, assembly, namespace, or some combination thereof, that is separate from the UI or Business layer. My experience is that handling these exceptions in the database code is not as helpful as allowing the exception to bubble up to a higher level of abstraction. You'll be better positioned to deal with it there. That's kind of what Try/Catch is all about... that exceptions can be caught at the level that is most appropriate to that kind of exception.
This is especially true when you don't even know what you want to do. If you don't have a plan to handle an exception, then don't handle it. Ditch the Try/Catch block and let the exception bubble up to a higher level where maybe someone else has a better strategy for it.
The Microsoft SQL server stores the error messages in the database so you can query it in your server:
select * from sys.messages where message_id = 427 and language_id = 1033
When I run it on my Sql Server 2016 Express, I got the following result:
Could not load the definition for constraint ID %d in database ID %d. Run DBCC CHECKCATALOG to verify the integrity of the database.
I suggest you to debug the error message not only the number and you will get some additional information about your problem. So please log the error message too, write that here and with that we will be able to help you.
Thank you,
Morzel

Fortran 90 Error: input requires too much data

I have the following code:
if (complex) then
read(unitvector) (CoefC(jl),jl=1,NV)
endif
Where a user indicates if the data is a collection of complex numbers. Now, if the user indicates that it is, but it actually isn't, i get error 67 (input requires too much data). How can i trap that, so i can write that perhaps a user made a mistake. I was thinking it would look something like:
read(unitvector, ioStat=iocplx) (CoefC(jl),jl=1,NV)
but where would i put the "if" to check for the error?
That depends on the overall logic of the program, we cannot tell you the best way for you from such small code snippet. You can try something like (not tested):
if (complex) then
read(unitvector, ioStat=iocplx) (CoefC(jl),jl=1,NV)
if (iocplx/=0) stop "Error reading the complex data."
end if
or
if (complex) then
read(unitvector, ioStat=iocplx) (CoefC(jl),jl=1,NV)
if (iocplx/=0) then
write(*,*) "Error reading the complex data, triung real."
complex = .false.
backspace(unitvector)
read(unitvector, ioStat=ioreal) (CoefR(jl),jl=1,NV)
if (ioreal/=0) then
stop "Error reading real data."
end if
end if
end if
But you really did not specify what you want, stop the program and write a meaningful message? Read data some other way? Everything is possible and we do not have a crystal ball.

VB.NET "Fixing" Code Clone

I'm working on refactoring a decently large project, and I'm interested in searching out and reducing Code Clone for better standardization as well as ease of development.
I've got a code snippet that keeps coming up in "Exact Matches" (using Visual Studio 2012's
"Find Code Clones" feature).
Here it is:
End If
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using
End Using
Return Nothing
Basically, I have a whole host of similar functions (similar in structure but not in actual function) that all open with something like this:
Const sql As String = ...
Using cn As SqlConnection...
Using cmd As SqlCommand(sql,cn)
... Maybe add some SqlParameters
cn.Open()
... Something with cmd.Execute...
Now, I recognize that the first code block is IDENTICAL across many, many methods, but I can't figure out a way to pull that code out, write it once and simply call it each time I need that functionality. It seems to me that there is too much control flow occurring.
So, I'm stumped as to how to fix this (and I'm only assuming that I can "fix" this because Microsoft has identified it as "cloned code").
I'm thinking of something along the lines of making a small number of functions that do the same type of thing (like returning a count from a table, returning a top value, etc...) and only really differ by the SQL that is executed. That could be a bit tricky, though, since sometimes the parameters (type and number) differ.
Any thoughts?
I wouldn't concern yourself with those. Your common-sense first impression is correct. While, technically speaking, the syntax is repeated multiple times, it is not really a repetition of logic or an algorithm of any kind. That's not to say there's no way to reduce that repetition, it's just that by doing so, you will likely end up with a worse design in your code.
For instance, you could create a single method that does all the setup and tear-down and then just calls a method in the middle that actually uses the connection to do the work, such as:
Public Function PerformDbTask(task As IMyDbTask)
Using cn As SqlConnection...
Using cmd As SqlCommand = cn.CreateCommand()
Try
cn.Open()
task.Perform(cmd)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using
End Using
Return Nothing
End Function
However, what have you really gained? Probably not much at all, yet you've lost a lot of flexibility. So, unless that kind of design is actually necessary for what you are trying to do, I wouldn't waste time trying to solve a problem that doesn't exist.
You could create a class that implements a builder pattern, that winds up looking like
Dim list =
SqlBuilder.Query("SELECT ...")
.WithConnection("...connection string...")
.WithParameter(userName)
.WithParameter(lastTrackId)
.RetrieveTopRows(10)
Your problem is you are using a clone detector that matches token sequences (thus it matches the end-of-block sequences you exhibited), as opposed to clone detectors that match code structures. While the token sequence is technically a clone, it isn't an interesting clone. Token clone detectors produce many many "false positive" clones like this, which simply waste your time.
It is easier to build token sequence detectors, which is why they built that into MS Studio.
If you want better detectors, you have to step outside of Studio.
You should look into clone detectors that match on abstract syntax trees. They don't produce this kind of false positive, and they can find clones with complex parameters (as opposed to single-token parameters).
You should also understand that just because something has been identified as a clone, that it is not always easy or possible to refactor it away. The language you have may not have sufficiently strong abstraction mechanisms to handle that case.

naming a function that exhibits "set if not equal" behavior

This might be an odd question, but I'm looking for a word to use in a function name. I'm normally good at coming up with succinct, meaningful function names, but this one has me stumped so I thought I'd appeal for help.
The function will take some desired state as an argument and compare it to the current state. If no change is needed, the function will exit normally without doing anything. Otherwise, the function will take some action to achieve the desired state.
For example, if wanted to make sure the front door was closed, i might say:
my_house.<something>_front_door('closed')
What word or term should use in place of the something? I'd like it to be short, readable, and minimize the astonishment factor.
A couple clarifying points...
I would want someone calling the function to intuitively know they didn't need to wrap the function an 'if' that checks the current state. For example, this would be bad:
if my_house.front_door_is_open():
my_house.<something>_front_door('closed')
Also, they should know that the function won't throw an exception if the desired state matches the current state. So this should never happen:
try:
my_house.<something>_front_door('closed')
except DoorWasAlreadyClosedException:
pass
Here are some options I've considered:
my_house.set_front_door('closed')
my_house.setne_front_door('closed') # ne=not equal, from the setne x86 instruction
my_house.ensure_front_door('closed')
my_house.configure_front_door('closed')
my_house.update_front_door('closed')
my_house.make_front_door('closed')
my_house.remediate_front_door('closed')
And I'm open to other forms, but most I've thought of don't improve readability. Such as...
my_house.ensure_front_door_is('closed')
my_house.conditionally_update_front_door('closed')
my_house.change_front_door_if_needed('closed')
Thanks for any input!
I would use "ensure" as its succinct, descriptive and to the point:
EnsureCustomerExists(CustomerID)
EnsureDoorState(DoorStates.Closed)
EnsureUserInterface(GUIStates.Disabled)
Interesting question!
From the info that you have supplied, it seems to me that setstate (or simply set, if you are setting other things than states) would be fine, though ensure is good if you want to really emphasize the redundancy of an if.
To me it is however perfectly intuitive that setting a state does not throw an exception, or require an if. Think of setting the state of any other variable:
In C:
int i;
i = 5; // Would you expect this to throw an exception if i was already 5?
// Would you write
if (i != 5)
i = 5;
// ?
Also it only takes about one sentence to document this behaviour:
The function does nothing if the
current state equals the requested
state.
EDIT: Actually, thinking about it, if it is really important to you (for some reason) that the user is not confused about this, I would in fact pick ensure (or some other non-standard name). Why? Because as a user, a name like that would make me scratch my head a bit and look up the documentation ("This is more than just an ordinary set-function, apparently").
EDIT 2: Only you know how you design your programs, and which function name fits in best. From what you are saying, it seems like your setting functions sometimes throw exceptions, and you need to name a setting function that doesn't - e.g. set_missile_target. If that is the case, I think you should consider the set_if, set_when, set_cond or cond_set names. Which one would kind of depend on the rest of your code. I would also add that one line of documentation (or two, if you're generous), which clarifies the whole thing.
For example:
// Sets missile target if current target is not already the requested target,
// in which case it does nothing. No exceptions are thrown.
function cond_set_missile_target ()
or function cond_set_MissileTarget ()
or function condSet_MissileTarget ()
or function condSetMissileTarget ()
ensure is not so bad, but to me it implies only that there is additional logic required to set the state (e.g. multiple states tied together, or other complications). It helps to make the user avoid adding unnecessary ifs, but it does not help much with the exception issue. I would expect an ensure function to throw an exception sooner than a set function, since the ensure function clearly has more responsibilities for, well, ensuring that this setting operation is in fact done right.
I'd go for ensure for the function you describe. I'd also use camelCase, but I suppose you may be in a language that prefers underscores.
You could always document (shock!) your API so that others don't make the mistakes you describe.

Using colons to put two statements on the same line in Visual Basic [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
Is it considered bad practice to use colons to put two statements on the same line in Visual Basic?
There is nothing inherently wrong with using the colon to combine statements. It really depends on the context but as long as it doesn't reduce readability, there is nothing wrong with it.
As a general rule I avoid using the colon for this purpose. I find it's more readable to have one statement per line. However this is not a colon specific issue. I avoid doing the same with a semi-colon in C# or C++. It's just a personal preference.
It's a good practice in moderation, because sometimes readability is enhanced by concatenating two lines:
when the lines are short and intimately
related
when the lines are short and trivial
Option Compare Database: Option Explicit ''My favorite!
rsDataSet.Close: Set rsDataSet= Nothing
Don't do it if:
it hurts readability.
it complicates debugging. Control structures such as If...Then need to stay clean. You'll be glad you kept it simple when it's time to set a break point.
it compromises future editing. Often you want to keep sections portable. Moving or re-structuring a block of code is easily hindered by attempts to minimize your code.
In general, I'd advise against it, as it makes for busier code.
However, for simple tasks, there is nothing wrong with it. For instance:
for i = 1 to 10: ProcessFoo(i): next
I think a line like this is short enough not to cause confusion.
I'll take the other side. I don't like dense lines of code. It is easier to skim code when lines are not combined.
Combining statements also makes it easier to create long functions that still fit on a single screen.
It isn't a major sin, I just don't like it.
I also don't like one line If statements.
To me you shouldn't say "never do thus", you should just say "If you do this, a possible problem is such and such." Then just weigh the pros and cons for yourself. The pro is brevity/few lines of code. Sometimes this can aid readability. For instance some people use it to do vb.Net declarations:
Dim x As Long: x = 1
Or wait loops:
Do Until IE.ReadyState = READYSTATE_COMPLETE: DoEvents: Loop
But obviously you can really make it rough on someone too:
Public Sub DoYouKnowWhatThisDoes()
MsgBox Example
End Sub
Private Function Example()
Const s$ = "078243185105164060193114247147243200250160004134202029132090174000215255134164128142"
Const w% = 3: Const l% = 42: Dim i%, r$: For i = 1 To l Step w: r = r & ChrW$(Mid$(s, i, w) Xor Mid$(s, i + l, w)): Next: Example = r
End Function
Another practical reason that you might not want to use this approach is breakpoints. Breakpoints can only be set by the line. So if you have several things executing on the same line you can't isolate the second thing. It will stop on the first statement. (This is also one of the reasons some people don't like single line ifs.) It just complicates debugging a little.
I usually don't use colons in production code for this reason. However I do use them to improve the brevity of "copy/paste" code that I post in forums and elsewhere. YMMV:)
I realize this is a very old question, but it was the first result on my Google search, so I hope I can be forgiven for chiming in here.
There is one situation (exactly what led me here in fact) in which this approach is not only useful, it's the only way to accomplish the desired result: the Immediate window. Any code you want to execute in the Immediate window must all be on one line. So in order to use any form of Do, Case, For, While, or With in the Immediate window, you will need to use colons.
It is considered bad practice in most of the sites at which I have worked. And by most of the VB developers with whom I have worked. And in my head. If I see it, I will admit that I would almost certainly change it. I say "almost" because I admit there's a possibility that I could find a piece of code that looked better that way. I don't expect to see it in my lifetime, though.
I also really don't like one-line **If**s either.
Both are most likely hangovers from the days of VGA (640x480) monitors; that's no excuse these days.
I've only ever used it when I'm clsoing a recordset and setting the variable to nothing. I figure one line instead of two gives me more lines of code on the screen and doesn't detract from readability.
I've seen it used in simple select cases such as the following but that would be as far as I would go.
Select Case success
Case ERROR_FILE_NO_ASSOCIATION: msg = "no association"
Case ERROR_FILE_NOT_FOUND: msg = "file not found"
Case ERROR_PATH_NOT_FOUND: msg = "path not found"
Case ERROR_BAD_FORMAT: msg = "bad format"
from http://vbnet.mvps.org/index.html?code/system/findexecutable.htm
And even then I would've lined up the "msg =" portion.
I've never seen this mentioned in an official capacity at any of the companies which I've worked. But I do think that using colons excessively can start to make your code less readable and more of a pain to maintain.
I do tend to use these myself at times, for example when checking for cancel in one of my recent projects:
If _bCancel Then Status = CancelProcess() : Return Status
Putting this in kept my code readable than the alternative IF block.
But it can be taken too far, I've recently inherited a project which is replete with examples of taking colon usage too far :
Select Case GetStringValue(Index).Trim.ToLower
Case "yes", "y" : GetBooleanValue = True
Case "no", "n" : GetBooleanValue = False
Case Else : GetBooleanValue = Nothing
End Select
Personally I find the above to be a bit much.
I like this one
Using pro As New Process() : With pro
...
End With
End Using
I've seen it used in class declarations when using inheritance or implementing an interface:
Public Class DerivedClass : Inherits BaseClass
...
End Class
But like the others, I also discourage its use.
Chris
The answer to the question is No. Anything beyond No is purely subjective and wasteful irrespective of the answer outside of a simple No. Below is my waste of typing.
Are you some sort of slave? Do as you wish. You are the center of your universe not some stranger from StackOverflow. If you work for a company the question is mute because coding style would already be defined and completely out of your control. As for one's self, who in this universe is going to ever in all eternity look at let along care about your code.
I would choose A over B. As evident this shows the purpose of a colon without the use of a colon. It's to save space. Below saves space and makes code far more readable. Keeps It Simple Stupid. Same for ternary ? : usage. When the code is inherently complex then a colon, single line if then else, or ternary no longer should be considered.
'================================================================
'A
If somevalue1 = 0 Then AddLogTry("True") Else AddLogFalse("False")
If somevalue2 = 0 Then AddLogTry("True") Else AddLogFalse("False")
If somevalue3 = 0 Then AddLogTry("True") Else AddLogFalse("False")
'================================================================
'================================================================
'B
If somevlaue1 = 0 Then
AddLogTrue("True")
Else
AddLogFalse("False")
EndIf
If somevlaue2 = 0 Then
AddLogTrue("True")
Else
AddLogFalse("False")
EndIf
If somevlaue3 = 0 Then
AddLogTrue("True")
Else
AddLogFalse("False")
EndIf
'================================================================