Post #83,103
2/21/03 12:42:42 AM
|
Programming algorithms, switch() and Perl.
There's something a little off I've noticed amongst programmers who know Perl well and then do extensive work in other languages. It's probably not their only sin, but it's the one I've noticed. It's the tendancy to use if( ) { ... } elseif( ) { ... } elseif ( ) { ... } else { ... } instead of switch( ) { case ...: ...; break; case ...: ...; break; case ...: ...; break; default: ...; } Why is this? I've known for a while that Perl doesn't have a switch() statement. The traditional explanation given for this is because you can synthesize one in a number of ways. I think that's rubbish. Perl prides itself on offering More Than One Way To Do It which makes the absence of switch() look like a personal quirk. Fortunately, Larry Wall gives [link|http://dev.perl.org/perl6/apocalypse/4#rfc 022: control flow: builtin switch statement|two much better explanations]: a) he didn't like the names "switch" and "case" and b) he and other Perlers wanted something that was Really Good rather than Merely Adequate. So Perl 6 will finally get a switch() structure (called given, BTW) but one so typically Perl that it can also be used for a new type of funky loop as well as for exception handling. Of course this won't solve the problem of (ahem) inexperienced programmers who need to read their language docs a little more closely but it should begin to temper Perl-programmers who forget that other languages can and do have things Perl doesn't. Wade, who wasn't sure he could make enough out of this for A Static Page.
Is it enough to love Is it enough to breathe Somebody rip my heart out And leave me here to bleed
| | Is it enough to die Somebody save my life I'd rather be Anything but Ordinary Please
| -- "Anything but Ordinary" by Avril Lavigne. |
|
Post #83,133
2/21/03 9:02:32 AM
|
well its not perl
I started with csh as my first language and learned case statements etc when I used xbase. So shell scripters would also be guilty of if elseif thanx, bill
will work for cash and other incentives [link|http://home.tampabay.rr.com/boxley/resume/Resume.html|skill set]
questions, help? [link|mailto:pappas@catholic.org|email pappas at catholic.org] \ufffdOmni Gaul Delenda est!\ufffd Ceasar
|
Post #83,371
2/22/03 5:04:33 AM
|
That's a point.
Because bash has it.
Wade.
Is it enough to love Is it enough to breathe Somebody rip my heart out And leave me here to bleed
| | Is it enough to die Somebody save my life I'd rather be Anything but Ordinary Please
| -- "Anything but Ordinary" by Avril Lavigne. |
|
Post #83,154
2/21/03 10:22:36 AM
|
What's the diff? If it needs a "break", it's just as stupid!
|
Post #83,159
2/21/03 10:40:14 AM
|
The difference is ...
In the switch statement, you'll notice the conditional only appears once. Then you can branch an arbitrary number of times based on the results. With the if..else statements you have to re-evaluate the conditional each time. If the conditional is a function with any significant overhead you're screwed.
You could simulate this by saving the result of the conditional to a variable and using this variable in your if statements. TIMTOWTDI ;)
===
Implicitly condoning stupidity since 2001.
|
Post #83,163
2/21/03 10:49:24 AM
|
Right, slight assembler efficiency gain.
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #83,161
2/21/03 10:47:57 AM
|
Re: What's the diff?
There are some things you can do with switch that you can't as easily (arguably) do with if/then: \nswitch (foo) {\ncase 1:\n /* something for 1 */\ncase 4:\n /* something for 1 and 4 */\n break;\ncase 2:\n /* something for 2 */\ncase 3:\n /* something for 2 and 3 */\n break;\ndefault:\n /* something for other things */\n}\n\nvs.\n\nif (foo == 4 || foo == 1) {\n /* something for 1 and 4 */\n if (foo == 1) {\n /* something for 1 */\n }\n} else if (foo == 2 || foo == 3) {\n /* something for 2 and 3 */\n if (foo == 3) {\n /* something for 3 */\n }\n} else {\n /* something for everyone else */\n}\n The switch is easier to read (IMO) but can get a bit confusing with the drop-throughs if you don't understand (or overlook) the break placements. Comments are encouraged when using that technique. ;-) But then again, in C you can only use ints in the switch test, so if/then has the added flexibility of arbitrary tests. Having said that, Python only has if/then as well, but IMO it's as easy to read as a switch statement because of the tabs-for-blocks paradigm: \nif foo == 1 or foo == 4:\n print "something for 1 and 4"\n if foo == 1: print "something for 1"\nelif foo == 2 or foo == 3:\n print "something for 2 and 3"\n if foo == 3: print "something for 3"\nelse:\n print "something else"\n\nor slightly more explicitly:\n\nif foo == 1 or foo == 4:\n print "something for 1 and 4"\n if foo == 1:\n print "something for 1"\nelif foo == 2 or foo == 3:\n print "something for 2 and 3"\n if foo == 3:\n print "something for 3"\nelse:\n print "something else"\n\n Perl has a somewhat cleaner idiom than C as well for single operation if blocks: \nif (foo == 4 || foo == 1) {\n print "something for 1 and 4";\n print "something for 1" if (foo == 1);\n} else if (foo == 2 || foo == 3) {\n print "something for 2 and 3";\n print "something for 3" if (foo == 3);\n} else {\n print "something for everyone else";\n}\n My preference, of course, is for Python. There are no braces or break statements to fat-finger and scope is obvious from the indentation.
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #83,216
2/21/03 3:45:11 PM
|
Couple more
The switch is uniquely qualified to implement a duff device.
\tsend(to, from, count) \tregister short *to, *from; \tregister count; \t{ \t\tregister n=(count+7)/8; \t\tswitch(count%8){ \t\tcase 0:\tdo{\t*to = *from++; \t\tcase 7:\t\t*to = *from++; \t\tcase 6:\t\t*to = *from++; \t\tcase 5:\t\t*to = *from++; \t\tcase 4:\t\t*to = *from++; \t\tcase 3:\t\t*to = *from++; \t\tcase 2:\t\t*to = *from++; \t\tcase 1:\t\t*to = *from++; \t\t\t}while(--n>0); \t\t} \t}
Apologies for the K&R but this is the exact code from Tom Duff's usenet posting. This sick and wrong hack gives partial loop unrolling when doing data moving. You can't exactly do this with if else's. Oh for the days when men were men and compilers were compilers and it was you against the awesomely slow machine struggling to coax behavior that was just barely good enough.
OK, whatever.
For completeness I thought I'd toss in the Squeak implementation of caseOf: otherwise:
A search of the stock images reveals that it is used just 3 times - two of those are in the parser.
someObject caseOf: { [someExpression]->[someCodeToPerform]. [otherExpression]=>[otherThingToDo]. } otherwise: [do this].
which is in fact implemented as:
caseOf: aBlockAssociationCollection otherwise: aBlock
aBlockAssociationCollection associationsDo: [:assoc | (assoc key value = self) ifTrue: [^assoc value value]]. \t^ aBlock value
I think that it's extraordinarily important that we in computer science keep fun in computing. When it started out, it was an awful lot of fun. Of course, the paying customer got shafted every now and then, and after a while we began to take their complaints seriously. We began to feel as if we really were responsible for the successful, error-free perfect use of these machines. I don't think we are. I think we're responsible for stretching them, setting them off in new directions, and keeping fun in the house. I hope the field of computer science never loses its sense of fun. Above all, I hope we don't become missionaries. Don't feel as if you're Bible salesmen. The world has too many of those already. What you know about computing other people will learn. Don't feel as if the key to successful computing is only in your hands. What's in your hands, I think and hope, is intelligence: the ability to see the machine as more than when you were first led up to it, that you can make it more.
--Alan Perlis
|
Post #83,370
2/22/03 5:03:45 AM
|
It's a kind of concealed goto.
By which I mean you can create branching code with some complex paths. Not that's necessarily bad, mind you. I've done more than enough goto-level programming where that was the most efficient way to code the algorithm that having this available can be very useful.
Although I don't do it very often, I've used drop-through enough that I would find it quite inconvenient if I couldn't do it. It's a tradeoff in programmer awareness versus flexibility and power. So I was a little surprised that Perl 6's proposed given {} blocks do not allow drop-through. I'd be curious to see what kind of workarounds and hacks are done to get around this lack.
I also didn't know Python didn't have switch. I guess it's a more controversial control structure than I realized.
Wade.
Is it enough to love Is it enough to breathe Somebody rip my heart out And leave me here to bleed
| | Is it enough to die Somebody save my life I'd rather be Anything but Ordinary Please
| -- "Anything but Ordinary" by Avril Lavigne. |
|
Post #83,556
2/23/03 5:50:39 PM
2/23/03 5:52:26 PM
|
Scott's closest, but not even he got it - my fault, though:
AdminiScott illustrates: There are some things you can do with switch that you can't as easily (arguably) do with if/then:
\nswitch (foo) {\ncase 1:\n/* something for 1 */\ncase 4:\n/* something for 1 and 4 */\nbreak;\ncase 2:\n/* something for 2 */\ncase 3:\n/* something for 2 and 3 */\nbreak;\ndefault:\n/* something for other things */\n}\n\n[...] The switch is easier to read (IMO) but can get a bit confusing with the drop-throughs if you don't understand (or overlook) the break placements. Comments are encouraged when using that technique. ;-) Actually, I knew all that... I just don't happen to agree that it's any (OK, much) better. What I meant was only that this is just (OK, almost) as bad as an if-elseif construct; that "drop-through" shit is stupid, confusing, a HUGE potenial source of errors, and just plain frigging *unnecessary*. "Comments are encouraged", in-freaking-deed... [Edit:] My bad, though, for writing just a terse one-liner.
[link|mailto:MyUserId@MyISP.CountryCode|Christian R. Conrad] (I live in Finland, and my e-mail in-box is at the Saunalahti company.)
Your lies are of Microsoftian Scale and boring to boot. Your 'depression' may be the closest you ever come to recognizing truth: you have no 'inferiority complex', you are inferior - and something inside you recognizes this. - [link|http://z.iwethey.org/forums/render/content/show?contentid=71575|Ashton Brown]
Edited by CRConrad
Feb. 23, 2003, 05:52:26 PM EST
|
Post #84,141
2/25/03 8:59:17 PM
|
VB does some things right
VB allows more of a set-based approach. It kind of resembles: \nselect on (foo) \ncase 1:\n /* something for 1 */\ncase 1,4:\n /* something for 1 and 4 */\ncase 2:\n /* something for 2 */\ncase 2,3:\n /* something for 2 and 3 */\ndefault:\n /* something for other things */\nend select\n All without those fricken "break" dealies.
________________ oop.ismad.com
|
Post #84,196
2/25/03 11:13:58 PM
|
If I'm not mistaken...
Having the same option in multiple case statements is legal in VB but it only peforms the first case that is matched.
|
Post #84,334
2/26/03 3:00:17 PM
|
poor substitute for Boolean expressions
Having the same option in multiple case statements is legal in VB but it only peforms the first case that is matched.
You are right. Bad example on my part.
But, if you want potentially multiple blocks to execute, then you might as well use IF blocks. I tend to shift to IF blocks for all but the simplest of case statements anyhow. They scale better in complexity.
And, I don't like BREAK statements. Too easy to forget, and they are a dumb substitute for Boolean expressions IMO. Too Goto-like.
________________ oop.ismad.com
|
Post #84,220
2/26/03 2:03:07 AM
|
Well, close. But cooler is the range stuff
Select aNumber\n Case Is < 0\n FunctionA\n Case 0 to 3\n FunctionB\n Case 4, 15, 32, 78\n FunctionC\n Case Else\n FunctionD\nEnd Select
Many fears are born of stupidity and ignorance - Which you should be feeding with rumour and generalisation. BOfH, 2002 "Episode" 10
|
Post #84,231
2/26/03 6:34:26 AM
|
Fugly syntax kind'a repeats itself: YTF "select" AND "case"?
Our residentnoncapitalisedpoet claims VB's "range" case construct is so cool: Select aNumber\nCase Is < 0\nFunctionA\nCase 0 to 3\nFunctionB\nCase 4, 15, 32, 78\nFunctionC\nCase Else\nFunctionD\nEnd Select
Just so nobody labours under the misapprehension that this was a VB "innovation" or anything... Pascal has had that since 197x! The ony difference being, the Pascal syntax is (as always) *much* cleaner and more elegant than VB's: Case AnInteger of\n -MAXINT .. -1 : ProcedureA;\n 0 .. 3 : ProcedureB;\n 4, 15, 32, 78 : ProcedureC;\n Else ProcedureD;\nEnd; {Case AnInteger} Behold the genius of Wirth in action: One construct, one keyword!
[link|mailto:MyUserId@MyISP.CountryCode|Christian R. Conrad] (I live in Finland, and my e-mail in-box is at the Saunalahti company.)
Your lies are of Microsoftian Scale and boring to boot. Your 'depression' may be the closest you ever come to recognizing truth: you have no 'inferiority complex', you are inferior - and something inside you recognizes this. - [link|http://z.iwethey.org/forums/render/content/show?contentid=71575|Ashton Brown]
|
Post #84,297
2/26/03 11:44:38 AM
|
Not trying to imply invention
Just pointing out:
1) tablizer's "VB" didn't look like any VB I've ever seen, and 2) I didn't think he pointed out anything really useful. So I thought I would.
We now return you to your regularly scheduled language war.
Many fears are born of stupidity and ignorance - Which you should be feeding with rumour and generalisation. BOfH, 2002 "Episode" 10
|
Post #84,445
2/26/03 8:09:43 PM
|
Pascal was invented before Visual BASIC
I remember using it in Turbo Pascal 2.0 before VB came out. Thanks for the reference.
In Pascal, Semi-Colons are your friends. :)
[link|http://pub75.ezboard.com/bantiiwethey| New and improved, Chicken Delvits!]
|
Post #83,194
2/21/03 2:17:54 PM
|
One more thing:
The caseof...case... construct (which was bastartized into the switch...case... construct by K&R) can generally only be used to compare fixed constant values against the target expression. If()...elseif()...else constructs are much more flexible, and can be (mis)used to perform comparisons if several unrelated conditions all witint he same construct.
Not knowing Perl, I don't know whether their given... construct would be restricted to comparisons of constants vs. an expression, or expressions against an expression. One could argue that, if it's the latter, its not a real case statement, but merely the god(s) of Perl showing off.
jb4 "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." Rich Cook
|
Post #83,411
2/22/03 2:55:32 PM
|
Constant vs an expression
Though, Perl being Perl, there will be a lot of interesting options for the kinds of expressions.
Cheers, Ben
"good ideas and bad code build communities, the other three combinations do not" - [link|http://archives.real-time.com/pipermail/cocoon-devel/2000-October/003023.html|Stefano Mazzocchi]
|
Post #84,600
2/27/03 9:16:11 AM
|
That's sorta what I figger...
jb4 "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." Rich Cook
|
Post #83,350
2/22/03 12:33:27 AM
|
Comments and thoughts...
one reason Perl may not have the switch statement, is that it doesn't need it.
No, I'm not talking about if/elseif.
But...for a single value, place the value into a map (er...hash, too much STL lately) with the function you want to call as the other value. Voila. (Let's see if I remember this correctly) &map[key];
(Someone want to check me on it?)
I have a personal dislike on if/elseifs - I think that they're often misused by programmers. I've seen way too many cases were a programmer ran through conditions...and wasn't checking everything he needed to cover...or mishandled a condition he though he covered.
|
Post #83,351
2/22/03 12:44:30 AM
|
Along similar lines...
Polymorphic dispatch from an OOP perspective also solves the problem. Instead of building the logic for the code in the user, build a common interface for the objects and have the object itself define what happens in the specific situation.
And, yes, Control Tables as a method of dispatch will go unmentioned. :-)
|
Post #84,143
2/25/03 9:11:49 PM
|
Multimorphism
Polymorphic dispatch from an OOP perspective also solves the problem. Instead of building the logic for the code in the user, build a common interface for the objects and have the object itself define what happens in the specific situation.
Only in "clean" shape, animal, device-driver, and stack examples. The real world often dispatches on multiple orthogonal criteria such that OO polymorphism cannot handle it nicely because polymorphism is mostly mono-dispatch.
Nor is it always convenient to make a seperate class for every combination of multiple orthogonal dispatching factors in order to partition them. At least case statements can be turned into IF statements when things get complex without having to do the Class Shuffle. Thus, case statements are more change-resistent.
And, yes, Control Tables as a method of dispatch will go unmentioned
Generally not a strong candidate unless the case list gets long and/or is duplicated in multiple spots.
________________ oop.ismad.com
|
Post #83,372
2/22/03 5:11:36 AM
|
Sometimes that's overkill.
A short, simple switch and a half a dozen case clauses with two or three lines each is generally regarded as nice and concise. Otherwise, I generally agree.
Besides, I think else gets over used these, days, too. :-) I remember some particularly shocking code some years ago where the programmer had only just discovered the else clause and managed to use it on almost every if statement.
Wade.
Is it enough to love Is it enough to breathe Somebody rip my heart out And leave me here to bleed
| | Is it enough to die Somebody save my life I'd rather be Anything but Ordinary Please
| -- "Anything but Ordinary" by Avril Lavigne. |
|
Post #83,381
2/22/03 7:05:49 AM
|
$foo->{$key}
Perl's hash syntax sucks hard, IMO.
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #83,410
2/22/03 2:54:15 PM
|
You are probably thinking of
$handler{$case}->(@args);
Which looks up your $case in a hash %handler to find the anonymous function for your case, and then calls @args with it. When I do this, many of the cases are handled by closures, with full control over the occasional case that doesn't fit a simple pattern.
This seems very convoluted the first time you see it, but with practice it becomes very natural. The only caveat is that it doesn't have a good way to fallback in the event that your case is not in the hash - you have to check that separately.
Cheers, Ben
"good ideas and bad code build communities, the other three combinations do not" - [link|http://archives.real-time.com/pipermail/cocoon-devel/2000-October/003023.html|Stefano Mazzocchi]
|