sandygad
asked on
A query pins me some time
Hello experts,
I have a question (may be confusion)
Text books says "Using GOTO statement is a bad programming Practice"
they added "U lost control over ur program by using it."
But practically we found that there is time when one has to use it.
On the top i am confused why its is bad to use ? how we lost control over code by using it ? and ok. if it is , then why
it is provided from QBasic to VB 6 .....may be in .Net.
(By the way I am a VB programmer)
Thanx
I have a question (may be confusion)
Text books says "Using GOTO statement is a bad programming Practice"
they added "U lost control over ur program by using it."
But practically we found that there is time when one has to use it.
On the top i am confused why its is bad to use ? how we lost control over code by using it ? and ok. if it is , then why
it is provided from QBasic to VB 6 .....may be in .Net.
(By the way I am a VB programmer)
Thanx
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
From what I understand the goto statement allowed (knowingly or otherwise) programmers to bypass code that could result in the application becomming unstable. For instance
Open a file
Read a value from the file
Is the file structure correct No then Goto Lable1
Close file
Exit
Lable1
Dispaly error
Exit
In this simple example the goto jumps over the close file leaving an orphaned resource.
This type of error can be easily avoided but in complex code using goto too many times could result in totally unmanageable code.
In our university courses we were taught "Use goto ONLY when you have to and then ONLY in a forward direction" in other words never use goto to jump to a previous point in the code.
That's my 2c worth - you will probably find a lot more info in the article listed by murugesandins above.
Open a file
Read a value from the file
Is the file structure correct No then Goto Lable1
Close file
Exit
Lable1
Dispaly error
Exit
In this simple example the goto jumps over the close file leaving an orphaned resource.
This type of error can be easily avoided but in complex code using goto too many times could result in totally unmanageable code.
In our university courses we were taught "Use goto ONLY when you have to and then ONLY in a forward direction" in other words never use goto to jump to a previous point in the code.
That's my 2c worth - you will probably find a lot more info in the article listed by murugesandins above.
The essential problem of 'goto' (and sometimes 'break', 'continue' etc) is for the future programmer.
Take the sample code above:
aStruct * aFunc( ... )
{
aStruct rtn = NULL;
char * mem = NULL;
FILE * fd = NULL;
int err = 0;
...
if (!(fd = fopen( ...))) goto abort;
...
if (!(rtn = (struct aStruct *))) goto abort;
...
if (!(mem = (char *)malloc(..))) goto abort;
...
/* success path */
return rtn;
abort:
if (fd) close(fd);
if (mem) free(mem);
if (rtn) free(rtn);
return NULL;
}
Imagine it is written and embedded in a program and stays there, stable and acceptable.
...
Now, a few years later, a novice programmer wishes to allocate another block of memory or open another file. Remember that the '...' can be many lines of code. It is not obvious, not even clear, what should be done if the allocation failed.
If, however, the code had been written:
aStruct * aFunc( ... )
{
aStruct rtn = NULL;
char * mem = NULL;
FILE * fd = NULL;
int err = 0;
...
if (fd = fopen( ...))
{
...
if (rtn = (struct aStruct *))
{
...
if (mem = (char *)malloc(..))
{
free(mem);
}
free(rtn);
}
close(fd);
}
...
/* success path */
return rtn;
}
then it is obvious what must be done!! In fact, almost any modification of the original code if fraught with danger.
Paul
Take the sample code above:
aStruct * aFunc( ... )
{
aStruct rtn = NULL;
char * mem = NULL;
FILE * fd = NULL;
int err = 0;
...
if (!(fd = fopen( ...))) goto abort;
...
if (!(rtn = (struct aStruct *))) goto abort;
...
if (!(mem = (char *)malloc(..))) goto abort;
...
/* success path */
return rtn;
abort:
if (fd) close(fd);
if (mem) free(mem);
if (rtn) free(rtn);
return NULL;
}
Imagine it is written and embedded in a program and stays there, stable and acceptable.
...
Now, a few years later, a novice programmer wishes to allocate another block of memory or open another file. Remember that the '...' can be many lines of code. It is not obvious, not even clear, what should be done if the allocation failed.
If, however, the code had been written:
aStruct * aFunc( ... )
{
aStruct rtn = NULL;
char * mem = NULL;
FILE * fd = NULL;
int err = 0;
...
if (fd = fopen( ...))
{
...
if (rtn = (struct aStruct *))
{
...
if (mem = (char *)malloc(..))
{
free(mem);
}
free(rtn);
}
close(fd);
}
...
/* success path */
return rtn;
}
then it is obvious what must be done!! In fact, almost any modification of the original code if fraught with danger.
Paul
In visual basic 6 you only should use goto with an on error clause. If goto is used in other context, the code it's dificultly to read and understand.
I hope i help you.
Bye, and sorry for my spell, i don't konw so much english.
Marcelo
Montevideo - Uruguay
I hope i help you.
Bye, and sorry for my spell, i don't konw so much english.
Marcelo
Montevideo - Uruguay
ASKER
Hi All
Thanks for your valuable comments.
I read them all & found more or less from each one.
Regards
Thanks for your valuable comments.
I read them all & found more or less from each one.
Regards
where we had to clean up resources (allocated memory, open files etc). The
typical code looked like this:
aStruct * aFunc( ... )
{
aStruct rtn = NULL;
char * mem = NULL;
FILE * fd = NULL;
int err = 0;
...
if (!(fd = fopen( ...))) goto abort;
...
if (!(rtn = (struct aStruct *))) goto abort;
...
if (!(mem = (char *)malloc(..))) goto abort;
...
/* success path */
return rtn;
abort:
if (fd) close(fd);
if (mem) free(mem);
if (rtn) free(rtn);
return NULL;
}
Of course the gotos could be avoided using deeply nested if-then-else constructs,
but the code became unmanagable as well as unreadable. The in-line alternative
cleanup:
if ((mem = (char *)malloc(...)) == NULL) {
fclose(fd); /* close the open file */
free(rtn); /* free our result obj */
return NULL;
}
is highly error-prone and clutters the flow with lots of redundant cleanup code -
obfuscating the true logic path with chunks of code that will hardly ever get
executed.