Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Error returns and repeated code, GOTOs, etc.

198 views
Skip to first unread message

mike3

unread,
May 30, 2012, 1:44:06 AM5/30/12
to
Hi.

I've got some stuff that looks like this:

---
ErrorCode MyFunc()
{
BigNum a, b, c, d;
ErrorCode rv;

rv = BigNum_Initialize(&a);
if(rv != ERROR_SUCCESS)
return(rv);

rv = BigNum_Initialize(&b);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&a); /* and what if THIS fails??? :) */
return(rv);
}

rv = BigNum_Initialize(&c);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}

rv = BigNum_Initialize(&d);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}

/* do some math */
rv = BigNum_Set(&b, 3);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&d);
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}

...

/* free buffers */
rv = BigNum_Free(&d);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}

rv = BigNum_Free(&c);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&b);
BigNum_Free(&a);
return(rv);
}

rv = BigNum_Free(&b);
if(rv != ERROR_SUCCESS)
{
BigNum_Free(&a);
return(rv);
}

rv = BigNum_Free(&a);
if(rv != ERROR_SUCCESS)
return(rv);

return(ERROR_SUCCESS);
}
---

But this is nasty, with all those duplicated "free" blocks. What can
be done to relieve this code duplication? It's ugly, it hurts my
freaking eyes and my nose is screaming for relief. And it hurts
maintainability to no end -- what if we decide to add more capability
to MyFunc() that requires additional bignums? Oy... We'd have to
update _all those blocks_.

I was thinking about using a "goto", but Gotos are Bad, aren't they? I
can't believe I may have to use a goto! What about Djikstra's famous
letter? Is it possible that perhaps a goto may be GOOD here? Because
with a goto this would all seem much simpler. If we violate Djikstra,
we get:

---

ErrorCode MyFunc()
{
BigNum a, b, c, d;
ErrorCode rv;

rv = BigNum_Initialize(&a); if(rv != ERROR_SUCCESS) goto
fail0;
rv = BigNum_Initialize(&b); if(rv != ERROR_SUCCESS) goto
fail1;
rv = BigNum_Initialize(&c); if(rv != ERROR_SUCCESS) goto
fail2;
rv = BigNum_Initialize(&d); if(rv != ERROR_SUCCESS) goto
fail3;

/* do some math */
rv = BigNum_Set(&b, 3); if(rv != ERROR_SUCCESS) goto fail4;

...

/* free buffers */
rv = BigNum_Free(&d); if(rv != ERROR_SUCCESS) goto fail3;
rv = BigNum_Free(&c); if(rv != ERROR_SUCCESS) goto fail2;
rv = BigNum_Free(&b); if(rv != ERROR_SUCCESS) goto fail1;
rv = BigNum_Free(&a); if(rv != ERROR_SUCCESS) goto fail0;

return(ERROR_SUCCESS);

fail4: BigNum_Free(&d);
fail3: BigNum_Free(&c);
fail2: BigNum_Free(&b);
fail1: BigNum_Free(&a);
fail0: return(rv);
}
---

But we've violated Djikstra and we've used a "bad" goto. How would
_you_ write MyFunc() above?

Ike Naar

unread,
May 30, 2012, 2:38:41 AM5/30/12
to
On 2012-05-30, mike3 <mike...@yahoo.com> wrote:
> Hi.
>
> I've got some stuff that looks like this:
>
> [stuff snipped]
>
> But this is nasty, with all those duplicated "free" blocks. What can
> be done to relieve this code duplication? It's ugly, it hurts my
> freaking eyes and my nose is screaming for relief. And it hurts
> maintainability to no end -- what if we decide to add more capability
> to MyFunc() that requires additional bignums? Oy... We'd have to
> update _all those blocks_.

ErrorCode MyFunc(void)
{
BigNum a;
ErrorCode rv = BigNum_Initialize(&a);
if (rv == ERROR_SUCCESS)
{
BigNum b;
rv = BigNum_Initialize(&b);
if (rv == ERROR_SUCCESS)
{
BigNum c;
rv = BigNum_Initialize(&c);
if (rv == ERROR_SUCCESS)
{
BigNum d;
rv = BigNum_Initialize(&d);
if (rv == ERROR_SUCCESS)
{
/* do some math */
rv = BigNum_Set(&b, 3);
if (rv == ERROR_SUCCESS)
{
/* ... */
}
BigNum_Free(&d);
}
BigNum_Free(&c);
}
BigNum_Free(&b);
}
BigNum_Free(&a);
}
return rv;
}

Nils M Holm

unread,
May 30, 2012, 2:57:25 AM5/30/12
to
mike3 <mike...@yahoo.com> wrote:
> But this is nasty, with all those duplicated "free" blocks. What can
> be done to relieve this code duplication? [...]

Add a garbage collector for BigNums.

--
Nils M Holm < n m h @ t 3 x . o r g > www.t3x.org

Malcolm McLean

unread,
May 30, 2012, 3:52:23 AM5/30/12
to
בתאריך יום רביעי, 30 במאי 2012 06:44:06 UTC+1, מאת mike3:
>
> But we've violated Djikstra and we've used a "bad" goto. How would
> _you_ write MyFunc() above?
>
I use gotos for handling memory allocation failures, but almost never for any other purpose.
--
Basic Algorithms - ANSI C source for fundamental programming operations.
http://www.malcolmmclean.site11.com/www

mike3

unread,
May 30, 2012, 4:50:55 AM5/30/12
to
On May 30, 1:52 am, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:
> בתאריך יום רביעי, 30 במאי 2012 06:44:06 UTC+1, מאת mike3:
>
> > But we've violated Djikstra and we've used a "bad" goto. How would
> > _you_ write MyFunc() above?
>
> I use gotos for handling memory allocation failures, but almost never for any other purpose.

So what would you do in the above circumstance?

MarkBluemel

unread,
May 30, 2012, 4:55:55 AM5/30/12
to
On 05/30/2012 06:44 AM, mike3 wrote:

> But we've violated Djikstra and we've used a "bad" goto. How would
> _you_ write MyFunc() above?

I personally don't like the infinitely indented if approach...

In C, I think it's probably OK to use goto for "exception handling".

If you have some way of indicating that a BigNum is uninitialised (e.g.
a BIGNUM_NULL macro) and you make BigNum_Free() set the BigNum to this
value, you could use something like this - goto-rich but less repetitive:-

ErrorCode MyFunc()
{
BigNum a = BIGNUM_NULL;
BigNum b = BIGNUM_NULL;
BigNum c = BIGNUM_NULL;
BigNum d = BIGNUM_NULL;
ErrorCode rv;

rv = BigNum_Initialize(&a);
if(rv != ERROR_SUCCESS)
goto failed;

rv = BigNum_Initialize(&b);
if(rv != ERROR_SUCCESS)
goto failed;

rv = BigNum_Initialize(&c);
if(rv != ERROR_SUCCESS)
goto failed;

rv = BigNum_Initialize(&d);
if(rv != ERROR_SUCCESS)
goto failed;

/* do some math */
rv = BigNum_Set(&b, 3);
if(rv != ERROR_SUCCESS)
goto failed;

...
/* free buffers */
rv = BigNum_Free(&d);
if(rv != ERROR_SUCCESS)
goto failed;

rv = BigNum_Free(&c);
if(rv != ERROR_SUCCESS)
goto failed;

rv = BigNum_Free(&b);
if(rv != ERROR_SUCCESS)
goto failed;

rv = BigNum_Free(&a);
if(rv != ERROR_SUCCESS)
goto failed;

return(ERROR_SUCCESS);

failed: /* we'll try and clean up, but won't care too much if it fails */
if (d != BIGNUM_NULL)
BigNum_Free(&d);
if (c != BIGNUM_NULL)
BigNum_Free(&c);
if (b != BIGNUM_NULL)
BigNum_Free(&b);
if (a != BIGNUM_NULL)
BigNum_Free(&a);

return(rv);
}

Willem

unread,
May 30, 2012, 5:18:54 AM5/30/12
to
MarkBluemel wrote:
) On 05/30/2012 06:44 AM, mike3 wrote:
)
)> But we've violated Djikstra and we've used a "bad" goto. How would
)> _you_ write MyFunc() above?
)
) I personally don't like the infinitely indented if approach...
)
) In C, I think it's probably OK to use goto for "exception handling".
)
) If you have some way of indicating that a BigNum is uninitialised (e.g.
) a BIGNUM_NULL macro) and you make BigNum_Free() set the BigNum to this
) value, you could use something like this - goto-rich but less repetitive:-

Rewritten to get rid of the gotos:

ErrorCode DoMath(BigNum a, BigNum b. BigNum c, BigNum d)
{
ErrorCode rv;
/* do some math */
rv = BigNum_Set(&b, 3);
if (rv != ERROR_SUCCESS) return rv;

...

return ERROR_SUCCESS;
}
ErrorCode MyFunc()
{
BigNum a = BIGNUM_NULL;
BigNum b = BIGNUM_NULL;
BigNum c = BIGNUM_NULL;
BigNum d = BIGNUM_NULL;
ErrorCode rv = ERROR_SUCCESS;

if (rv == ERROR_SUCCESS) rv = BigNum_Initialize(&a);
if (rv == ERROR_SUCCESS) rv = BigNum_Initialize(&b);
if (rv == ERROR_SUCCESS) rv = BigNum_Initialize(&c);
if (rv == ERROR_SUCCESS) rv = BigNum_Initialize(&d);

if (rv == ERROR_SUCCESS) rv = DoMath(a, b, c, d);

/* BigNum_Free should check for BIGNUM_NULL itself */
BigNum_Free(&d);
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);

return rv;
}

If you want to be more concise, you can make ERROR_SUCCESS equal 0,
and then you can simply do:

rv = BigNum_Initialize(&a) || ... || BigNum_Set(&b, 3) || BigNum_AddTo(&a, &b) || ... ;

Which will short-circuit at the first failure.

SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT

Ian Collins

unread,
May 30, 2012, 5:50:10 AM5/30/12
to
On 05/30/12 05:44 PM, mike3 wrote:
> Hi.
>
> I've got some stuff that looks like this:
>
> ---
> ErrorCode MyFunc()
> {
> BigNum a, b, c, d;
> ErrorCode rv;
>
> rv = BigNum_Initialize(&a);
> if(rv != ERROR_SUCCESS)
> return(rv);
>
> rv = BigNum_Initialize(&b);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&a); /* and what if THIS fails??? :) */
> return(rv);
> }

<snip lots more of the same>

I know I'm inviting flames, but this really is a classic case where C++
if you have access to it can be used as a better C....

--
Ian Collins

Malcolm McLean

unread,
May 30, 2012, 6:34:13 AM5/30/12
to
בתאריך יום רביעי, 30 במאי 2012 10:50:10 UTC+1, מאת Ian Collins:
> On 05/30/12 05:44 PM, mike3 wrote:
> > Hi.
> >
> > I've got some stuff that looks like this:
> >
> > ---
> > ErrorCode MyFunc()
> > {
> > BigNum a, b, c, d;
> > ErrorCode rv;
> >
> > rv = BigNum_Initialize(&a);
> > if(rv != ERROR_SUCCESS)
> > return(rv);
> >
> > rv = BigNum_Initialize(&b);
> > if(rv != ERROR_SUCCESS)
> > {
> > BigNum_Free(&a); /* and what if THIS fails??? :) */
> > return(rv);
> > }
>
> I know I'm inviting flames, but this really is a classic case where C++
> if you have access to it can be used as a better C....
>
You want

rv = BigNum_Initilaize(&a);
if(rv)
goto error_exit;
rv = BigNum_Add(&a, &b, &c);
if(!rv)
goto error_exit;

it's slightly messier than exceptions, but unlike exceptions it's easier to test and harder to abuse.
You don't want to be defining the symbol,ERROR_SUCCESS in a bignum.h header, and you don't want bignum.c dependent on myerrorcodes.h. However -1 for out of memory is pretty standard.


Ian Collins

unread,
May 30, 2012, 6:57:04 AM5/30/12
to
It's way uglier and no easier to test.

> You don't want to be defining the symbol,ERROR_SUCCESS in a bignum.h header, and you don't want bignum.c dependent on myerrorcodes.h. However -1 for out of memory is pretty standard.

I'm not sure what you are saying there.

--
Ian Collins

Willem

unread,
May 30, 2012, 7:04:48 AM5/30/12
to
Malcolm McLean wrote:
) You want
)
) rv = BigNum_Initilaize(&a);
) if(rv)
) goto error_exit;
) rv = BigNum_Add(&a, &b, &c);
) if(!rv)
) goto error_exit;

Why one positive and one negative test? Is that a typo?
Message has been deleted

nick_keigh...@hotmail.com

unread,
May 30, 2012, 7:53:56 AM5/30/12
to
On Wednesday, May 30, 2012 11:34:13 AM UTC+1, Malcolm McLean wrote:
> בתאריך יום רביעי, 30 במאי 2012 10:50:10 UTC+1, מאת Ian Collins:
> > On 05/30/12 05:44 PM, mike3 wrote:

> > > I've got some stuff that looks like this:
> > >
> > > ---
> > > ErrorCode MyFunc()
> > > {
> > > BigNum a, b, c, d;
> > > ErrorCode rv;
> > >
> > > rv = BigNum_Initialize(&a);
> > > if(rv != ERROR_SUCCESS)
> > > return(rv);
> > >
> > > rv = BigNum_Initialize(&b);
> > > if(rv != ERROR_SUCCESS)
> > > {
> > > BigNum_Free(&a); /* and what if THIS fails??? :) */
> > > return(rv);
> > > }
> >
> > I know I'm inviting flames, but this really is a classic case where C++
> > if you have access to it can be used as a better C....

I was tempted to say the same. Exceptiosn and RAII should be able to make it quite tidy.

> You want
>
> rv = BigNum_Initilaize(&a);
> if(rv)
> goto error_exit;
> rv = BigNum_Add(&a, &b, &c);
> if(!rv)
> goto error_exit;
>
> it's slightly messier than exceptions, but unlike exceptions it's easier to test and harder to abuse.

why?

> You don't want to be defining the symbol,ERROR_SUCCESS in a bignum.h header,

why? It's part of the Bignum interface.

> and you don't want bignum.c dependent on myerrorcodes.h.

ditto

> However -1 for out of memory is pretty standard.

I'd rather use a named constant... (I only recently found out this was a controversial opinion!)

Message has been deleted

tom st denis

unread,
May 30, 2012, 8:16:55 AM5/30/12
to
On May 30, 5:18 am, Willem <wil...@toad.stack.nl> wrote:
> If you want to be more concise, you can make ERROR_SUCCESS equal 0,
> and then you can simply do:
>
>     rv = BigNum_Initialize(&a) || ... || BigNum_Set(&b, 3) || BigNum_AddTo(&a, &b) || ... ;
>
> Which will short-circuit at the first failure.

Which in a sufficiently complicated function like an ECC point add/
double would result in spaghetti code and your termination. :-)

The "if (err == OK) ..." method is cool but frankly I just like the
goto's when I'm writing out something the long way.

Tom

BartC

unread,
May 30, 2012, 8:28:44 AM5/30/12
to
"mike3" <mike...@yahoo.com> wrote in message
news:7e54cf3c-d514-407b...@ra8g2000pbc.googlegroups.com...

> ErrorCode MyFunc()
> {
> BigNum a, b, c, d;
> ErrorCode rv;
>
> rv = BigNum_Initialize(&a);
> if(rv != ERROR_SUCCESS)
> return(rv);

<etc>

> But this is nasty, with all those duplicated "free" blocks. What can
> be done to relieve this code duplication? It's ugly, it hurts my
> freaking eyes and my nose is screaming for relief. And it hurts
> maintainability to no end -- what if we decide to add more capability
> to MyFunc() that requires additional bignums? Oy... We'd have to
> update _all those blocks_.

I think you've designed in too much error-checking, and made your bignums
unwieldy to initialise and manage.

Any code trying to actually do something with bignums would be lost amongst
all the error-checking and recovery. And if there was some conditional code,
and every single calculation needed checking, then you would easily lose
track of what needed freeing and what didn't.

Why does an initialisation need error-checking anyway? Does it involve
allocating memory?

It's not clear if a bignum is a pointer or a struct; they could be simply
initialised to NULL or to {0}, leaving it to the bignum arithmetic routines
to allocate as needed, and do the error-checking. Your code might still need
to free, but the free routine can leave alone bignums that are still NULL or
{0}.

Actually, for memory management, you should take seriously the idea put
forward of using garbage collection. Then you don't need to explicitly free
memory.

> ErrorCode MyFunc()
> {
> BigNum a, b, c, d;
> ErrorCode rv;
>
> rv = BigNum_Initialize(&a); if(rv != ERROR_SUCCESS) goto
> fail0;
> rv = BigNum_Initialize(&b); if(rv != ERROR_SUCCESS) goto
> fail1;
> rv = BigNum_Initialize(&c); if(rv != ERROR_SUCCESS) goto
> fail2;
> rv = BigNum_Initialize(&d); if(rv != ERROR_SUCCESS) goto
> fail3;

(As a personal preference, I would use something like BN_Init(). Then these
big names would dominate the code so much.)

And, whatever the initialisation does, is it really necessary to check the
result? Why not leave it to routines such as BigNum_Set() to validate it's
arguments; if an argument has not been properly initialised, then *it*
returns a failure code.

>
> /* do some math */
> rv = BigNum_Set(&b, 3); if(rv != ERROR_SUCCESS) goto fail4;
>
> ...
>
> /* free buffers */
> rv = BigNum_Free(&d); if(rv != ERROR_SUCCESS) goto fail3;

And what is likely to go wrong with BigNum_Free() that will need checking?
Will the caller of this function care, provided it gets the right answer? Or
is the result of BigNum_Set() likely to be invalidated if a subsequent free
fails?

> rv = BigNum_Free(&c); if(rv != ERROR_SUCCESS) goto fail2;
> rv = BigNum_Free(&b); if(rv != ERROR_SUCCESS) goto fail1;
> rv = BigNum_Free(&a); if(rv != ERROR_SUCCESS) goto fail0;
>
> return(ERROR_SUCCESS);
>
> fail4: BigNum_Free(&d);
> fail3: BigNum_Free(&c);
> fail2: BigNum_Free(&b);
> fail1: BigNum_Free(&a);
> fail0: return(rv);
> }

If you do need to do this, then just combine all the statuses of multiple
calls to BigNum_Free() (the error code needs to be of a format that will
allow | or & operations).

I know your post is about managing error recovery, rather than the merits of
a particular library. But, someone needing to do arithmetic via function
calls, might prefer to keep error-checking low-key, perhaps something like
this:

ErrorCode BigNum_Average(BigNum A, BigNum B, BigNum Result) {
BigNum Two=NULL;
ErrorCode e=0;

e |= BigNum_Add(A,B, Result);
e |= BigNum_Set(&Two, 2);
e |= BigNum_Div(Result, Two, Result);

e |= BigNum_Free(&Two);

return e;
}

Then it is still reasonably easy to follow what's going on. (Actually, I
wouldn't bother with the error codes myself; I would build a status into the
bignum itself, a bit like the Nans of floating point.)

--
Bartc

Message has been deleted
Message has been deleted
Message has been deleted

io_x

unread,
May 30, 2012, 9:19:26 AM5/30/12
to

"mike3" <mike...@yahoo.com> ha scritto nel messaggio
news:7e54cf3c-d514-407b...@ra8g2000pbc.googlegroups.com...
> Hi.
>
> I've got some stuff that looks like this:

this is my way...

ErrorCode MyFunc(void)
{BigNum a, b, c, d;
ErrorCode rv, rk;

if((rv=BigNum_Initialize(&a))!= ERROR_SUCCESS)
return rv;
if((rv = BigNum_Initialize(&b)) != ERROR_SUCCESS)
{ex1: BigNum_Free(&a); return rv;}
if((rv = BigNum_Initialize(&c)) != ERROR_SUCCESS)
{ex2: BigNum_Free(&b); goto ex1;}
if((rv = BigNum_Initialize(&d)) != ERROR_SUCCESS)
{ex3: BigNum_Free(&c); goto ex2;}
if((rv = BigNum_Set(&b, 3)) != ERROR_SUCCESS)
{ex4: BigNum_Free(&d); goto ex3;}
...
/* free buffers */
rv=ERROR_SUCCESS;
if((rk=BigNum_Free(&d))!=ERROR_SUCCESS) rv=rk;
if((rk=BigNum_Free(&c))!=ERROR_SUCCESS) rv=rk;
if((rk=BigNum_Free(&b))!=ERROR_SUCCESS) rv=rk;
if((rk=BigNum_Free(&a))!=ERROR_SUCCESS) rv=rk;
return rv;
if above fail you not free c, b and a...

Ike Naar

unread,
May 30, 2012, 9:56:45 AM5/30/12
to
On 2012-05-30, mike3 <mike...@yahoo.com> wrote:
> I was thinking about using a "goto", but Gotos are Bad, aren't they? I
> can't believe I may have to use a goto! What about Djikstra's famous
> letter? Is it possible that perhaps a goto may be GOOD here? Because
> with a goto this would all seem much simpler. If we violate Djikstra,
> we get:

The name is Dijkstra, not Djikstra.

ImpalerCore

unread,
May 30, 2012, 10:13:11 AM5/30/12
to
rv = rv == ERROR_SUCCESS ? BigNum_Initialize(&b) : rv;
rv = rv == ERROR_SUCCESS ? BigNum_Initialize(&c) : rv;
rv = rv == ERROR_SUCCESS ? BigNum_Initialize(&d) : rv;

if (rv != ERROR_SUCCESS)
{
BigNum_Free(&d);
BigNum_Free(&c);
BigNum_Free(&b);
BigNum_Free(&a);
}

return(rv);
}
\endcode

The main issue with this style is that it assumes that BigNum_Free
operates like 'free' where a NULL pointer is a no-op. If you can
initialize your BigNum variables to a corresponding "NULL" BigNum
state, and BigNum_Free interprets a "NULL" BigNum as a no-op, you can
duplicate this style. You may need to add a distinct struct
initializer to your variable declarations if BigNum is not a pointer.

\code
/* Define an initialize macro to create a "NULL" BigNum */
#define BIGNUM_NULL_INIT { 0, NULL, ... }

BigNum a = BIGNUM_NULL_INIT;
BigNum b = BIGNUM_NULL_INIT;
BigNum c = BIGNUM_NULL_INIT;
BigNum d = BIGNUM_NULL_INIT;
\endcode

On a side note, the term ERROR_SUCCESS appears contradictory to me. I
would prefer something like NO_ERROR or SUCCESS if you had control
over the error definitions.

Best regards,
John D.

nick_keigh...@hotmail.com

unread,
May 30, 2012, 10:25:58 AM5/30/12
to mark_b...@pobox.com
On Wednesday, May 30, 2012 9:55:55 AM UTC+1, MarkBluemel wrote:
> On 05/30/2012 06:44 AM, mike3 wrote:
>
> > But we've violated Djikstra and we've used a "bad" goto. How would
> > _you_ write MyFunc() above?
>
> I personally don't like the infinitely indented if approach...

nor me. Even goto is cleaner.


Ben Bacarisse

unread,
May 30, 2012, 11:37:42 AM5/30/12
to
mike3 <mike...@yahoo.com> writes:

> I've got some stuff that looks like this:
<snip code>

Just because no one has yet used an array:

ErrorCode MyFunc(void)
{
enum { a, b, c, d, n_big_nums };
BigNum num[n_big_nums];
ErrorCode rv;

int n = 0;
while (n < n_big_nums && BigNum_Initialize(&num[n]) == ERROR_SUCCESS)
n++;

if (n == n_big_nums)
do {
/* do some math */
rv = BigNum_Set(&num[b], 3);
if (rv != ERROR_SUCCESS)
break;
/* ... */
} while (0);

while (n--)
BigNum_Free(&num[n]);
return rv;
}

You don't have to use the do { ... } while (0); thing. Just add a label
to the end loop and goto it instead of using break.

You have to switch a, b and so on to num[a], num[b] but it does extend
easily if you find you need another BigNum.

(Note that "ErrorCode MyFunc(void)" is a prototype whereas "ErrorCode
MyFunc()" is not.)

<snip>
--
Ben.

Willem

unread,
May 30, 2012, 12:26:47 PM5/30/12
to
tom st denis wrote:
) On May 30, 5:18?am, Willem <wil...@toad.stack.nl> wrote:
)> If you want to be more concise, you can make ERROR_SUCCESS equal 0,
)> and then you can simply do:
)>
)> ? ? rv = BigNum_Initialize(&a) || ... || BigNum_Set(&b, 3) || BigNum_AddTo(&a, &b) || ... ;
)>
)> Which will short-circuit at the first failure.
)
) Which in a sufficiently complicated function like an ECC point add/
) double would result in spaghetti code and your termination. :-)

How can it be spaghetti when it's a single line of calls, one after
the other? Spaghetti code is meant to be tangled, isn't it?

) The "if (err == OK) ..." method is cool but frankly I just like the
) goto's when I'm writing out something the long way.

I've seen the (err == OK) method used too much in code that didn't require
cleanup at end of function. Apparently somebody at our company believes in
'one-function-one-return' religiously. I agree gotos are better.


Another method is to have all 'bignum' functions check for 'error' inputs
and generate 'error' outputs when they encounter them (or whenever they
encounter an error), and then you only have to check for an 'error'
result at the very end.

Something like:

int DoCalc()
{
int rv;
BigNum a;
BigNum b;
BigNum c;
BigNum d;

BigNum_Init(&a);
BigNum_Init(&b);
BigNum_Init(&c);
BigNum_Init(&d);

BigNum_Set(&a, 3);
BigNum_Set(&b, 5);
...
BigNum_Multiply(&c, &d);
...
if ((rv = BigNum_GetError(&d)) != ERROR_SUCCESS) return rv;

BigNum_Print("The result is: %bn", &d);
BigNum_Free(&a);
BigNum_Free(&b);
BigNum_Free(&c);
BigNum_Free(&d);

return ERROR_SUCCESS;
}

The only weirdside to this is when a value is not used in the final result,
then that value will not be checked for errors.

Johann Klammer

unread,
May 30, 2012, 1:05:41 PM5/30/12
to
mike3 wrote:
[...]
> But we've violated Djikstra and we've used a "bad" goto. How would
> _you_ write MyFunc() above?

Hello,

If you want to get rid of the gotos and the ifs, you might end up using
some kind of object stack. Every time you create or initialize
something, you push a handle and a destructor onto the stack. If
something goes wrong, you work your way down the stack destroying all
the resources. A bit like pthread_cleanup_push/pop. Of course it is
kludgy, may involve unsafe casts and a bit of additional overhead. I do
not use it much myself.

There is an implementation here:
http://members.aon.at/~aklamme4/dvbv/dvbvulture_1.0.23.tar.gz
In the files common/custck.c include/custck.h

(please ignore the code smell)

JK

Kulin

unread,
May 30, 2012, 1:29:01 PM5/30/12
to
The name is Dumbsonofabitch, not Dijkstra. And he's dead. Good riddance!



mike3

unread,
May 30, 2012, 4:57:35 PM5/30/12
to
On May 30, 6:28 am, "BartC" <b...@freeuk.com> wrote:
> "mike3" <mike4...@yahoo.com> wrote in message
<snip>
> I think you've designed in too much error-checking, and made your bignums
> unwieldy to initialise and manage.
>
> Any code trying to actually do something with bignums would be lost amongst
> all the error-checking and recovery. And if there was some conditional code,
> and every single calculation needed checking, then you would easily lose
> track of what needed freeing and what didn't.
>
> Why does an initialisation need error-checking anyway? Does it involve
> allocating memory?
>

Yes. You have to allocate memory to initialize (for the buffer holding
the
bignum's digits.). And that can fail. Thus, I return an error code.
What do you do with that failure code? :) See, you still need a
handler around
every math routine call. This would help with the Init() functions'
handlers, though.

>
>
> >          /* do some math */
> >          rv = BigNum_Set(&b, 3); if(rv != ERROR_SUCCESS) goto fail4;
>
> >          ...
>
> >          /* free buffers */
> >          rv = BigNum_Free(&d); if(rv != ERROR_SUCCESS) goto fail3;
>
> And what is likely to go wrong with BigNum_Free() that will need checking?
> Will the caller of this function care, provided it gets the right answer? Or
> is the result of BigNum_Set() likely to be invalidated if a subsequent free
> fails?
>

Looking at the free function, it can return one error code:
ERROR_INVALID_STORAGE_TYPE. A bignum can be stored on either
memory or on disk (disk not yet implemented, but the stuff is there to
allow
for its implementation). There is, of course, a field in the bignum
that indicates
which is being used. If this is something weird -- something other
than
"memory" or "disk", then the "Free" function would get confused as it
wouldn't know how to properly free the bignum. Normally, that
shouldn't
happen. But if someone was doing something silly, the catch is there
to catch that. So, should I just remove that error return and say,
"well,
if you're messing around with this in some improper fashion, then
expect things to break"? But then we run into the problem of where
the field is corrupted due to a memory bug. In this case, a fail could
be useful (although one of the other bignum routines could puke as
well.).

An idea I had is to drop the type field altogether and use
something like this:

typedef struct BigNum {
...
Digit *RAMBuffer;
FILE *DiskBuffer;
...
} BigNum;

and when BigNum is initialized to RAM storage, RAMBuffer holds a ptr,
and DiskBuffer is NULL, and when BigNum is initialized to Disk
storage,
RAMBuffer is NULL, and DiskBuffer holds a ptr. Then there's no field
that
can get an invalid value, and if someone tries to set the NULL ptrs
to something else, then expect things to break. (If a ptr gets
corrupted,
you're pretty screwed anyway and there isn't much you can do about it)

> >          rv = BigNum_Free(&c); if(rv != ERROR_SUCCESS) goto fail2;
> >          rv = BigNum_Free(&b); if(rv != ERROR_SUCCESS) goto fail1;
> >          rv = BigNum_Free(&a); if(rv != ERROR_SUCCESS) goto fail0;
>
> >          return(ERROR_SUCCESS);
>
> > fail4:    BigNum_Free(&d);
> > fail3:    BigNum_Free(&c);
> > fail2:    BigNum_Free(&b);
> > fail1:    BigNum_Free(&a);
> > fail0:    return(rv);
> > }
>
> If you do need to do this, then just combine all the statuses of multiple
> calls to BigNum_Free() (the error code needs to be of a format that will
> allow | or & operations).
>

The thing here is, that I have a general "universal" list of error
codes, numbered
0 (= success), 1, 2, 3, etc. and functions take their return codes
from that.
Perhaps that's not the best way to do it? (I was inspired by
Microsoft's Windows
system with all its error codes.) E.g. we could use for the bignum
routines
a special set of 32-bit (or even 64-bit, in this case -- this program
is for 64-bit
systems anyway) error codes with at most 32 possible errors (probably
way more than'd be needed from a simple bignum routine!) error codes
that
indicate errors by bit flags (all zeroes = success), and could be ORed
together
to get what errors occurred in the code under consideration.

> I know your post is about managing error recovery, rather than the merits of
> a particular library. But, someone needing to do arithmetic via function
> calls, might prefer to keep error-checking low-key, perhaps something like
> this:
>
> ErrorCode BigNum_Average(BigNum A, BigNum B, BigNum Result) {
> BigNum Two=NULL;
> ErrorCode e=0;
>
>  e |= BigNum_Add(A,B, Result);
>  e |= BigNum_Set(&Two, 2);
>  e |= BigNum_Div(Result, Two, Result);
>
>  e |= BigNum_Free(&Two);
>
>  return e;
>
> }
>
> Then it is still reasonably easy to follow what's going on. (Actually, I
> wouldn't bother with the error codes myself; I would build a status into the
> bignum itself, a bit like the Nans of floating point.)
>

Yes, a "NAN" or error flag is another possibility. Flag would be best
-- it's
real easy to check and you could set multiple values -- like 1 for bad
alloc,
2 for overflow, etc.

Mark Bluemel

unread,
May 31, 2012, 4:10:14 AM5/31/12
to
On May 30, 2:19 pm, "io_x" <a...@b.c.invalid> wrote:

> this is my way...

Why does this not surprise me?

> ErrorCode MyFunc(void)
> {BigNum a, b, c, d;
>  ErrorCode  rv, rk;
>
>  if((rv=BigNum_Initialize(&a))!= ERROR_SUCCESS)
>                              return  rv;
>  if((rv = BigNum_Initialize(&b)) != ERROR_SUCCESS)
>     {ex1:   BigNum_Free(&a); return  rv;}
>  if((rv = BigNum_Initialize(&c)) != ERROR_SUCCESS)
>     {ex2:   BigNum_Free(&b); goto   ex1;}
>  if((rv = BigNum_Initialize(&d)) != ERROR_SUCCESS)
>     {ex3:   BigNum_Free(&c); goto   ex2;}
>  if((rv = BigNum_Set(&b, 3))     != ERROR_SUCCESS)
>     {ex4:   BigNum_Free(&d); goto   ex3;}

Ouch!

Tim Rentsch

unread,
May 31, 2012, 4:19:00 PM5/31/12
to
mike3 <mike...@yahoo.com> writes:

> I've got some stuff that looks like this:
>
> ---
> ErrorCode MyFunc()
> {
> BigNum a, b, c, d;
> ErrorCode rv;
>
> rv = BigNum_Initialize(&a);
> if(rv != ERROR_SUCCESS)
> return(rv);
>
> rv = BigNum_Initialize(&b);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&a); /* and what if THIS fails??? :) */
> return(rv);
> }
>
> rv = BigNum_Initialize(&c);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&b);
> BigNum_Free(&a);
> return(rv);
> }
>
> rv = BigNum_Initialize(&d);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&c);
> BigNum_Free(&b);
> BigNum_Free(&a);
> return(rv);
> }
>
> /* do some math */
> rv = BigNum_Set(&b, 3);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&d);
> BigNum_Free(&c);
> BigNum_Free(&b);
> BigNum_Free(&a);
> return(rv);
> }
>
> ...
>
> /* free buffers */
> rv = BigNum_Free(&d);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&c);
> BigNum_Free(&b);
> BigNum_Free(&a);
> return(rv);
> }
>
> rv = BigNum_Free(&c);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&b);
> BigNum_Free(&a);
> return(rv);
> }
>
> rv = BigNum_Free(&b);
> if(rv != ERROR_SUCCESS)
> {
> BigNum_Free(&a);
> return(rv);
> }
>
> rv = BigNum_Free(&a);
> if(rv != ERROR_SUCCESS)
> return(rv);
>
> return(ERROR_SUCCESS);
> }
> ---
>
> But this is nasty, with all those duplicated "free" blocks. What can
> be done to relieve this code duplication? It's ugly, it hurts my
> freaking eyes and my nose is screaming for relief. And it hurts
> maintainability to no end -- what if we decide to add more capability
> to MyFunc() that requires additional bignums? Oy... We'd have to
> update _all those blocks_.
>
> I was thinking about using a "goto", but Gotos are Bad, aren't they? I
> can't believe I may have to use a goto! What about Djikstra's famous
> letter? Is it possible that perhaps a goto may be GOOD here? Because
> with a goto this would all seem much simpler. If we violate Djikstra,
> we get:
>
> ---
>
> ErrorCode MyFunc()
> {
> BigNum a, b, c, d;
> ErrorCode rv;
>
> rv = BigNum_Initialize(&a); if(rv != ERROR_SUCCESS) goto
> fail0;
> rv = BigNum_Initialize(&b); if(rv != ERROR_SUCCESS) goto
> fail1;
> rv = BigNum_Initialize(&c); if(rv != ERROR_SUCCESS) goto
> fail2;
> rv = BigNum_Initialize(&d); if(rv != ERROR_SUCCESS) goto
> fail3;
>
> /* do some math */
> rv = BigNum_Set(&b, 3); if(rv != ERROR_SUCCESS) goto fail4;
>
> ...
>
> /* free buffers */
> rv = BigNum_Free(&d); if(rv != ERROR_SUCCESS) goto fail3;
> rv = BigNum_Free(&c); if(rv != ERROR_SUCCESS) goto fail2;
> rv = BigNum_Free(&b); if(rv != ERROR_SUCCESS) goto fail1;
> rv = BigNum_Free(&a); if(rv != ERROR_SUCCESS) goto fail0;
>
> return(ERROR_SUCCESS);
>
> fail4: BigNum_Free(&d);
> fail3: BigNum_Free(&c);
> fail2: BigNum_Free(&b);
> fail1: BigNum_Free(&a);
> fail0: return(rv);
> }
> ---
>
> But we've violated Djikstra and we've used a "bad" goto. How would
> _you_ write MyFunc() above?

Your question is really about style. As is usually the case in
such matters, there are no right or wrong answers, just individual
preference, and perhaps local culture that should also be taken
into account.

That said, when a question like this comes up, usually it's a
strong indication that the program design is wrong at some
higher level. If you find yourself writing lots of ugly
functions, there's a good chance it will be worth rethinking
some higher-level decisions and see if a different approach
leads to cleaner code at the function level.

mike3

unread,
May 31, 2012, 4:49:08 PM5/31/12
to
On May 31, 2:19 pm, Tim Rentsch <t...@alumni.caltech.edu> wrote:
So what would the "bad design" be in this case? There doesn't
seem to be a whole lot of things that could be changed. A bignum
system will have init, free, and arithmetic routines. Trouble
seems to be due to the possibility of return codes on every
bignum operation. Is this the "design problem"? Notice that
something like, say, GMP, doesn't do that. All GMP functions
return void or an arithmetic result, not an error code. But I *do*
want to have some sort of error reporting functionality.

BartC

unread,
May 31, 2012, 5:08:02 PM5/31/12
to
"mike3" <mike...@yahoo.com> wrote in message
news:58595afa-412f-4ef0...@s6g2000pbi.googlegroups.com...
Sounds like it.

But whatever you end up doing, perhaps consider the possibility of having a
second set of functions that shadow the main ones (and which could wrap the
main functions).

These secondary functions take care of error-checking. Then the programmer
can do more productive work without worrying about errors 90% of the time.

Of course it depends on what sort of errors are likely; if they are rare,
and an abort (or one of those longjmps) is acceptable when there is a
problem, then this can be workable. But it is also up to the programmer
which set of functions to call.

It depends also how the code that uses this library fits into the overall
program; if this is just servicing something bigger, such as a language
runtime, then you don't want minor numeric problems to bring down the
system.

In any case, ignoring checking an errorcode shouldn't bring down the system
either; but this could need *more* checking inside the library itself (which
you may or may not have access to).

--
Bartc

mike3

unread,
May 31, 2012, 7:08:46 PM5/31/12
to
On May 31, 3:08 pm, "BartC" <b...@freeuk.com> wrote:
> "mike3" <mike4...@yahoo.com> wrote in message
However, some of these errors can't simply be ignored, like an "out of
memory"
error or "out of disk space" error. And it would also be a nice
feature to know
if something has gone wrong with the computation.

mike3

unread,
May 31, 2012, 7:39:28 PM5/31/12
to
On May 29, 11:44 pm, mike3 <mike4...@yahoo.com> wrote:
<snip>

I've made an interesting and disturbing discovery.

I found THIS:

http://www.isc.org/software/bind/991

I decided to have a look at the source code, and oh my goodness! What
did I find?!
Oh NO....!!!!!!!!!!!!!!!!!!!!!!! :

----

idn_result_t
idn_normalizer_add(idn_normalizer_t ctx, const char *scheme_name) {
idn_result_t r;
void *v;
normalize_scheme_t *scheme;

assert(ctx != NULL && scheme_name != NULL);

TRACE(("idn_normalizer_add(scheme_name=%s)\n", scheme_name));

assert(INITIALIZED);

if (idn__strhash_get(scheme_hash, scheme_name, &v) != idn_success) {
ERROR(("idn_normalizer_add(): invalid scheme \"%-.30s\"\n",
scheme_name));
r = idn_invalid_name;
goto ret;
<----------------- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}

scheme = v;

assert(ctx->nschemes <= ctx->scheme_size);

if (ctx->nschemes == ctx->scheme_size &&
(r = expand_schemes(ctx)) != idn_success) {
goto ret;
<----------------- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}

ctx->schemes[ctx->nschemes++] = scheme;
r = idn_success;
ret:
<----------------- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
TRACE(("idn_normalizer_add(): %s\n", idn_result_tostring(r)));
return (r);
}

----

YES, that's right -- those are GOTOs in there, and they do this a LOT
in this program! Djikstra!!!

But as this thread seems to show, it looks like that there exist
alternatives
to GOTO, and so we can still uphold Djikstra's law. Or is there
something
about this program that makes it OK to use GOTOs in it, but it is not
OK
to use them in the one I'm doing?

mike3

unread,
May 31, 2012, 7:46:40 PM5/31/12
to
On May 29, 11:44 pm, mike3 <mike4...@yahoo.com> wrote:
<snip>

I've also noticed another problem. I've got a place where a
routine needs to _return_ a BigNum it mints inside itself.

ErrorCode MyFunc(BigNum **OutputValue)
{
...
*OutputValue = (BigNum *)malloc(sizeof(BigNum));
if(*OutputValue == NULL)
{
<duplicated err handler>
}

rv = BigNum_Initialize(*OutputValue);
if(rv != ERROR_SUCCESS)
{
<ditto>
}

...
(error handlers in here that now have to _free the alloced
memory
and not just deinit the BigNum_! What should I do about
this?)
...
}

What to do?

Tim Rentsch

unread,
May 31, 2012, 8:34:30 PM5/31/12
to
mike3 <mike...@yahoo.com> writes:

> On May 31, 2:19 pm, Tim Rentsch <t...@alumni.caltech.edu> wrote:
>> mike3 <mike4...@yahoo.com> writes:
>> [snip]
>>
>> Your question is really about style. As is usually the case in
>> such matters, there are no right or wrong answers, just individual
>> preference, and perhaps local culture that should also be taken
>> into account.
>>
>> That said, when a question like this comes up, usually it's a
>> strong indication that the program design is wrong at some
>> higher level. If you find yourself writing lots of ugly
>> functions, there's a good chance it will be worth rethinking
>> some higher-level decisions and see if a different approach
>> leads to cleaner code at the function level.
>
> So what would the "bad design" be in this case?

To answer that question one would need both more specific information
and more context. The example you gave was fairly limited and also
rather abstract. Not saying there is anything wrong with that, there
isn't, but it doesn't provide enough information to answer the
followup question.

> There doesn't seem to be a whole lot of things that could be
> changed. [snip elaboration]

Undoubtedly there are lots of things that can't be changed, but
unless the situation is very different from what I would expect there
still are lots of design choices available. Maybe you have locked in
on some unconscious assumptions? I'm sorry I don't have a better
answer for you, but the question you're asking now is much larger
than the original topic.

Ben Bacarisse

unread,
May 31, 2012, 10:21:12 PM5/31/12
to
It's Dijkstra, OK? Dijkstra.

The above is a terrible example. It looks like programming by numbers:
"I've been told to trace entry and exit so I'll stick a label at the end
and replace returns with gotos". I think it's clearer without them,
although there is some justification if my guess is right -- it might
have been a ploy to minimise re-writing.

> But as this thread seems to show, it looks like that there exist
> alternatives to GOTO, and so we can still uphold Djikstra's law.

It's not a law. The famous article is a well-argued case. Do read it
if you haven't.

> Or is there something about this program that makes it OK to use GOTOs
> in it, but it is not OK to use them in the one I'm doing?

I don't know the program, but this function does not benefit from having
gotos. There are cases where a goto really helps, but they are far
fewer than some people think.

--
Ben.

Ian Collins

unread,
May 31, 2012, 11:55:38 PM5/31/12
to
Use C++!

You appear to be using C++ already given your remarkably similar flame
bait thread over on c.l.c++.

--
Ian Collins

Willem

unread,
Jun 1, 2012, 3:40:37 AM6/1/12
to
mike3 wrote:
) So what would the "bad design" be in this case? There doesn't
) seem to be a whole lot of things that could be changed. A bignum
) system will have init, free, and arithmetic routines. Trouble
) seems to be due to the possibility of return codes on every
) bignum operation. Is this the "design problem"? Notice that
) something like, say, GMP, doesn't do that. All GMP functions
) return void or an arithmetic result, not an error code. But I *do*
) want to have some sort of error reporting functionality.

A better design would be to catch errors into the bignum type itself,
and propagate that through the calculations. I.E.: Have 'error' be
a possible value for a bignum (or perhaps multiple 'error' values)
and whenever an 'error' value is used in a calculation, the result
is also (that same) 'error'.

That way, you can calculate away without error handling and at the
end do one single error check to see if everything went well.

mike3

unread,
Jun 1, 2012, 6:49:24 AM6/1/12
to
On May 31, 8:21 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> mike3 <mike4...@yahoo.com> writes:
> > YES, that's right -- those are GOTOs in there, and they do this a LOT
> > in this program! Djikstra!!!
>
> It's Dijkstra, OK? Dijkstra.
>

OK...

> The above is a terrible example. It looks like programming by numbers:
> "I've been told to trace entry and exit so I'll stick a label at the end
> and replace returns with gotos". I think it's clearer without them,
> although there is some justification if my guess is right -- it might
> have been a ploy to minimise re-writing.
>

To me, it looks like they're trying to reuse the TRACE call. So that
one
could modify the TRACE call without having to modify a clone at
another
point in the routine. Would it be OK to duplicate the line at each
return
point?

> > But as this thread seems to show, it looks like that there exist
> > alternatives to GOTO, and so we can still uphold Djikstra's law.
>
> It's not a law. The famous article is a well-argued case. Do read it
> if you haven't.
>
> > Or is there something about this program that makes it OK to use GOTOs
> > in it, but it is not OK to use them in the one I'm doing?
>
> I don't know the program, but this function does not benefit from having
> gotos. There are cases where a goto really helps, but they are far
> fewer than some people think.
>

Mmmm. So how would you write those returns?

tom st denis

unread,
Jun 1, 2012, 11:05:37 AM6/1/12
to
That only works if you capture the error codes in your bignum
structure otherwise it's not thread safe.

Tom

Aaron W. Hsu

unread,
Jun 1, 2012, 12:06:37 PM6/1/12
to
Ben Bacarisse wrote:

>> But as this thread seems to show, it looks like that there exist
>> alternatives to GOTO, and so we can still uphold Djikstra's law.
>
> It's not a law. The famous article is a well-argued case. Do read it
> if you haven't.

Knuth has a famous "retort" to the GOTO article.

Donald E. Knuth. 1974. Structured Programming with go to Statements. ACM
Comput. Surv. 6, 4 (December 1974), 261-301. DOI=10.1145/356635.356640
http://doi.acm.org/10.1145/356635.356640

--
Aaron W. Hsu | arc...@sacrideo.us | http://www.sacrideo.us
Programming is just another word for the lost art of thinking.

Ben Bacarisse

unread,
Jun 1, 2012, 9:01:10 PM6/1/12
to
"Aaron W. Hsu" <arc...@sacrideo.us> writes:

> Ben Bacarisse wrote:
>
>>> But as this thread seems to show, it looks like that there exist
>>> alternatives to GOTO, and so we can still uphold Djikstra's law.
>>
>> It's not a law. The famous article is a well-argued case. Do read it
>> if you haven't.
>
> Knuth has a famous "retort" to the GOTO article.

I am sure you know (hence the quotes) that it is not a refutation of
what Dijkstra wrote. Knuth says:

I argue for the elimination of go to's in certain cases, and for their
introduction in others. I believe that by presenting such a view I am
not in fact disagreeing sharply with Dijkstra's ideas, since he
recently wrote the following: "Please don't fall into the trap of
believing that I am terribly dogmatical about [the go to statement]."

Both are models of clarity, and neither is dogmatic. I feel sure that
if all gotos in all programs had been as well-reasoned for as those in
Knuth's paper, Dijkstra would never have written his.

> Donald E. Knuth. 1974. Structured Programming with go to Statements. ACM
> Comput. Surv. 6, 4 (December 1974), 261-301. DOI=10.1145/356635.356640
> http://doi.acm.org/10.1145/356635.356640

--
Ben.

Ben Bacarisse

unread,
Jun 1, 2012, 9:15:32 PM6/1/12
to
mike3 <mike...@yahoo.com> writes:

> On May 31, 8:21 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
>> mike3 <mike4...@yahoo.com> writes:
>> > YES, that's right -- those are GOTOs in there, and they do this a LOT
>> > in this program! Djikstra!!!
<snip>
>> The above is a terrible example. It looks like programming by numbers:
>> "I've been told to trace entry and exit so I'll stick a label at the end
>> and replace returns with gotos". I think it's clearer without them,
>> although there is some justification if my guess is right -- it might
>> have been a ploy to minimise re-writing.
>
> To me, it looks like they're trying to reuse the TRACE call.

Yes, but what came first? If the tracing was there originally and the
logic of the function was subsequently made more complex, doing it with
gotos makes no sense to me. If the logic was there and used multiple
returns when the tracing was added, I can see some value in making the
minimum of changes -- just replace the returns with jumps.

> So that
> one could modify the TRACE call without having to modify a clone at
> another point in the routine. Would it be OK to duplicate the line at
> each return point?

No, of course not.

<snip>
>> I don't know the program, but this function does not benefit from having
>> gotos. There are cases where a goto really helps, but they are far
>> fewer than some people think.
>
> Mmmm. So how would you write those returns?

Having got this far -- a single return -- I would add any more. I'd
just write the function using natural structures rather than jumps:

idn_result_t
idn_normalizer_add(idn_normalizer_t ctx, const char *scheme_name) {
idn_result_t r;
void *v;

assert(ctx != NULL && scheme_name != NULL);
TRACE(("idn_normalizer_add(scheme_name=%s)\n", scheme_name));
assert(INITIALIZED);

if (idn__strhash_get(scheme_hash, scheme_name, &v) != idn_success) {
ERROR(("idn_normalizer_add(): invalid scheme \"%-.30s\"\n",
scheme_name));
r = idn_invalid_name;
}
else {
assert(ctx->nschemes <= ctx->scheme_size);

if (ctx->nschemes != ctx->scheme_size ||
(r = expand_schemes(ctx)) == idn_success) {
ctx->schemes[ctx->nschemes++] = v;
r = idn_success;
}
}
TRACE(("idn_normalizer_add(): %s\n", idn_result_tostring(r)));
return r;
}

(I've also removed an unneeded variable: "scheme", but it would probably
be better to rename "v" as "scheme" now.)

--
Ben.

mike3

unread,
Jun 1, 2012, 10:45:45 PM6/1/12
to
On Jun 1, 7:15 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> mike3 <mike4...@yahoo.com> writes:
<snip>
> > To me, it looks like they're trying to reuse the TRACE call.
>
> Yes, but what came first?  If the tracing was there originally and the
> logic of the function was subsequently made more complex, doing it with
> gotos makes no sense to me.  If the logic was there and used multiple
> returns when the tracing was added, I can see some value in making the
> minimum of changes -- just replace the returns with jumps.
>

You mean a goto?

<snip>
> > Mmmm. So how would you write those returns?
>
> Having got this far -- a single return -- I would add any more.  I'd
> just write the function using natural structures rather than jumps:
>
>   idn_result_t
>   idn_normalizer_add(idn_normalizer_t ctx, const char *scheme_name) {
>        idn_result_t r;
>        void *v;
>
>        assert(ctx != NULL && scheme_name != NULL);
>        TRACE(("idn_normalizer_add(scheme_name=%s)\n", scheme_name));
>        assert(INITIALIZED);
>
>        if (idn__strhash_get(scheme_hash, scheme_name, &v) != idn_success) {
>             ERROR(("idn_normalizer_add(): invalid scheme \"%-.30s\"\n",
>                    scheme_name));
>             r = idn_invalid_name;
>        }
>        else {
>             assert(ctx->nschemes <= ctx->scheme_size);
>
>             if (ctx->nschemes != ctx->scheme_size ||
>                 (r = expand_schemes(ctx)) == idn_success) {
>                  ctx->schemes[ctx->nschemes++] = v;
>                  r = idn_success;
>             }
>        }
>        TRACE(("idn_normalizer_add(): %s\n", idn_result_tostring(r)));
>        return r;
>   }
>
> (I've also removed an unneeded variable: "scheme", but it would probably
> be better to rename "v" as "scheme" now.)
>

Hmm. This looks like the "nest" approach suggested on this thread by
Ike Naar. I suppose it'd be OK in this case, since there are only a
couple of
error-code-returning calls and so the nesting does not get too deep.
But
what if you had like 5 calls or more (and with something that's not a
bignum
package, so you couldn't, e.g. pass error codes inside bignums)?

mike3

unread,
Jun 1, 2012, 10:46:45 PM6/1/12
to
On Jun 1, 7:01 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> "Aaron W.  Hsu" <arcf...@sacrideo.us> writes:
<snip>
> Both are models of clarity, and neither is dogmatic.  I feel sure that
> if all gotos in all programs had been as well-reasoned for as those in
> Knuth's paper, Dijkstra would never have written his.
>

But I take it that, from what I've seen on this thread, using gotos to
jump to error code handlers is _not_ a "well-reasoned" use, right, and
so
Djikstra's rules still apply?

mike3

unread,
Jun 2, 2012, 12:19:41 AM6/2/12
to
^^^^^^^^^
Damn, I did it again! Dijkstra, oops. :(

BartC

unread,
Jun 2, 2012, 4:46:11 AM6/2/12
to
"mike3" <mike...@yahoo.com> wrote in message
news:d4477aa8-f837-4bee...@pr7g2000pbb.googlegroups.com...
> On May 29, 11:44 pm, mike3 <mike4...@yahoo.com> wrote:

> I've made an interesting and disturbing discovery.
>
> I found THIS:

> YES, that's right -- those are GOTOs in there, and they do this a LOT
> in this program!

I've just looked at the Python source code. I counted around 2000 gotos in
200,000 lines of code. Mostly they seemed to be used in place of an early
return, where there is common code to be executed before a return, so this
is just written once at the end of a function.

It seems clear enough. Some people don't like goto because it can lead to
spaghetti code (eg. as used by io_x), but it doesn't need to.

> Djikstra!!!

I've no idea who you're talking about there...

--
Bartc

Aaron W. Hsu

unread,
Jun 2, 2012, 5:37:50 AM6/2/12
to
On Sat, 02 Jun 2012 02:01:10 +0100, Ben Bacarisse wrote:

> Both are models of clarity, and neither is dogmatic. I feel sure that
> if all gotos in all programs had been as well-reasoned for as those in
> Knuth's paper, Dijkstra would never have written his.

Indeed, that is why I tend to refer people to the Knuth response after
reading Dijkstra's original. Even today there is an unnecessary
avoidance of GOTO, as if they are the root cause of all problems, when
the problem both of the above authors really want to address is code that
is not clear, reasoned, and justified. Spaghetti code should not exist,
regardless of whether or not you use Gotos to write spaghetti code.

mike3

unread,
Jun 2, 2012, 6:40:16 AM6/2/12
to
On Jun 2, 3:37 am, "Aaron W. Hsu" <arcf...@sacrideo.us> wrote:
> On Sat, 02 Jun 2012 02:01:10 +0100, Ben Bacarisse wrote:
> > Both are models of clarity, and neither is dogmatic.  I feel sure that
> > if all gotos in all programs had been as well-reasoned for as those in
> > Knuth's paper, Dijkstra would never have written his.
>
> Indeed, that is why I tend to refer people to the Knuth response after
> reading Dijkstra's original.  Even today there is an unnecessary
> avoidance of GOTO, as if they are the root cause of all problems, when
> the problem both of the above authors really want to address is code that
> is not clear, reasoned, and justified. Spaghetti code should not exist,
> regardless of whether or not you use Gotos to write spaghetti code.
>

So does using GOTOs to jump to error handlers make the code less
clear, reasoned, and justified (see the example in my OP)? How do they
affect the clarity of the "real world program" code snippet I posted?

Thad Smith

unread,
Jun 2, 2012, 9:20:45 AM6/2/12
to
On 5/30/2012 8:13 AM, ImpalerCore wrote:

> On a side note, the term ERROR_SUCCESS appears contradictory to me. I
> would prefer something like NO_ERROR or SUCCESS if you had control
> over the error definitions.

I agree. With an ERROR prefix I would use ERROR_NONE. My preference, though,
is to use <module>_SUCCESS (or <module>_OK), where <module> is replaced by a
name that designates the particular module whose status is being reported.

Thad

Joe keane

unread,
Jun 2, 2012, 9:54:24 AM6/2/12
to
In article <slrnjscii7....@toad.stack.nl>,
Willem <wil...@toad.stack.nl> wrote:
>I agree gotos are better.

I agree gotos are better.

int func(int x)
{
int err;
struct bar *a;
struct bar *b;
struct bar *c;
int err2;

err = allocate_bar(&a);
if (err != X_OK)
goto done;

err = allocate_bar(&b);
if (err != X_OK)
goto free_a;

err = allocate_bar(&c);
if (err != X_OK)
goto free_b;

...

/* normal exit */

err = free_bar(c);

err2 = free_bar(b);
err = err != X_OK ? err : err2;

err2 = free_bar(a);
err = err != X_OK ? err : err2;
return err;

/* error exit */

err2 = free_bar(c);
(void) err2;

free_b:
err2 = free_bar(b);
(void) err2;

free_a:
err2 = free_bar(a);
(void) err2;

done:
return err;
}

do that in C++!

Ben Bacarisse

unread,
Jun 2, 2012, 9:46:13 AM6/2/12
to
mike3 <mike...@yahoo.com> writes:

> On Jun 2, 3:37 am, "Aaron W. Hsu" <arcf...@sacrideo.us> wrote:
>> On Sat, 02 Jun 2012 02:01:10 +0100, Ben Bacarisse wrote:
>> > Both are models of clarity, and neither is dogmatic.  I feel sure that
>> > if all gotos in all programs had been as well-reasoned for as those in
>> > Knuth's paper, Dijkstra would never have written his.

It's been a while since I read it, so I read it again and I am no longer
so sure.

The surprising thing is that the note (it less then two pages long) is
about go to in programming languages -- not in programs. In effect, it
is a call to language designers to provide the right set of control
structures so that go to's are no longer needed.

Of course, the problem he so clearly identifies -- the fact that
unbridled use of the go to (note: _unbridled use_) leads to code that
can't be understood without maintaining a very complex view of the
code's execution sate -- applies to code written in those languages that
already have a go to statement.

>> Indeed, that is why I tend to refer people to the Knuth response after
>> reading Dijkstra's original.  Even today there is an unnecessary
>> avoidance of GOTO, as if they are the root cause of all problems, when
>> the problem both of the above authors really want to address is code that
>> is not clear, reasoned, and justified. Spaghetti code should not exist,
>> regardless of whether or not you use Gotos to write spaghetti code.
>
> So does using GOTOs to jump to error handlers make the code less
> clear, reasoned, and justified (see the example in my OP)? How do they
> affect the clarity of the "real world program" code snippet I posted?

To my mind, yes. However, the code is short and simple to re-write
without goto, so it is neither a good example of what Dijkstra was
arguing against, nor is it a good example of what Knuth was arguing to
retain. Because it is short, it is not particularly hard to reason
about (though it is harder to reason about than the goto-free version)
and because the pattern is simple to re-write without goto, it not a
case that shows the value of retaining goto in the language.

--
Ben.

Ben Bacarisse

unread,
Jun 2, 2012, 9:50:55 AM6/2/12
to
A well-reasoned use needs reasoning. Your recent example did not
include any reasoning, just a slightly facetious remark that you'd found
a goto in real code (multiple exclamation marks!!!).

In certain cases, depending on the logic, the case for a jump to a block
of common clean-up code can be made. It needs care to get it right
since you are often cleaning up an incomplete configuration using
variables whose cope is, by definition, nearly all of (and in C90 is all
of) the function body.

Your example was a bad one because the jump-free version is, to my mind,
clearer and simpler.

> and so Djikstra's rules still apply?

(You've corrected the name error.)

Go read the note -- it less then two pages. Honestly, go read it. It
does not present a rule for programmers, so much as a call for language
designers to provide control structures that are easy to reason about.
If gotos are still needed, it suggests a lack of suitable alternatives.

--
Ben.

Ben Bacarisse

unread,
Jun 2, 2012, 10:00:52 AM6/2/12
to
mike3 <mike...@yahoo.com> writes:

> On Jun 1, 7:15 pm, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
>> mike3 <mike4...@yahoo.com> writes:
> <snip>
>> > To me, it looks like they're trying to reuse the TRACE call.
>>
>> Yes, but what came first?  If the tracing was there originally and the
>> logic of the function was subsequently made more complex, doing it with
>> gotos makes no sense to me.  If the logic was there and used multiple
>> returns when the tracing was added, I can see some value in making the
>> minimum of changes -- just replace the returns with jumps.
>
> You mean a goto?

Yes.
Give an example, and I'll comment. I can't see exactly what it is you
are saying. I presume it is not just the code that you originally
posted, since I commented on that.

Having, multiple early error cases does not always lead to conceptually
deep nesting. If you have:

if (C1) {
rc = E1;
goto error;
}
if (C2) {
rc = E2;
goto error;
}
if (C3) {
rc = E3;
goto error;
}
/* main error-free code */
error:
/* common clean-up code */
return rc;

you can turn it into:

if (C1)
rc = E1;
else if (C2)
rc = E2;
else if (C3)
rc = E3;
else {
/* main error-free code */
}
/* common clean-up code */
return rc;

That's deeply nested in the most literal sense, but no one would have
any trouble reasoning about the nesting, eleven if were 100 levels deep.

--
Ben.

Malcolm McLean

unread,
Jun 2, 2012, 10:04:33 AM6/2/12
to
בתאריך יום שבת, 2 ביוני 2012 03:46:45 UTC+1, מאת mike3:
>
> But I take it that, from what I've seen on this thread, using gotos to
> jump to error code handlers is _not_ a "well-reasoned" use, right, and
> so Djikstra's rules still apply?
>
Gotos for error handling ia a well reasoned use. Being able to give cogent reasons for doing something doesn't mean that it is right, or that someone else might be able to give even better reasons against. But it's rather different from the situation where an action is taken without consideration, or in ignorance of the problems that may be associated with it.

Jean-Christophe

unread,
Jun 2, 2012, 10:24:44 AM6/2/12
to
On Jun 2, 3:54 pm, j...@panix.com (Joe keane) wrote:

> I agree gotos are better.

#define SIZE 3
int func(int x)
{
int i, err;
struct bar *s[SIZE];

// init
for( err=X_OK, i=0; (err==X_OK) && (i<SIZE); i++ )
err = allocate_bar( &s[i] );

// check success
if( err == X_OK )
{ // process ...
}

// free only allocated bar(s)
while( --i >= 0 ) free_bar( s[i] );

// done
return err; // zero = success

Ben Bacarisse

unread,
Jun 2, 2012, 10:42:27 AM6/2/12
to
This code is unreachable but I think it's not needed by any path so it's
probably just there due to an editing error.

> free_b:
> err2 = free_bar(b);
> (void) err2;
>
> free_a:
> err2 = free_bar(a);
> (void) err2;
>
> done:
> return err;
> }
>
> do that in C++!

Why do you think this is not already C++?

BTW, to my mind this API is broken. I like allocation functions that
return NULL on failure. If you need more data, an error-collecting
parameter can be passed. Having NULL pointers make it possible to write
clean-up code that does not depend on the order of allocation.

However, using the same API, I'd write:

int func(int x)
{
int err_a, err_b, err_c;
struct bar *a, *b, *c;

err_a = allocate_bar(&a);
err_b = allocate_bar(&b);
err_c = allocate_bar(&c);

if (err_a == X_OK && err_b == X_OK && err_c == X_OK) {
/* normal code */
}

if (err_a == X_OK) err_a = free_bar(a);
if (err_b == X_OK) err_b = free_bar(b);
if (err_c == X_OK) err_c = free_bar(c);

return err_a == X_OK && err_b == X_OK && err_c == X_OK;
}

This does not return the same value, as your code but that's not hard to
change. I found your code's preference for one possible error over
another to be a little odd, so I changed it to appear more uniform.

--
Ben.

io_x

unread,
Jun 2, 2012, 11:34:39 AM6/2/12
to

"io_x" <a...@b.c.invalid> ha scritto nel messaggio
news:4fc61d23$0$1385$4faf...@reader2.news.tin.it...
>
> "mike3" <mike...@yahoo.com> ha scritto nel messaggio
> news:7e54cf3c-d514-407b...@ra8g2000pbc.googlegroups.com...
>> Hi.
>>
>> I've got some stuff that looks like this:
>
> this is my way...

this could be my way...
probabily i use not well C macro...
'2' exit[it is always one]: one for error one for ok

#include <stdio.h>

#define u32 unsigned
#define u64 unsigned __int64
#define i32 int
#define u16 unsigned short
#define u8 unsigned char
#define i8 char
#define i16 short
#define long_long __int64

#define sdC __stdcall
#define ooo cout
#define S sizeof
#define MM Malloc_m
#define FF Free_m
#define F for
#define R return
#define W while
#define G goto
#define P printf
#define jj(x) if((x)==-1) goto

typedef u32* BigNum;

// dummy functions
i32 BigNum_Initialize(BigNum* a) {R (i32)(*a=0);}
i32 BigNum_Set(BigNum* a, u32 b) {R (i32)(*a=(u32*)b);}
i32 BigNum_Add(BigNum* c,BigNum* b, u32 r){R (i32)(*c=(u32*)((u32)*b+r));}
i32 BigNum_Add(BigNum* c,BigNum* b, BigNum* r)
{R (i32)(*c=(u32*)((u32)*b+(u32)*r));}
i32 BigNum_Free(BigNum* a) {R (i32)(*a=0);}

i32 MyFunc(void)
{BigNum a, b, c, d;

P("Inizio a=%u b=%u c=%u d=%u\n", a, b, c, d);
if(BigNum_Initialize(&a)== -1)
{ex0: R -1;}
if(BigNum_Initialize(&b)== -1)
{ex1: BigNum_Free(&a); G ex0;}
if(BigNum_Initialize(&c)== -1)
{ex2: BigNum_Free(&b); G ex1;}
if(BigNum_Initialize(&d)== -1)
{ex3: BigNum_Free(&c); G ex2;}

P("Inizilizzati a=%u b=%u c=%u d=%u\n", a, b, c, d);

if(BigNum_Set(&b, 3)==-1)
{ex4: BigNum_Free(&d); G ex3;}

jj(BigNum_Add(&c, &b, 3)) ex4;
jj(BigNum_Add(&a, &d, 3)) ex4;
jj(BigNum_Add(&d, &c,&a)) ex4;
// etc
// ....
/* free buffers */
P("fine a=%u b=%u c=%u d=%u\n", a, b, c, d);

jj(BigNum_Free(&d)) ex3;
jj(BigNum_Free(&c)) ex2;
jj(BigNum_Free(&b)) ex1;
jj(BigNum_Free(&a)) ex0;

P("fine1 a=%u b=%u c=%u d=%u\n", a, b, c, d);
R 0;
}

main(void){R MyFunc();}



BartC

unread,
Jun 2, 2012, 12:10:51 PM6/2/12
to
"Ben Bacarisse" <ben.u...@bsb.me.uk> wrote in message
> To my mind, yes. However, the code is short and simple to re-write
> without goto, so it is neither a good example of what Dijkstra was
> arguing against, nor is it a good example of what Knuth was arguing to
> retain. Because it is short, it is not particularly hard to reason
> about (though it is harder to reason about than the goto-free version)
> and because the pattern is simple to re-write without goto, it not a
> case that shows the value of retaining goto in the language.

The fact that C is quite often used a compilation target for other
languages, is enough reason to retain the goto statement. (Even forgetting
the millions of lines of existing code.)

Any control statement that doesn't exactly match one of C's limited
selection of statements, can easily be translated instead into a series of
conditional statements and gotos. Then there might be housekeeping code,
common return code, etc that doesn't fit into a structured programming
pattern, as well as actual spaghetti code, using gotos, in the source
language.

(Actually, you can probably get rid of most control statements; just leave a
simple if-statement (you don't need else), and goto. These are the most
important.)

While there might be theoretical ways of always being able to eliminate all
gotos by convoluting the code and adding extra state variables, it's far
easier just to use gotos. Especially in target code that no-one is ever
going to read.

But for actually writing in C, obviously you will use them sparingly.

--
Bartc

Robert Wessel

unread,
Jun 2, 2012, 12:35:06 PM6/2/12
to
I think that's an important point - the problems Dijkstra was
referring to were in programs of multiple thousands of line of code
with gotos jumping all around that entire program. More modern
language, like C, which constrain gotos to a single function, greatly
reduce the problem (the odd 5000 line function excluded, of course),
because you simply cannot make that much spaghetti in a hundred (or
two) lines of code. As always, locality is a major key to
understanding.

My personal opinion is that clarity trumps all. That being said,
while I use gotos rarely, I have no problem with the
error/cleanup/common-return pattern, an occasional break/continue out
of more than one level of loop or other (very rare) uses where it's
just simpler (some state machine like constructs, for example). All
acknowledging that there are always alternatives, and many times,
given that we shouldn't be writing excessively long functions, none of
the alternatives is really that much more complex or unclear than the
others.

blmblm.m...@gmail.com

unread,
Jun 2, 2012, 12:35:09 PM6/2/12
to
In article <fc325350-fecd-4c33...@tx6g2000pbc.googlegroups.com>,
mike3 <mike...@yahoo.com> wrote:
> On Jun 1, 8:46 pm, mike3 <mike4...@yahoo.com> wrote:

[ snip ]

> > Djikstra's rules still apply?
> ^^^^^^^^^
> Damn, I did it again! Dijkstra, oops. :(

Maybe you will find the following useful as a way of remembering
(I *think* I got this from a native speaker of Dutch, though I may
be misremembering): "Dykstra" might be a more logical spelling,
and the "i" and "j" together look sort of like a "y". FWIW?

--
B. L. Massingill
ObDisclaimer: I don't speak for my employers; they return the favor.

Joe keane

unread,
Jun 2, 2012, 12:37:43 PM6/2/12
to
In article <a77db563-a307-4c82...@cu1g2000vbb.googlegroups.com>,
Jean-Christophe <5...@free.fr> wrote:
>#define SIZE 3
>int func(int x)
>{
>int i, err;
>struct bar *s[SIZE];
>
>// init
> for( err=X_OK, i=0; (err==X_OK) && (i<SIZE); i++ )
> err = allocate_bar( &s[i] );
>
>// check success
> if( err == X_OK )
> { // process ...
> }
>
>// free only allocated bar(s)
> while( --i >= 0 ) free_bar( s[i] );
>
>// done
>return err; // zero = success
>}

I used 'struct bar',
for all of them,
for sake of example.

It's very likely that in real world code
they are all different types,
with different functions to allocate them and unallocate them,
and so some code to iterate over them is likely to be
some more confusing than helpful.

If they are the same type,
such that you can put them in an array,
then of course what you say is better.

Martin Shobe

unread,
Jun 2, 2012, 3:27:55 PM6/2/12
to
If you insist. :)

void func(int x)
{
std::unique_ptr<bar> a = new bar();
std::unique_ptr<bar> b = new bar();
std::unique_ptr<bar> c = new bar();

...
}

Martin Shobe

Joe keane

unread,
Jun 2, 2012, 3:35:59 PM6/2/12
to
In article <0.ad98122c5f4b9fe6aef5.2012...@bsb.me.uk>,
Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
>I like allocation functions that return NULL on failure.

I like allocation functions that set the carry bit on failure.

My own convention is that if a function returns less than zero, it has
reset your state to the most extent possible, and none of the 'output'
parameters are changed (but be liberal in what you receive).

IMHE the stupid mistakes occur when you mix together conventions [it
-should- be easy to do this, but we are just monkeys].

When you prevent stupid mistakes, you force people to make the more
complicated mistakes.

Jean-Christophe

unread,
Jun 2, 2012, 3:46:35 PM6/2/12
to
On 2 juin, 18:37, j...@panix.com (Joe keane) :

> I used 'struct bar',
> for all of them, for sake of example.
> It's very likely that in real world code
> they are all different types,
> with different functions to allocate them and unallocate them,
> and so some code to iterate over them is likely to be
> some more confusing than helpful.

I'd rather encapsulate functions pointers
( allocate, init, ... etc ... )
into the structure itself, to allow the
use of identical syntax all down the code.
It makes it more readable, and shorter.
And still, this is not C++, juste pure C.

mike3

unread,
Jun 2, 2012, 7:44:39 PM6/2/12
to
On Jun 2, 8:00 am, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
> mike3 <mike4...@yahoo.com> writes:
<snip>
> > You mean a goto?
>
> Yes.
>

Thanks for the explanation.

<snip>
So you're suggesting to abuse the if() to create a list of executed
functions
that breaks off at an error, then, right? Is that a "dirty" trick?

Ben Bacarisse

unread,
Jun 2, 2012, 10:51:29 PM6/2/12
to
I can't made head or tail of that. If you consider my use of if .. else
if ... to be an abuse, I doubt we have enough common ground debate this
point, but that seems like an unlikely position to hold and does not
explain the "list of executed functions" remark.

--
Ben.

Ben Bacarisse

unread,
Jun 2, 2012, 10:53:03 PM6/2/12
to
j...@panix.com (Joe keane) writes:

> In article <0.ad98122c5f4b9fe6aef5.2012...@bsb.me.uk>,
> Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
>>I like allocation functions that return NULL on failure.
>
> I like allocation functions that set the carry bit on failure.

I wish you and the carry bit all the best.

<snip>
--
Ben.

io_x

unread,
Jun 3, 2012, 4:33:17 AM6/3/12
to

"io_x" <a...@b.c.invalid> ha scritto nel messaggio
news:4fca3222$0$1380$4faf...@reader2.news.tin.it...
at end i wuold write something as:
i32 MyFunc(BigNum* x)
{BigNum a, b, c, d;
if(x==0) R -1;
a=0; b=3; c=b+3; *x=c+a+d;
if(x->err()) R -1;
else R 0;
}

but would be the OT c++...
yes it is intendend all c++ exceptions turn off
but except the one
"write out of mem reserved to that program"





io_x

unread,
Jun 3, 2012, 4:43:11 AM6/3/12
to

"BartC" <b...@freeuk.com> ha scritto nel messaggio
news:jqcjta$7mk$1...@dont-email.me...
so you know what structured programming mean?

>> Djikstra!!!

so Djikstra know what structured programming mean?
"structured programming" has something in common to write
down in code the correct algo?

if someone speak not good for goto he/she make wrong...
he she don't know to what he she is talking about...

it is good find a way to write easy one algo
and find a way for find easily errors in that too
but it need art

BartC

unread,
Jun 3, 2012, 5:58:49 AM6/3/12
to


"io_x" <a...@b.c.invalid> wrote in message
news:4fcb2258$0$1375$4faf...@reader2.news.tin.it...
>
> "BartC" <b...@freeuk.com> ha scritto nel messaggio

>> It seems clear enough. Some people don't like goto because it can lead to
>> spaghetti code (eg. as used by io_x), but it doesn't need to.
>
> so you know what structured programming mean?

Something like this I guess:

http://en.wikipedia.org/wiki/Structured_programming

> so Djikstra know what structured programming mean?
> "structured programming" has something in common to write
> down in code the correct algo?
>
> if someone speak not good for goto he/she make wrong...
> he she don't know to what he she is talking about...

It's not just black and white. You wouldn't use 'goto' to replace the
if-else, while, do-while, switch and for statements, because the code would
be much more obscure. But I can't see the problem in using it where no
suitable control statement exists (although others would argue that it is
better then to turn the code upside-down so that it does fit into the
statements that are available).

(I couldn't find a copy of Dijkstra's letter; there's an annotated version
here, with his text in blue: http://david.tribble.com/text/goto.html)

> it is good find a way to write easy one algo
> and find a way for find easily errors in that too
> but it need art

It needs that you are the one who wrote the original code, and that you are
reading the same code five minutes later.

--
Bartc

Willem

unread,
Jun 3, 2012, 7:24:26 AM6/3/12
to
tom st denis wrote:
) On May 30, 12:26?pm, Willem <wil...@toad.stack.nl> wrote:
)> Another method is to have all 'bignum' functions check for 'error' inputs
)> and generate 'error' outputs when they encounter them (or whenever they
)> ?encounter an error), and then you only have to check for an 'error'
)> result at the very end.
)>
)> Something like:

<snip>

)> The only weirdside to this is when a value is not used in the final result,
)> then that value will not be checked for errors.
)
) That only works if you capture the error codes in your bignum
) structure otherwise it's not thread safe.

I don't see any way to implement what I described other than storing
the error codes in the bignum structures.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
Message has been deleted

io_x

unread,
Jun 3, 2012, 11:18:40 AM6/3/12
to

"BartC" <b...@freeuk.com> ha scritto nel messaggio
news:jqfcgt$i8m$1...@dont-email.me...
>> it is good find a way to write easy one algo
>> and find a way for find easily errors in that too
>> but it need art
>
> It needs that you are the one who wrote the original code, and that you are
> reading the same code five minutes later.

i read my code only in case of bug...i think i could not read code from some
other one...

i don't know for debug-understand other code, but for my code i not have
problem;
can be years 1000 yesars etc etc...
yes i not use much comment, for find one error i use the debug for find
the 10-20 lines that generate the error; without understand the remain...

than i debug these line for to see what dey do
and what they do when error came out...
and for this, there is some time because one has to understand all:
why this, why that, etc
until the error is found; until now, using above method
i found all error i searched.
these bugs came out one time 30-90 days or when i change the library
functions etc

for example the last one...
some day ago i test if the new library goes well with the old program...
but there was one error;
i just track down all function changed from old-new dll
but no step toward find the error...

so i trace for find the function find for the first the error:
it was one time function, the error is not in the new function
but in the old ones in a time function that found "this day"
the last day of the month, is not right... and so return error

the error was that in time library the tables for days in month
are wrong

daytab db 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
daytabL db 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31

instead of
; 1 2 3 4 5 6 7 8 9 10 11 12
daytab db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
daytabL db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31

and the function return error because it
find that the now day is not right
i change the table and all ok...
this error could no came out easily because came out only in
the last day of the month if the month is the one right :)
i think i like track down errors it is like read one book
of Agatha Cristie...



io_x

unread,
Jun 3, 2012, 11:30:42 AM6/3/12
to

"io_x" <a...@b.c.invalid> ha scritto nel messaggio
news:4fcb2258$0$1375$4faf...@reader2.news.tin.it...
>
> "BartC" <b...@freeuk.com> ha scritto nel messaggio
> news:jqcjta$7mk$1...@dont-email.me...
>> "mike3" <mike...@yahoo.com> wrote in message
>> news:d4477aa8-f837-4bee...@pr7g2000pbb.googlegroups.com...
>>> On May 29, 11:44 pm, mike3 <mike4...@yahoo.com> wrote:
>>> Djikstra!!!
>
> so Djikstra know what structured programming mean?

error above: "Dijkstra" excuse me...


Jean-Christophe

unread,
Jun 3, 2012, 12:02:02 PM6/3/12
to
On 3 juin, 17:30, "io_x" <a...@b.c.invalid> wrote:

> Dijkstra know what structured programming mean?

Edsgar Dijkstra is a quiche eater:
http://powerdown.free.fr/rp.html

Ben Bacarisse

unread,
Jun 3, 2012, 5:37:33 PM6/3/12
to
"Was", not "is". He died in 2002.

To get a flavour of what a real "quiche eater" is like, read his
development of a program to find the convex hull of a set of 3D points,
which is done in parallel with the development of a proof of the
algorithm's correctness.[1] In fact, read the whole book, if you have
time. It changed the way I think about programming.

[1] E. W. Dijkstra, "A Discipline of Programming", Prentice Hall, 1977,
Chapter 24, pp 168--191.

--
Ben.

Joe keane

unread,
Jun 3, 2012, 7:48:18 PM6/3/12
to
In article <jqdpfq$pqs$1...@dont-email.me>,
Martin Shobe <martin...@yahoo.com> wrote:
>If you insist. :)
>
>void func(int x)
>{
> std::unique_ptr<bar> a = new bar();
> std::unique_ptr<bar> b = new bar();
> std::unique_ptr<bar> c = new bar();
>
> ...
>}

Does it return the correct error code if an error occurs in the
unallocate function?

Ian Collins

unread,
Jun 3, 2012, 7:53:59 PM6/3/12
to
delete does not return errors and func is declared void.

Your code ignored the errors from free_bar (in a very ugly fashion I
might add).

--
Ian Collins

Martin Shobe

unread,
Jun 3, 2012, 11:32:11 PM6/3/12
to
Return it? No. But it would throw the correct exception.

Martin Shobe

Ike Naar

unread,
Jun 4, 2012, 3:28:39 AM6/4/12
to
On 2012-06-03, Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
> Jean-Christophe <5...@free.fr> writes:
>> Edsgar Dijkstra is a quiche eater:
>> http://powerdown.free.fr/rp.html
>
> "Was", not "is". He died in 2002.
>
> To get a flavour of what a real "quiche eater" is like, read his
> development of a program to find the convex hull of a set of 3D points,
> which is done in parallel with the development of a proof of the
> algorithm's correctness.[1] In fact, read the whole book, if you have
> time. It changed the way I think about programming.
>
> [1] E. W. Dijkstra, "A Discipline of Programming", Prentice Hall, 1977,
> Chapter 24, pp 168--191.

Another book, that describes the same ideas in a more accessible manner,
is David Gries' "The Science of Programming", Springer, 1981.
With a foreword by E.W. Dijkstra.

Joe keane

unread,
Jun 4, 2012, 4:40:40 PM6/4/12
to
In article <goto-2012...@ram.dialup.fu-berlin.de>,
Stefan Ram <r...@zedat.fu-berlin.de> wrote:
> The code alteration of the first paragraph seems to be
> easier with structured blocks. It also might be easier to
> read and to argue about properties of that code segment or
> to prove them; the mere wording »precondition«,
> »postcondition«, and »invariant« of a block seem to imply
> that it is a structured block.

What i see here is that the postcondition typically comprises two
conditions, one for normal exit, one for error exit, and they are
usually pretty dissimilar. So i'm not sure that insisting on one
postcondition really buys you any simplicity.

In terms of code, it's always nice to see the normal exit first, then
the error handling. Someone who just wants to get some idea how a
function works does not need to plow through the latter. Of course we
want to be sure that it's right, but it's often just distracting.
Message has been deleted

Joe keane

unread,
Jun 4, 2012, 9:03:40 PM6/4/12
to
In article <postconditions...@ram.dialup.fu-berlin.de>,
Stefan Ram <r...@zedat.fu-berlin.de> wrote:
> It is not mentioned on
>
>http://en.wikipedia.org/wiki/Postcondition

?

'a postcondition is a condition or predicate that must always be true
just after the execution of some section of code'

e.g.

int foo(int x)
{
int y;

if (x == 0)
{
y = 0;
}
else
{
y = 1;
}

return y;
}

A precondition of the first block is "x == 0".
A precondition of the second block is "x != 0".
A postcondition of the first block is "x == 0 && y == 0".
A postcondition of the second block is "x != 0 && y != 0".

A postcondition of the if/else construct is
"x == 0 && y == 0 || x != 0 && y != 0".
Message has been deleted

Joe keane

unread,
Jun 4, 2012, 10:05:40 PM6/4/12
to
In article <postconditions...@ram.dialup.fu-berlin.de>,
Stefan Ram <r...@zedat.fu-berlin.de> wrote:
> and I am not aware of any source speaking of such /two/
> postconditions.

http://en.wikipedia.org/wiki/Hoare_triple#Conditional_rule

any language with an if/else construct has two postconditions

{B && P} S {Q}, {!B && P} T {Q}
----
{P} if B then S else T endif {Q}

or mine

{B && P} S {Q}, {!B && P} T {R}
----
{P} if B then S else T endif {Q || R}

identical since "Q" -> "Q || R", "R" -> "Q || R", "Q || Q" -> "Q" are
tautologies
Message has been deleted

Martin Shobe

unread,
Jun 4, 2012, 11:16:58 PM6/4/12
to
Joe keane wrote:

> In article <postconditions...@ram.dialup.fu-berlin.de>,
> Stefan Ram <r...@zedat.fu-berlin.de> wrote:
>> and I am not aware of any source speaking of such /two/
>> postconditions.
>
> http://en.wikipedia.org/wiki/Hoare_triple#Conditional_rule
>
> any language with an if/else construct has two postconditions
>
> {B && P} S {Q}, {!B && P} T {Q}
> ----
> {P} if B then S else T endif {Q}

Only one postcondition here (namely Q).

>
> or mine
>
> {B && P} S {Q}, {!B && P} T {R}
> ----
> {P} if B then S else T endif {Q || R}
>
> identical since "Q" -> "Q || R", "R" -> "Q || R", "Q || Q" -> "Q" are
> tautologies

Again, only one post condition here (namely Q || R).

And before you try to say that Q is one postcondition and R is the
other, consider that, in general, neither Q nor R are postconditions by
themselves.

Martin Shobe


Martin Shobe

Joe Pfeiffer

unread,
Jun 4, 2012, 11:36:39 PM6/4/12
to
r...@zedat.fu-berlin.de (Stefan Ram) writes:

> j...@panix.com (Joe keane) writes:
>>A precondition of the first block is "x == 0".
>
> This is the /second/ compound statement. The /first/
> compound statement starts at the first brace in your code.
>
>>A postcondition of the first block is "x == 0 && y == 0".
>
> This is /one/ postcondition. Before, you wrote:
>
>>>>the postcondition typically comprises two conditions
> ¯¯¯
> . There is no source that says so (except your post).

I think he's talking about what he's seen in his experience, not a
definition -- that he's tended to see postconditions of the form
(a || b) where 'a' means "the postcondition you'd expect from a naive
statement of the algorithm" and 'b' means "some strange kludge that came
about as a result of an error in the course of executing the code".

Edward A. Falk

unread,
Jun 5, 2012, 3:20:52 AM6/5/12
to
In article <jq4nar$lvm$1...@dont-email.me>,
MarkBluemel <mark_b...@pobox.com> wrote:
>On 05/30/2012 06:44 AM, mike3 wrote:
>
>ErrorCode MyFunc()
>{
> BigNum a = BIGNUM_NULL;
> BigNum b = BIGNUM_NULL;
> BigNum c = BIGNUM_NULL;
> BigNum d = BIGNUM_NULL;
> ErrorCode rv;
>
> rv = BigNum_Initialize(&a);
> if(rv != ERROR_SUCCESS)
> goto failed;
>
> ...
>
>failed: /* we'll try and clean up, but won't care too much if it fails */
> if (d != BIGNUM_NULL)
> BigNum_Free(&d);
> ...

This is the style I tend to prefer. I've written a lot of device drivers
in the past, and the attach function generally has to catch about a
dozen failure cases. This is pretty much the cleanest & safest way
to deal with it.

--
-Ed Falk, fa...@despams.r.us.com
http://thespamdiaries.blogspot.com/

Ike Naar

unread,
Jun 5, 2012, 4:12:58 AM6/5/12
to
On 2012-06-05, Stefan Ram <r...@zedat.fu-berlin.de> wrote:
> j...@panix.com (Joe keane) writes:
>>A precondition of the first block is "x == 0".
>
> The /first/
> compound statement starts at the first brace in your code.

A real quiche-eater would call that the zero-th compound statement ;-)

James Kuyper

unread,
Jun 5, 2012, 6:00:19 AM6/5/12
to
Such people really do exist; I once had a very confusing discussion with
someone who insisted on misusing English that way.
--
James Kuyper
Message has been deleted

Joe keane

unread,
Jun 5, 2012, 11:13:40 AM6/5/12
to
In article <1bzk8ib...@pfeifferfamily.net>,
Joe Pfeiffer <pfei...@cs.nmsu.edu> wrote:
>I think he's talking about what he's seen in his experience, not a
>definition

I think i'm talking about what i've seen in my experience, not a
definition

>-- that he's tended to see postconditions of the form (a || b)

i tended to see all postconditions of the form

IF [error code is zero] THEN
all operations we did completed successfuly
go ahead with what you wanted to do
ELSE /* error code is not zero */
at least one thing we tried did not complete successfully
we tried to clean it up but we can not guarantee that
we tried to return the error code for the -first- error
if you fix the first error we can probably do a better job
at telling you what if anything else is wrong
ENDIF

>where 'a' means "the postcondition you'd expect from a naive statement
>of the algorithm" and 'b' means "some strange kludge that came about as
>a result of an error in the course of executing the code".

; handling 'double errors' you will never get -right-, but at least you can
try to be helpful.

mike3

unread,
Jun 6, 2012, 5:54:56 AM6/6/12
to
On May 31, 5:39 pm, mike3 <mike4...@yahoo.com> wrote:
> On May 29, 11:44 pm, mike3 <mike4...@yahoo.com> wrote:
<snip>

I've been wondering about this. _Why_ was a GOTO used in this
program? How could one be used in _such a high-profile program
like that_? And it's not just a lone GOTO or a few here and there,
as I said, this program is infected with a serious case of GOTOitis...

Ben Bacarisse

unread,
Jun 6, 2012, 8:14:43 AM6/6/12
to
You'd have to ask the people who wrote it.

Some of the code looks extraordinary to me. Whilst the vast majority of
goto's are clearly of the "error cleanup" sort, they are not all like
that. For example there is this pattern:

cmsgp = CMSG_FIRSTHDR(msg);
while (cmsgp != NULL) {
socket_log(...);

#ifdef ISC_PLATFORM_HAVEIN6PKTINFO
if (...) {
/* stuff */
goto next;
}
#endif

#ifdef SO_TIMESTAMP
if (...) {
/* stuff */
goto next;
}
#endif
next:
cmsgp = CMSG_NXTHDR(msg, cmsgp);
}

Why is this not just a for loop? Failing that, why not just remove the
label and the goto's? Maybe this is a fossilised relic of some much
more complex code.

Although there may well be a reason the code ended up like this, I hope
everyone agrees that it would be odd (to say the least) to write it like
this from scratch.

--
Ben.

Angel

unread,
Jun 6, 2012, 9:06:28 AM6/6/12
to
A quick search through the source code of Linux 3.2.12 reveals no less
than 94422 goto statements.

I agree that one should think very carefully about using a goto statement
where structured code would be much better. But there are, especially in
exception handling (which, um, C doesn't really provide), cases where the
use of a goto statement produces much more elegant code.

There is an interesting read about it all here:
http://kerneltrap.org/node/553/2131


I agree with what Scott Robert Ladd states: Bad code is produced by bad
programmers, not by bad language features.


--
"C provides a programmer with more than enough rope to hang himself.
C++ provides a firing squad, blindfold and last cigarette."
- seen in comp.lang.c

pete

unread,
Jun 6, 2012, 9:22:18 AM6/6/12
to
It may be the case
that it is, or was, somewhat common
for expert proffesional programmers
to have accomplished a lot of proffesional programming work
before they became experts.

I recall many many years ago,
showing some crappy looking code to my new boss,
and him telling me that because of time constraints
I would soon be writing crappy looking code too.
And he was right.
They hired me when they needed a programmer right away,
and I didn't know C or good writing style
nearly as well as I do now,
and because of time constraints, I had to program quickly.

--
pete

Willem

unread,
Jun 6, 2012, 9:49:56 AM6/6/12
to
pete wrote:
) I recall many many years ago,
) showing some crappy looking code to my new boss,
) and him telling me that because of time constraints
) I would soon be writing crappy looking code too.
) And he was right.
) They hired me when they needed a programmer right away,
) and I didn't know C or good writing style
) nearly as well as I do now,
) and because of time constraints, I had to program quickly.

Your boss obviously was unaware that crappy code saves time in the
short run, but costs more time (with compound interest) in the long run.

But it seems that choosing short term benefits over long term benefits
is all the rage these days, so that is no surprise.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
It is loading more messages.
0 new messages