![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
"nemesis" <nam### [at] gmail com> wrote:
> Orchid XP v8 <voi### [at] dev null> wrote:
> > Oh wow. 42 years later, it still exists:
> >
> > http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF
> >
> > "Go to considered harmful."
>
> a classic! I'm glad you've been interested in the evolution of programming
> formalisms -- and all by yourself! Next on, the lambda papers! ;)
>
> > I also note, with some interest, what looks suspiciously like Haskell
> > syntax, in a letter typed 42 years ago. Obviously it's not after
> > Haskell, but rather whatever mathematical formalism Haskell borrowed the
> > notation from. Still, interesting none the less...)
>
> bwahahahaha
>
> you must be talking about `conditional expressions as introduced by J.McCarthy
> ("B1 -> E1, B2 -> E2,....., Bn -> En")'... although it looks like currying
> haskell notation, it's actually what it's told: John McCarthy's conditional
> expressions for Lisp!
>
> (cond
> ((null? ls) 0)
> ((zero? (car ls)) 0)
> (#t (/ n (car ls))))
>
> cond was blowderized and adapted to all other programming languages in the
> simplified form if-then-else... even Lisp provides it as well as cond!
in other words: "I am your father!" :D
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Orchid XP v8 <voi### [at] dev null> wrote:
> "Go to considered harmful."
Some people go to (pun semi-intended) extremes with the structured
programming paradigm and have the firm stance that anything even resembling
'goto' should be avoided, such as 'break', 'continue' and early returns
(iow. the only 'return' that a function can have is at the end of the
function, nowhere else). Likewise no "fall-through" in switch-case blocks
in languages like C (although this has less to do with goto-like statements
and more to do with structured programming).
Sometimes this principle is good and leads in a natural way to imperative
code that is cleaner, simpler and easier to read. Othertimes, however, it
leads to the contrary. My favorite example is this (C++-like code, but the
same could be written in any imperative language supporting early returns):
Value* MyClass::searchForValue(const Value& value)
{
for(size_t x = 0; x < mValues.size(); ++x)
for(size_t y = 0; y < mValues[x].size(); ++y)
for(size_t z = 0; z < mValues[x][y].size(); ++z)
if(mValues[x][y][z] == value)
return &mValues[x][y][z];
return 0;
}
If you want to avoid the early return in that function, you have to
jump through quite many hoops, all of which make the code more complicated,
without making it any more readable.
As a personal preference, I also prefer writing code like this:
int someFunction(param1, param2, param3)
{
if(param1_is_not_ok) return error_code1;
some_code; // code needed to see if param2 is ok
if(param2_is_not_ok) return error_code2;
more_code; // needed to see if param3 is ok
if(param3_is_not_ok) return error_code3;
significant_amount_of_code;
return ok_code;
}
Even though it could perfectly well be written without the early returns:
int someFunction(param1, param2, param3)
{
int retval = ok_code;
if(param1_is_not_ok) retval = error_code1;
else
{
some_code; // code needed to see if param2 is ok
if(param2_is_not_ok) retval = error_code2;
else
{
more_code; // needed to see if param3 is ok
if(param3_is_not_ok) retval = error_code3;
else
{
significant_amount_of_code;
}
}
}
return retval;
}
The more such error situations there could be, the more indentation the
code would require which is not only inconvenient but also IMO makes the
code less readable. (After all, in my preferred form all the error checking
is nicely at the same indentation level, rather than each subsequent check
being indented more than the previous.)
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> "Go to considered harmful."
>
> I must say, I love how steampunk he sounds.
With a name like "Edsger W. Dijkstra", I'm guessing English isn't his
first language.
>> Well there we are. I have to say, not the most convincing description
>> of the problem I've ever seen.
>
> It's the difference between programming and computer science, is all.
> Plus, you probably grew up after things like while statements and if
> statements with actual bodies were common. Where do you think that came
> from? :-)
I don't pretend to know much about history. It just seems fairly
self-evident that having formally organised stuff makes it easier to
comprehend than unorganised stuff. Hell, if you said that phrase to
somebody who knows nothing about computers, they'd probably agree with you.
> Did you look at that link I posted about the semantics of programming
> langauges?
When?
--
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Orchid XP v8 wrote:
>>> "Go to considered harmful."
>>
>> I must say, I love how steampunk he sounds.
>
> With a name like "Edsger W. Dijkstra", I'm guessing English isn't his
> first language.
Yes, I had considered that as well. He still gives a lovely victorian
wording to high-tech building-automated-machinery, hence my observation.
> I don't pretend to know much about history. It just seems fairly
> self-evident that having formally organised stuff makes it easier to
> comprehend than unorganised stuff.
Dijkstra is one of the few who figured out what "formally organized" means
for imperative computer programs. He's the one who figured out how you can
look at a program and say "this one will be easy to understand because it is
well organized, and that one will be difficult because it is not well
organized." Indeed, "formally organized" is what he's defining in that paper.
>> Did you look at that link I posted about the semantics of programming
>> langauges?
>
> When?
Probably a couple weeks back. Let me see if I can find it again.
Ah. There.
http://web.archive.org/web/20040410154109/cs.wwc.edu/~aabyan/PLBook/HTML/Semantics.html
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
There's really one primary problem with early returns, and that's handling
things that ought be handled before the function returns, like deallocating
memory, closing files, logging, etc. In a decent language like C++, there's
invisible bits of code stuck into your object code before each return (or,
alternately, the compiler rewrites the return statement to be a goto to the
end of the function). Without that, it requires somewhat more code to return
early *and* clean up, to the point where skipping over blocks with flags
might be more clear and maintainable than duplicating clean-up code.
Especially if you want to DRY on the cleanup code.
Someone way back proved you could turn *any* control flow into structured
flow, with enough booleans and repeated code. That doesn't mean it's a good
idea.
And of course, this is all local to a fairly small function. Think about a
program with significant amounts of control flow using setjmp/longjmp, or
where gotos can go to any label anywhere in a program, and you get the idea
of what Dr D was arguing against.
It turns out that what's really formally the problem is more the labels than
the gotos. The problem is if you look at the preconditions of the label,
it's an amalgamation of all the postconditions of every goto that goes to
that label. You can't look at the line before the label and the line after
the label and know *anything* about any of the variables or program state
when you reach the line after the label, unless you hunt down and analyze
every goto as well.
> Likewise no "fall-through" in switch-case blocks in languages like C
I like how C# handles this. Each branch has to end with either a break or a
goto X, where X is one of the labels of the switch. So you can rearrange the
order of the branches, insert branches in the middle, etc, and not break
anything. And you can't accidentally fall through to the next case and bring
down the entire east coast telecommunication infrastructure. ;-)
> The more such error situations there could be, the more indentation the
> code would require which is not only inconvenient but also IMO makes the
> code less readable.
I find another way of doing this also works. My own invention:
bool worked = true;
if (worked) worked = try_thing_one();
if (worked) { reset_flobulator(); worked = query_flobulator(); }
if (worked) worked = yidda < 27;
clean_up_temps();
return worked;
and so on. Each block of work can be rearranged, nothing runs and it falls
out very quickly on failure, everything inline, everything's indented only
one, yet it's pretty easy to follow what's going on. And of course if you
want specific error codes, that works just as easily.
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
nemesis wrote:
> Darren New <dne### [at] san rr com> wrote:
>> andrel wrote:
>>> at least three or four different languages.
>> Noting that C, C++, C#, Java, and Pascal are all "the same language" for
>> these purposes. ;-)
>
> they are all Algol.
Basically, yes. Altho I'd say OO, and maybe some of the stuff in Ada are
things you should know about algol-like languages.
You should also learn APL, LISP, Prolog, Erlang, Eiffel, and some machine code.
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> nemesis wrote:
> > Darren New <dne### [at] san rr com> wrote:
> >> andrel wrote:
> >>> at least three or four different languages.
> >> Noting that C, C++, C#, Java, and Pascal are all "the same language" for
> >> these purposes. ;-)
> >
> > they are all Algol.
>
> Basically, yes. Altho I'd say OO, and maybe some of the stuff in Ada are
> things you should know about algol-like languages.
>
> You should also learn APL, LISP, Prolog, Erlang, Eiffel, and some machine code.
I'd put Perl and Haskell into the mix too.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
nemesis wrote:
> Darren New <dne### [at] san rr com> wrote:
>> nemesis wrote:
>>> Darren New <dne### [at] san rr com> wrote:
>>>> andrel wrote:
>>>>> at least three or four different languages.
>>>> Noting that C, C++, C#, Java, and Pascal are all "the same language" for
>>>> these purposes. ;-)
>>> they are all Algol.
>> Basically, yes. Altho I'd say OO, and maybe some of the stuff in Ada are
>> things you should know about algol-like languages.
>>
>> You should also learn APL, LISP, Prolog, Erlang, Eiffel, and some machine code.
>
> I'd put Perl and Haskell into the mix too.
Yeah, I was trying to remember some of the others. Something perl-like,
certanily (python, Perl, bash, Tcl, etc). FORTH. Haskell or some other
very functional language, for sure.
The thing about APL, LISP, FORTH, and Tcl is they're all simple enough that
once you have a few under your belt, you can learn them well enough to
understand the principles rather easily, even if it's not obvious the best
way to write large programs. Of course, writing large programs is where
having the alternate paradigms can shine (or collapse), so that might not be
a recommendation there.
--
Darren New, San Diego CA, USA (PST)
Serving Suggestion:
"Don't serve this any more. It's awful."
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 10/15/2010 7:51 PM, nemesis wrote:
> Orchid XP v8<voi### [at] dev null> wrote:
>> Oh wow. 42 years later, it still exists:
>>
>> http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF
>>
>> "Go to considered harmful."
>
> a classic! I'm glad you've been interested in the evolution of programming
> formalisms -- and all by yourself! Next on, the lambda papers! ;)
>
>> I also note, with some interest, what looks suspiciously like Haskell
>> syntax, in a letter typed 42 years ago. Obviously it's not after
>> Haskell, but rather whatever mathematical formalism Haskell borrowed the
>> notation from. Still, interesting none the less...)
>
> bwahahahaha
>
> you must be talking about `conditional expressions as introduced by J.McCarthy
> ("B1 -> E1, B2 -> E2,....., Bn -> En")'... although it looks like currying
> haskell notation, it's actually what it's told: John McCarthy's conditional
> expressions for Lisp!
>
> (cond
> ((null? ls) 0)
> ((zero? (car ls)) 0)
> (#t (/ n (car ls))))
>
> cond was blowderized and adapted to all other programming languages in the
> simplified form if-then-else... even Lisp provides it as well as cond!
>
>
Snort.. While the above is slightly annoying (though only due to the
fact that I prefer a syntax which is marginally clearer, if only just..,
claiming that if-then-else is simpler is just flat wrong. Lot of extra
typing to get you where you are going, when something closer to the
original, like one languages 'switch' statement makes a lot more sense.
But, it only gets worse when some joker does what was done in a few
versions of basic (Apple Basic being one of them), and lost the else, or
denied use of more than one else, by disallowing 'else if', etc.
Definitely times when I seriously *hate* if-then-else, even if the
result is, theoretically, the same.
--
void main () {
if version = "Vista" {
call slow_by_half();
call DRM_everything();
}
call functional_code();
}
else
call crash_windows();
}
<A HREF='http://www.daz3d.com/index.php?refid=16130551'>Get 3D Models,
3D Content, and 3D Software at DAZ3D!</A>
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> There's really one primary problem with early returns, and that's handling
> things that ought be handled before the function returns, like deallocating
> memory, closing files, logging, etc. In a decent language like C++, there's
> invisible bits of code stuck into your object code before each return (or,
> alternately, the compiler rewrites the return statement to be a goto to the
> end of the function). Without that, it requires somewhat more code to return
> early *and* clean up, to the point where skipping over blocks with flags
> might be more clear and maintainable than duplicating clean-up code.
> Especially if you want to DRY on the cleanup code.
Maybe the fact that C++ basically removed the need for manual cleanup of
resources (if you use its constructs properly) made it much safer and
cleaner to use early returns. Early returns would indeed be a hazard in C,
where there's no automatic scope-based cleanup mechanism.
It's not just memory. It's anything that needs to be released after use,
such as for example file handles. In C++ it's completely safe to do things
like:
void foo()
{
std::ifstram is("file.txt");
do_something;
if(error) return;
do_something_else;
if(another_error) return;
do_more;
}
There's no need to clean up 'is' (ie. close the file handle) because it
will clean up itself when its scope ends. This is not possible in C (where
you always have to manually make sure it gets closed when the function is
exited).
(This is actually important because in C++ the function might be exited
at surprising places, even without explicit early returns, namely if
something throws an exception. The above code is exception-safe because
the file will be closed even if anything inside the function unexpectedly
throws.)
If you see something like this in C++:
void foo()
{
FILE* infile = std::fopen("file.txt", "r");
then you should immediately see "DANGER! DANGER!", because whatever follows
that will *not* be exception-safe (well, not unless the very next line is
'try').
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |