> return immer nur am Ende einer C-funktion.
Macht oft den Code unnötig kompliziert. Ich prüfe oft am Anfang einer
Funktion die Vorbedingungen ab und kehre dann ggf. direkt mit einem
return zurück. Warum soll ich da den gesamten Funktionsinhalt in eine
Verschachtelung aus mehreren ifs stecken?
Was sieht einfacher übersichtlicher aus:
[C
file_id file_create(const char* name)
{
file_id ret;
if (name != NULL)
{
if (!file_id_pool_full())
{
if (!file_exists(name))
{
if (can_create(name))
{
// ok, create the file
ret = ...
}
else
{
ret = -1;
}
}
else
{
ret = -2;
}
}
else
{
ret = -3;
}
}
else
{
ret = -4;
}
return ret;
}
[/C]
oder
1 | file_id file_create(const char* name)
|
2 | {
|
3 | // check all the preconditions
|
4 |
|
5 | if (name == NULL)
|
6 | return -4;
|
7 |
|
8 | if (file_id_pool_full())
|
9 | return -3;
|
10 |
|
11 | if (file_exists(name))
|
12 | return -2;
|
13 |
|
14 | if (!can_create(name))
|
15 | return -1;
|
16 |
|
17 | // ok, create the file
|
18 | return ...
|
19 | }
|
> Dieses versteckte return wird dann einfach übersehen.
Man könnte auch argumentieren, daß die Funktion zu lang bzw. zu komplex
ist, wenn die returns dadurch so versteckt werden, daß man sie übersehen
kann.
> Returns vor dem Funktionsende sind (ähnlich wie Breaks und Continues)
> getarnte und und in ihren Möglichkeiten eingeschränkte Verianten des
> Gotos.
> in Zeiten der objektorientierten Programmierung ist der Ausstieg z.B.
> über Exceptions sogar durchaus üblich.
Die sind in der Hinsicht eigentlich schlimmer als goto, da sie nicht nur
direkt in der aktuellen Funktion selbst, sondern auch irgendwo anders in
einer aufgerufenen Funktion geworfen werden können und entsprechend auch
in irgendeinem Aufrufer gefangen werden können. Beim goto stehen Start
und Ziel des Sprungs wenigstens in der selben Funktion, und sie sind zur
Compilezeit festgelegt.