October 05, 2018
On Thursday, 4 October 2018 at 06:43:02 UTC, Gopan wrote:
> Any advices?

In C, I will layout my functions like that (that's especially good for initializer functions):

int init(struct my_handle *handle, ...)
{
  if (handle == NULL)
    return -EINVAL;  // direct return for parameter safety check

  if (other_arg > MY_MIN || other_arg > MY_MAX)
    return -EINVAL;  // same here

  handle->data == calloc(1, SIZE);
  if (handle->data == NULL)
    return -ENOMEM;  // return when memory allocation fails,
                     // I assume my program won't recover anyway

  // create some system resource
  handle->fd = fopen("bla.txt", "w");
  if (handle->fd == NULL)
    goto error;  // goto error, because I have some cleanup to do
                 // I will use goto's from now on every time I have
                 // some action that return an error

  ...

  return 0; // Success

error:
  close(handle->fd);  // maybe check first fd is valid...
  free(handle->data);
  return -EFAIL;
}


My basic rules are:
1- Argument safety check before anything else, return straightaway.
2- If memory allocation fails, return (or assert), no cleanup, unless you expect to recover from it, so that is a resource allocation like described in the next point.
3- If some resource allocation fails, escape using a goto statement to final label. I call it "error" for simple cases, else "error_closepipe", "error_epoll" etc, depending on the resource I'm cleaning up.
4- error handling is after a successful "return 0;" which finalizes a nominal execution flow.
5- Maybe use some "int ret" to carry some error code at the end, and maybe log it, for easier debugging.
6- Don't use a return statement in a loop. Break from it: there could be some cleanup to do after the loop.

As a side-note, one instruction is one operation, I don't like:

if ((ret = handle->doSomeStuff(args)) < 0)
  goto error;

I prefer:

ret = handle->doSomestuff(args);
if (ret < 0)
  goto error;

It's especially annoying to read (and thus maintain) if some other conditions are tested in the if-statement.
October 05, 2018
On Thursday, 4 October 2018 at 06:43:02 UTC, Gopan wrote:
>  I have seen people enclosing the function logic inside a while(1) merely to stick on to single return at the end.
>
> while(1)
> {
> 	...
> 	break; //otherwise return would come here.
> 	...
> 	break;
> }
>
> return ...;

I think `switch (0) default:` is better, because it's not a loop so the intent is clear - no continue statements somewhere below (so it's also better than `do ... while (0);`). Also you might forget the final break statement with `while` and get an infinite loop.

This is an occasionally useful general pattern (I use early returns).


October 05, 2018
On 10/04/2018 11:40 PM, rikki cattermole wrote:
> On 05/10/2018 8:23 AM, Nick Sabalausky (Abscissa) wrote:
>> I was in college during the height of the Java craze, so my instructors highly recommended the deep nesting approach. This was because return statements are control-flow, and control-flow isn't very object-orientedy, and is old-fasioned and in the same category as the dreaded goto and was therefore bad. So I switched to the nesting-instead-of-returning style because it was "The Right Way".
> 
> "Terminology invoking "objects" and "oriented" in the modern sense of object-oriented programming made its first appearance at MIT in the late 1950s and early 1960s."[0].
> 
> And this is why you have to be very careful with any sort of trend in programming. Because it was already done before you were born (assuming you began learning after 1990) ;)
> 
> [0] https://en.wikipedia.org/wiki/Object-oriented_programming#History

It's not *my* statement about newer/older. If you recall the programming atmosphere around 2000, OO was widely being touted as a newer thing, superior to "old-fashioned" imperative, even though there's a million things about that whole assessment that are false (not the least of which being the at-the-time popular notion that Java-style OO somehow wasn't still imperative, or, as you pointed out, that OO was a new invention).

There's one minor aspect of it that was true though: Widespread popularity of OO was certainly a new thing, even if OO itself wasn't.
October 05, 2018
On Friday, 5 October 2018 at 16:02:49 UTC, Nick Treleaven wrote:
> On Thursday, 4 October 2018 at 06:43:02 UTC, Gopan wrote:
>>  I have seen people enclosing the function logic inside a while(1) merely to stick on to single return at the end.
>>
>> while(1)
>> {
>> 	...
>> 	break; //otherwise return would come here.
>> 	...
>> 	break;
>> }
>>
>> return ...;
>
> I think `switch (0) default:` is better, because it's not a loop so the intent is clear - no continue statements somewhere below (so it's also better than `do ... while (0);`). Also you might forget the final break statement with `while` and get an infinite loop.
>
`do ... while (0);` and also the loop above are abominations. They are for goto hypocrits, i.e. people who think that a goto when it is not named goto but works exactly like a goto is something better (the Voldemort goto).
The breaks above and in are GOTOS, no point in obfuscating them. Sorry if I'm a little bit inflammatory about these constructs, but I have to work with code written by a `do {} while(0)` champion and I can tell you, it's the horror when you have to make changes.
It was so bad that I finally used  __attribute__((__cleanup__(x))) gcc extension to implement something resembling D's scope(exit) so that I'm sure that the code doesn't leak like it did before.


October 05, 2018
On Tuesday, 2 October 2018 at 18:14:55 UTC, Andrei Alexandrescu wrote:
> Kate Gregory makes a good argument on something I've often commented in code reviews: https://youtu.be/n0Ak6xtVXno?t=2682

I've found a good explanation for the reason behind nesting here:
https://softwareengineering.stackexchange.com/a/118793

The "single entry, single exit" principle seems to predate structured programming. It was a best practice of a time when gotos and other jumps were preventing the call stack to be properly cleaned up or local variables to be initialized thus leading to  difficult to debug errors.

October 05, 2018
On Fri, Oct 05, 2018 at 08:00:03PM +0000, Patrick Schluter via Digitalmars-d wrote:
> On Friday, 5 October 2018 at 16:02:49 UTC, Nick Treleaven wrote:
> > On Thursday, 4 October 2018 at 06:43:02 UTC, Gopan wrote:
[...]
> > > while(1)
> > > {
> > > 	...
> > > 	break; //otherwise return would come here.
> > > 	...
> > > 	break;
> > > }
> > > 
> > > return ...;
> > 
> > I think `switch (0) default:` is better, because it's not a loop so
> > the intent is clear - no continue statements somewhere below (so
> > it's also better than `do ... while (0);`). Also you might forget
> > the final break statement with `while` and get an infinite loop.
> > 
> `do ... while (0);` and also the loop above are abominations. They are for goto hypocrits, i.e. people who think that a goto when it is not named goto but works exactly like a goto is something better (the Voldemort goto).

+1.  D (and C/C++) has a 'goto' keyword for a reason.  It's stupid to try to avoid it like a taboo keyword when it's what the code actually *means*.  Just because you write it with "more acceptable" constructs does not change the fact that the code is essentially doing a goto.

Not to mention the fact that modern-day `goto` statements are nowhere near as powerful (nor as evil) as the original goto, which was program-wide (and sometimes even more than that, before the days of protected mode and process isolation :-P), and could jump from anywhere to literally anywhere else, including the middle of another construct. Modern-day `goto`s are far tamer, and not overly hard to reason about provided you don't abuse them for stuff that could be better-written with other constructs.


> The breaks above and in are GOTOS, no point in obfuscating them. Sorry if I'm a little bit inflammatory about these constructs, but I have to work with code written by a `do {} while(0)` champion and I can tell you, it's the horror when you have to make changes.

I've had to work with code that had multiply-nested #define macros involving `do {} while(0)`, and have hated every minute of it.


> It was so bad that I finally used  __attribute__((__cleanup__(x))) gcc
> extension to implement something resembling D's scope(exit) so that
> I'm sure that the code doesn't leak like it did before.

Ouch.


T

-- 
"I suspect the best way to deal with procrastination is to put off the procrastination itself until later. I've been meaning to try this, but haven't gotten around to it yet. " -- swr
October 05, 2018
On Tuesday, October 2, 2018 12:14:55 PM MDT Andrei Alexandrescu via Digitalmars-d wrote:
> Kate Gregory makes a good argument on something I've often commented in code reviews: https://youtu.be/n0Ak6xtVXno?t=2682

It's one of those things that I would have thought would just be obvious with experience, but if nothing else, some folks still try to stick to the whole "single return" idea even though I think that most folks agree at this point that it causes more problems than it solves.

Certainly, if you try to do it both ways, it shouldn't take long to see exactly what she shows in your own code.

- Jonathan M Davis



October 05, 2018
H. S. Teoh <hsteoh@quickfur.ath.cx> wrote:
> I've had to work with code that had multiply-nested #define macros involving `do {} while(0)`, and have hated every minute of it.

Yes it's ugly but it's also the only way to define a multi-statement macro that can be used like a function.

---
Tobias
October 06, 2018
On Friday, 5 October 2018 at 19:04:26 UTC, Nick Sabalausky (Abscissa) wrote:
> On 10/04/2018 11:40 PM, rikki cattermole wrote:
>> [...]
>
> It's not *my* statement about newer/older. If you recall the programming atmosphere around 2000, OO was widely being touted as a newer thing, superior to "old-fashioned" imperative, even though there's a million things about that whole assessment that are false (not the least of which being the at-the-time popular notion that Java-style OO somehow wasn't still imperative, or, as you pointed out, that OO was a new invention).
>
> There's one minor aspect of it that was true though: Widespread popularity of OO was certainly a new thing, even if OO itself wasn't.

The hype was hight also in the 90...

I remember having used (in production!) a 3rd party  extension to Clipper (I don't remember if Summer 87, or 5.0.x) that added OO to the language!

0__o

/Paolo
October 06, 2018
On Saturday, 6 October 2018 at 05:36:59 UTC, Paolo Invernizzi wrote:
> On Friday, 5 October 2018 at 19:04:26 UTC, Nick Sabalausky (Abscissa) wrote:
>> On 10/04/2018 11:40 PM, rikki cattermole wrote:
>>> [...]
>>
>> It's not *my* statement about newer/older. If you recall the programming atmosphere around 2000, OO was widely being touted as a newer thing, superior to "old-fashioned" imperative, even though there's a million things about that whole assessment that are false (not the least of which being the at-the-time popular notion that Java-style OO somehow wasn't still imperative, or, as you pointed out, that OO was a new invention).
>>
>> There's one minor aspect of it that was true though: Widespread popularity of OO was certainly a new thing, even if OO itself wasn't.
>
> The hype was hight also in the 90...
>
> I remember having used (in production!) a 3rd party  extension to Clipper (I don't remember if Summer 87, or 5.0.x) that added OO to the language!
>
In the 90s I used to add the C preprocessor to other languages which lacked efficient constant definition (i.e. compile time constructs). AutoLISP, the LISP dialect used to write application in AutoCAD. There were nearly a 100 of small programs in different files and throughout the whole project there were a lot repetitions that could not be factorized with AutoCAD means. Include, define and ifdef allowed to do things, that were very difficult to do at that time (it was on AutoCAD v9.0 which had only 64K memory for the LISP code).
I also added the C preprocessor to the DBASE III and the compatible MS-DOS based Foxbase.