- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Am I the only one (maybe missing prior post) that sees this flaw with the for (;;) construct:
for (int I = 0; I < StupidSlowUpperLimit(); ++I) {
// Stuff
};
At least in Pascal
FOR I := 0 TO StupidSlowUpperLimit() DO BEGIN
END;
you are guaranteed the limits are only evaluated once on entry. The same applies to the code in this post (although that is its only redeeming feature).
What C and C-like languages need is a proper "loop <statement>" statement like (?Pascal) Modula-2's LOOP ... END; and then use break to leave the loop whenever we need to. I think "foreach <ident> in <generator> ..." is the way forward. The for (;;) construct is simply an artefact of when computers were slow, compilers were dumb and C was just a refined version of a macro assembler.
Admin
Damn, it should say (and does on my screen)
</generator></ident></statement> for (int I = 0; I < StupidSlowUpperLimit(); ++I) {
// Stuff
};
Admin
You could just assign StupidSlowUpperLimit() to a variable and use that variable as the upper limit of the loop to accomplish the same thing...
If you want to do that, just use while(true){} and then break; whenever you decide you want to break out of the loop.
Admin
I don't know that I would necessarily take that as a guarantee.
I could have sworn that C and C++ had a "loop" construct:
do
{
:
.
} while(!false);
or just simply
while(!false)
{
:
.
}
A bit more on the guarantee:
If there truely is a guarantee (and there may be, I don't know, I don't have the spec for pascal in front of me), What if a situation arises where StupidSlowFunction() needs to be checked on each iteration of the loop? What do you do then?
Others have said it, the for(;;) construct is very powerful. Just remember it's basically like an initialiser, a while loop and statement all wrapped into one.
</generator></ident></statement>
Admin
Jonas is right! Once you've used "foreach var in list", (I'm using it in Perl.), having to each time manually create the increment and test of a traditional C 'for' loop seems as silly as being forced to write '5.2 + int_to_float( 3);' instead of '5.2 + 3'. It;'s drudgery -- let the computer do it!
While creating a whole new dependency for all your code, plus the fact the each person who sees this code is going to have to get over a WTF moment, makes this a bad decision, I think this programmer saw that a useful syntax was missing, and decided to try to supply it.
Also, I gotta say that encapsulating this in a class instead of a macro is a good idea. Macros that make multiple use of their arguments being passed code fragments with side effects is a well-known and irritating gotcha. This approach protects you for this.
Admin
Nope. I see it as int i=1 is the start condition, i<=4 is the continuation condition, and i++ is the incremental condition. But that would mean you understand what the for loop was truly designed for! Programming is all about being able to wrap your head around constructs and the unique syntax of the language, not to force it to do something it wasn't designed to do. I bet you've never used a language like Ocaml where there are no loops, they're all recursions! Or MatLab, which doesn't use loops at all, but arrays (and you can apply boolean conditions to these arrays). Good luck with Prolog! Go back to using VB if you can't handle a simple for loop or even a foreach loop.
Admin
C Pound?
Admin
A Joke. A reference to some post made way in the past, before the advent of horrible forum software. Back in the good ol' days.
Admin
Man, you must be joking, did you read the post at all? it was clearly meant in a perceptual filtering sense. The guy is talking about expressiveness, not idioms.
Admin
Charles Nadolski: "Nope. I see it as int i=1 is the start condition, i<=4 is the continuation condition, and i++ is the incremental condition."
Yep - and the problem is if it got mistyped as
(int i=1;l<=4;i++)
(and that managed to compile), you'd probably still see the same, because you know what it should be.
"Programming is all about being able to wrap your head around constructs and the unique syntax of the language, not to force it to do something it wasn't designed to do."
Certainly. But it's also about attempting to minimise errors. The C-style for-loop construct is marvellously general - the language has no need for the while() {} construct at all. But if within the language (which language? - OK, say C++), there existed a "foreach(x; 1:4)" type loop construct, and the generalised for(;;) construct was used only for those cases that that didn't match, then I'd expect a reduction in the number of bugs.
Admin
<font face="Tahoma" size="2">From http://www.codeproject.com/useritems/ForCSharp.asp
"For such a simple counting function, the for loop is a bit of overkill syntacticly. The problem is that this syntax is a roach point. What is a roach? A roach is a bug that recurs often. A roach point, is a place that roaches breed. Developers moving into C# from other languages very often make mistakes in writing this function. Instead of i <= 5, they write i = 5, or i < 5. A simple mistake, but a very common one. Another common mistake is this - lets use a 0 based loop. 0 to 4 - quick - what changes need to be made to count from 0 to 4? Did you have to think about this at all? If so - poof theres room for a roach."
OK, what fucknut decides to call something a "roach point?" WTF?
</font>
Admin
and the main(I think) author of the Indy Project, wich is pretty good stuff... Though still coded Delphi Style. Actually it is Delphi.
Admin
Of course, it's worth knowing that there's a bunch of people who've used this technique in Perl to allow you to write your Perl programs in Latin.
As it says on the website: "If you have to ask why, then the answer probably won't make any sense to you either." :D
(just so you know, it's at http://search.cpan.org/~dconway/Lingua-Romana-Perligata-0.50/lib/Lingua/Romana/Perligata.pm )
Admin
I wonder how much of it is a joke and how much is serious. There really is some amazing depth in that work.
Admin
Someone who has smoked too much wacky-weed and thinks about nothing else but what's in his ashtray?
Admin
It's short for "cockroaches" which are tough bugs to kill. Just when you think you got the last one, a few more cockroaches crawl out of the cracks.
Admin
Nothing wrong with the idea. The implementation is more complex than it needs to be, and is a good example of overusing objects, but the concept is fine. Idealy, a language would support a foreach-style for the 90% of code where array iteration is what you want, and a for-style for the last 10% where you need the extra flexibility.
In fact, a language that fully supports foreach and a simple list-building construct can be more efficient. That's because you give the compiler more information about what you're trying to do. Loop unrolling optimization would be far easier with foreach than for.
This is simply how new programming languages are developed--i.e., anaylize what common tasks are being done in current languages, and make them easier. Array iteration is a very common task, so creating syntax to make it easier is an advancement of a language in general. This is also why we have things like garbage collection in modern implementations.
Of course, the orginal code posted wouldn't be optimized very well without hooking into a the compiler. That ammount of effort probably wouldn't be worth it.
Admin
Big sigh. This programmer should be taken out back and flogged, shot and dismembered [:P] This is unacceptable code, if you have a problem with a language's specific format, use another one. I know 6 or 7 languages and I would never imagine using something like that to get around a for loop!
Admin
My theory on this is that the progrmmer want to learn about writing an IEnumerator class, and chose a project the was a bit different than the obvious (and already written) iterating through a collection.
Admin
Perhaps it's unbelievably slow because their code uses generics, iterators, and anonymous delegates instead of a simple for loop?
Admin
Perhaps it's unbelievably slow because their code uses generics, iterators, and anonymous delegates instead of a simple for loop?
Admin
You mean you wouldn't catch that running your unit tests?
umm... you are writing unit tests right?
Admin
Wow... who let this guy write C#? Is no one in his office saying "WTF"? Not even his boss?
Admin
I Love the summary comment... fantastic... hahahaha
Admin
Yes, of course one should write unit tests to work around the failings of the language itself. (Or asserts, if you're very confident of your looping skillz.) But you've never seen a PHP or Perl programmer (aside from language devs) waste time writing unit tests around every damned loop on the off chance that maybe, just maybe, this time foreach will mysteriously fail from comparing against l or I or j instead of i.
Of course for loops have their uses. Why are any of you even arguing that need them, this should be self-evident. They aren't going away because they're far too widely used and too versitile to ever be useless; but here's the important part, language design is not a zero-sum game - you can have more than one looping construct, and it won't blow the compiler's mind. Well, unless it's made by Borland.
Hey Chuck, I pity your code-scanning skills if every time you see a for loop you have to sit down and analyze what operation is being performed each iteration and what operation is done to test it, then mentally compile and execute the entire loop to see what you end up with. Hope your employer pays you for that. The sad part is that the language forces us to do that every time we write a normal for loop, not just you "special needs" programmers.
Also there's no such thing as "incremental condition". That's just the grab bag, moreso than the rest, the fact that it's usually just an increment is convention. Or would the perfectly legal (with a suitable backend) i.deleteLastNode() as the final condition also constitute an "increment"?
Admin
No, no, no. That's far from generic. It has a hell of a lot of baggage in it. In particular, it couples too tightly the iteration logic with the things to be done in each iteration.
What do I regard as a generic iteration mechanism? Well, iteration involves (a) a set of things to be iterated over, (b) an order in which the iteration happens, (c) the thing that is done in each iteration, and (d) the way the iterations contribute to the overall result. The set of things may be numbers, or it may be nodes of a tree. The order may be the normal integer succession, or it may be the preorder of the nodes of a tree. The thing to be done varies endlessly; that's why we have loop bodies, after all. The ways the iterations contribute to the result are many: sometime we want to produce another similar collection of elements, where each element in the result is "mapped" to a result indpendently; other times we want to collapse (or "fold") a collection down to some result value which depends on all of the elements.
Languages that provide what I call a proper abstraction here separate all of these things. Instead of writing a loop to sum the elements of an array or to multiply each by a constant, you fold a sequence with the plus operator, or map a constant multiplication function over it. Have to do the same over a tree instead of an array? No problem, just say what order you want (preorder, postorder, inorder).
Admin
I've always wondered why unit test-evangelists fail to realise that they can't catch every bug ("testing can only show the prescence of bugs, not their absence", Dijkstra). Furthermore, it's always better to catch bugs by design than by testing, its faster, easier, and cheaper. Plus, the result will be more intelligible.
In the above example: the i=something could be some complex assignement (instead of a complex test) that would only lead to an infinite loop for very special cases of something.
Admin
I can see from many of the posts that there is a widespread belief that if it is not part of the language, then you shouldn't do it, you should change language.
Leaving aside the fact that in many projects this would not be feasible for a number of reasons, am I the only one here to think that if you can make the language more readable and usable then you should do it?
On the other side I see appreciation for the idioms of the language, which are seen as being superior to any possible change. Unfortunately these idioms -IMO- while powerful, often make for less readable code.
What do you guys think? Which side are you on? and why?
Admin
I don't think (and most agree here if I'm right) that the code doesn't offer any value over the "for (int i ... i++)" syntax, and in it's current form shouldn't be used in production code to prevent, but it's a nice and simple example on how to implement IEnumerable, and definately not a WTF.
Admin
BTW, WTF is there an edit button above my posts if I can't edit it because it has to be edited within 5 ms after posting?
Admin
This isn't a real WTF. The biggest wtf with this is actually the naming. ForTo doesn't specify the functionality. Range is a much better name. Also, this code becomes bloated because it isn't using C# 2.0. Here is the same functionality in C# 2.0.
Much more readable, and less error prone. The speed is about 1/10 of an ordinary for loop, which isn't the best but unless speed is really critical it shouldn't matter.
Using c# 2.0 I have come to rely more on iterators and the yield syntax. They can seriously improve code readability and are easy to write correctly. Personally I prefer using the for loop, but I have no problem at all reading the foreach variant and people calling this a wtf are seriously shortminded. As some people have shown, doing this bears a striking resemblance to Python syntax and several other languages have similar constructs.
The real wtf in pascal.h is that keywords are redefined which doesn't actually add anything useful. Syntax sugar must do more than change words to be useful. A Range iterator provides functionality in that it hides comparisons as well as increments. That is useful syntactic sugar unlike replacing { with begin.
Admin
If anything is wtf, it is this forums preview. It should be removed since it doesn't actually show the previewed message. Ok, second try, code only
public class Series { public static IEnumerable<int> Range(int start, int stop) { return Range(start, stop, 1); }
} .. foreach(int i in Series.Range(9,18,3)) ..
Admin
OK.
I can't comment any further on the code. However, why are people calling it C-Pound?
It's C Sharp. C#.
C Pound would be C£.
Please remember that not everyone lives in the USA.
Admin
http://www.thedailywtf.com/forums/25129/ShowPost.aspx
Admin
I think it would be best that you remember not everyone lives in a country where the currency is based on the british pound. Anywhere else in the world, and I'm reasonably certain that even in jolly old England, there is a # on your telephones, which is called the pound sign.
As for calling it C-Pound, as has been explained elsewhere in this WTF, it's a stab at hackjob programmers who don't know the proper name for the language, although as has also been mentioned, I move that we instead call it D-flat.
Admin
Yes, there is a # sign on UK phones, but nobody here calls in a "pound sign". Most people call it a "hash" (although for some reason BT's recorded messages call it "the square key.")
To allow everyone to be equally confused, I propose that C# be read as "C octothorpe" :-P
Admin
Recursion is a pretty damn general 'loop construct' too, rather more general than for() is in fact, yet even a rabid Schemer like me would be hard put to argue that recursion is clearer than a specialized iterative construct in all cases (in Scheme. it usually is, as well as in the majority of FP and Logic languages, but those languages were designed for clear expression of recursive idioms). As you point out yourself, certain constructs are common enough that a specialized construct is justified; indeed, if you are familiar you with such reducto ad absurdum languages as Unlambda or OISC, then you know that every construct is a special-purpose one - there is always some way of deriving any construct from some other primitive, and for any given primitive there are other equally primitive constructs which it can be duplicated with. In any practical language, you have make some arbitrary choices as to which primitives to support (though as you can guess, I personally prefer languages where it is possible to define first-class user syntax constructs with a minimum of fuss).
Where was I going with this, anyway? Oh, never mind. Consider it just something to reflect upon in an idle moment later.
Admin
Ah... get it now! What a stunning candidate.
I spent some time in America last year and you can imagine my surprise the first time I heard an automated switchboard ask callers to press the "pound key". WTF?
I had no idea until that point that you guys called the # (hash) symbol "pound". Strange - I wonder how it came about.
It's a bit like calling the @ symbol "dollar".
Admin
Using while(true){} assumes the compiler will optimize out the redundant check at each step, and assumptions about optimization strategies are bad. In fact you can use for(;;) {} instead. Oh, and don't forget:
start:
if (condition) goto end;
goto start;
end:
0;
We need the 0 here since C does not allow a label by itself at the end of a block, (well GCC anyway). Let's hope the compiler optimizes it out, right?
Also assigning StupidSlowUpperLimit() to a variable forces it to be stored in a variable somewhere, ruining optimization strategies, as well as the automatic decision regarding what type of variable to store the limit in. Finally it is still a means of emulating a language feature that C is missing.
On the otherhand, to have a for(;;) {} in a language like Modula-2
for (<init>; <condition>; <post>) <body>;
becomes
<init>;
LOOP IF NOT <condition> THEN EXIT END;
<body>;
<post>;
END;
And don't say anything about the scope of variables in the <init> code since it isn't really standardized properly anyway. Nothing that a VAR BEGIN END won't solve anyway.
I have always disliked the C syntax, and think is extremely stupid (and typical of the computer industry) to continue to use it in languages like Java and C#.
Admin
Apparently, it was once popular as an abbrevation for "pound" (as in weight)
e.g " 5 # @ .30/#...... $1.50"
However, I believe this usage peaked in the 19th Century (when everything was hand written, and therefore you looked for as many abbreviations as possible)