Example: Why does .NET promote bad programming practices?
-
OK, this is a more language specific post, but the VB thread below got me thinking (a bad thing, I know). For example, being able to do:
switch(myString)
{
case "Hello":
...
case "Goodbye":
...
}is a perfect example of how the language promotes bad programming. The result is a case-sensitive, culture-specific, difficult to extend, and probably format specific within the context of the whole parser, implementation. Now, I personally don't feel a language should (or even can) enforce good programming practices. But a language that supports a bad practice certainly doesn't help the situation. Anyone want to contribute other examples or thoughts? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithSince strings in .NET are unicode, the string "Hello" is basically a byte[10] array with fixed, compile-time known value. This is not a language issue or compiler issue at all because instead of 'case 0: case 1: case 234:', you have a string representative of the underlying values, which is much more readable. In terms of case-sensitive and culture issue, it really depends on where the given string comes from and what does it represent. For instance, in a localized app, regardless of the culture, you will need a culture-unspecific id to identify a control/component. That id could be a GUID, an integer, or a string. From your code sample, I will presume that the given 'myString' is properly normalized with correct cap and trimming. If this isn't the case, then it is the programmer's problem, never the tool.
-
OK, this is a more language specific post, but the VB thread below got me thinking (a bad thing, I know). For example, being able to do:
switch(myString)
{
case "Hello":
...
case "Goodbye":
...
}is a perfect example of how the language promotes bad programming. The result is a case-sensitive, culture-specific, difficult to extend, and probably format specific within the context of the whole parser, implementation. Now, I personally don't feel a language should (or even can) enforce good programming practices. But a language that supports a bad practice certainly doesn't help the situation. Anyone want to contribute other examples or thoughts? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithIt is very difficult to find the ballance between enforcing good practices and giving developers more control. The example you posted can be dangerous, but it is perfectly correct in certain situations (as Rocky Moore mentioned). Interesting extension to the swith control structure are Active patterns available in F#: http://blogs.msdn.com/dsyme/archive/2006/08/16/ActivePatterns.aspx[^]. In simple words, active patterns make it is possible to write patterns (rules) that are executed when "case" statement is reached. This rule can than decide whether case statement should be executed. Of course this can be misused, but I think that it would be interesting extension to main-stream programming languages.
// You could then use something like this..:
switch(str)
{
case CaseSensitiveMatch("something"):
... break;
case CaseInsensitiveMatch("SomeThinG"):
... break;
case CaseInsensitiveContains("thing"):
... break;
}Actually working with strings directly is always potential source of problems (with localization), but I think that active patterns could be useful in many other sitations.
Homepage: TomasP.net | Photo of the month: Calendar | C# and LINQ, F#, Phalanger: My Blog
Latest article: Phalanger, PHP for .NET: Introduction for .NET developers -
Interesting, this is what my Reflector shows: private static bool TryStringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal);
if (!Number.ParseNumber(ref chPtr2, options, ref number, numfmt, parseDecimal) || ((((long) ((chPtr2 - chPtr1) / 2)) < str.Length) && !Number.TrailingZeros(str, (int) ((long) ((chPtr2 - chPtr1) / 2))))) { return false; }
private static void StringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo info, bool parseDecimal);
if (!Number.ParseNumber(ref chPtr2, options, ref number, info, parseDecimal) || ((((long) ((chPtr2 - chPtr1) / 2)) < str.Length) && !Number.TrailingZeros(str, (int) ((long) ((chPtr2 - chPtr1) / 2))))) { throw new FormatException(Environment.GetResourceString("Format_InvalidString")); }
"Throughout human history, we have been dependent on machines to survive. Fate, it seems, is not without a sense of irony. " - Morpheus
-
'cause it is useful when you need it to get a quick job done. There is a lot to be said about premature optimisation and astronaut architects.
regards, Paul Watson Ireland & South Africa
Shog9 wrote:
And with that, Paul closed his browser, sipped his herbal tea, fixed the flower in his hair, and smiled brightly at the multitude of cute, furry animals flocking around the grassy hillside where he sat coding Ruby on his Mac...
And then the "quick job" gets used a lot and built upon and (before you know it) that quick hack is the corner stone of a dreadful big monolithic application...
-
Phrase "astronaut architects" is not known to be, but I think I agree :) Using TryParse when dealing with user input is usually sufficient. If TryParse methods are not fast enough, by all means implement yours. edit: oops, didn't see you responded to original post and not TryParse debate above. Well, surprisingly my post didn't lost its meaning. :->
"Throughout human history, we have been dependent on machines to survive. Fate, it seems, is not without a sense of irony. " - Morpheus
I first heard about it from Joel[^].
regards, Paul Watson Ireland & South Africa
Shog9 wrote:
And with that, Paul closed his browser, sipped his herbal tea, fixed the flower in his hair, and smiled brightly at the multitude of cute, furry animals flocking around the grassy hillside where he sat coding Ruby on his Mac...
-
OK, this is a more language specific post, but the VB thread below got me thinking (a bad thing, I know). For example, being able to do:
switch(myString)
{
case "Hello":
...
case "Goodbye":
...
}is a perfect example of how the language promotes bad programming. The result is a case-sensitive, culture-specific, difficult to extend, and probably format specific within the context of the whole parser, implementation. Now, I personally don't feel a language should (or even can) enforce good programming practices. But a language that supports a bad practice certainly doesn't help the situation. Anyone want to contribute other examples or thoughts? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithSwitching on strings is a good feature, but to be used sparingly. Many years ago I had need of reading in some reports and processing the data, having only Vax-C as a tool. I found that because a character constant could actually hold two characters I could switch on the first two characters of each line, something like:
FILE* file ;
char* buffer ;
char firsttwocharacters ;...
readaline ( file , buffer ) ;
firsttwocharacters = *buffer ;
switch ( firsttwocharacters )
{
case 'AB' : ...
case 'CD' : ...
...
}
...And I don't use TryParse, I've read articles like this one: http://www.codeproject.com/dotnet/ExceptionPerformance.asp[^]
-
OK, this is a more language specific post, but the VB thread below got me thinking (a bad thing, I know). For example, being able to do:
switch(myString)
{
case "Hello":
...
case "Goodbye":
...
}is a perfect example of how the language promotes bad programming. The result is a case-sensitive, culture-specific, difficult to extend, and probably format specific within the context of the whole parser, implementation. Now, I personally don't feel a language should (or even can) enforce good programming practices. But a language that supports a bad practice certainly doesn't help the situation. Anyone want to contribute other examples or thoughts? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithFirst thing one learns in a Test Driven Development environment is: switch statements = bad bad bad.
-
And then the "quick job" gets used a lot and built upon and (before you know it) that quick hack is the corner stone of a dreadful big monolithic application...
Well obviously that shouldn't happen. People just need to use their heads :)
regards, Paul Watson Ireland & South Africa
Shog9 wrote:
And with that, Paul closed his browser, sipped his herbal tea, fixed the flower in his hair, and smiled brightly at the multitude of cute, furry animals flocking around the grassy hillside where he sat coding Ruby on his Mac...
-
'cause it is useful when you need it to get a quick job done. There is a lot to be said about premature optimisation and astronaut architects.
regards, Paul Watson Ireland & South Africa
Shog9 wrote:
And with that, Paul closed his browser, sipped his herbal tea, fixed the flower in his hair, and smiled brightly at the multitude of cute, furry animals flocking around the grassy hillside where he sat coding Ruby on his Mac...
Paul Watson wrote:
premature optimisation
You can get medication for that these days.
cheers, Chris Maunder
CodeProject.com : C++ MVP
-
Paul Watson wrote:
premature optimisation
You can get medication for that these days.
cheers, Chris Maunder
CodeProject.com : C++ MVP
Sadly it can make you go blind.
regards, Paul Watson Ireland & South Africa
Shog9 wrote:
And with that, Paul closed his browser, sipped his herbal tea, fixed the flower in his hair, and smiled brightly at the multitude of cute, furry animals flocking around the grassy hillside where he sat coding Ruby on his Mac...
-
I don't have VS05, what's inside
Number.ParseNumber
?-- Rules of thumb should not be taken for the whole hand.
-
-
First thing one learns in a Test Driven Development environment is: switch statements = bad bad bad.
Paul Brower wrote:
First thing one learns in a Test Driven Development environment is: switch statements = bad bad bad.
Why? How do switch statements affect TDD? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith -
Ennis Ray Lynch, Jr. wrote:
but using Exceptions as a point of logic is not acceptable!
That was one of my beefs with the Parse methods, that I couldn't get access to the underlying validator to test the string without having Parse throw an exception. I raised (harhar) this issue at one of the "meet the developers" meetings and they said it was being addressed in .NET 2.0. I felt that was a good thing. TryParse addresses that issue, IMO. Throwing an exception is expensive, and in some cases I'd rather:
int userInputId=0;
bool success=Int64.TryParse(someText);Similarly, I don't like writing code like:
if (container.Contains(myKey))
but prefer:
bool success=container.TryGetValue(key, out val);
Because there are many cases when it's OK if the container doesn't contain the key. Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithMarc Clifton wrote:
Throwing an exception is expensive
I'm not familiar enough with the CLR to know, but just how expensive is an exception? My background is C++ (where exceptions are potentially very expensive) and Java (where exceptions are very cheap) I'm going to go out on alimb and guess the CLR is somewhere in the middle? - Phil
-
Paul Brower wrote:
First thing one learns in a Test Driven Development environment is: switch statements = bad bad bad.
Why? How do switch statements affect TDD? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithSwitch statements are one of the most obvious 'code smells.' Typically switch statements are indicative of duplication. Most times when you see a switch statements, you should consider refactoring with polymorphism. Below are some common refactoring methods to deal with switch 'smells.' 1: If you're switching on some kind of code, you'll want a method or class that hosts the type code. (Extract case to new method then move it to the appropriate -- new if necessary -- class where the polymorphism is needed. At that point you can replace type code with State or Strategy pattern. Once that is done, replace conditional with polymorphism, possibly making original method abstract. 2: If you only have a few cases in a single method, and you don't expect change, then polymorphism is definately too much. In this case, you can use the 'Replace Parameter with Explicit Methods'. Create an explicit method for each value of the parameter, for each leg of the conditional, call the appropriate new method, replace each caller of the conditional method with a call to the appropriate new method, remove the conditional method. (Excerpts taken from REFACTORING - IMPROVING THE DESIGN OF EXISTING CODE -- Martin Fowler).
-
OK, this is a more language specific post, but the VB thread below got me thinking (a bad thing, I know). For example, being able to do:
switch(myString)
{
case "Hello":
...
case "Goodbye":
...
}is a perfect example of how the language promotes bad programming. The result is a case-sensitive, culture-specific, difficult to extend, and probably format specific within the context of the whole parser, implementation. Now, I personally don't feel a language should (or even can) enforce good programming practices. But a language that supports a bad practice certainly doesn't help the situation. Anyone want to contribute other examples or thoughts? Marc
People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh SmithNot to continue beating this horse, but how would this really be different than using a sequence of if/else if statements to do the test? You would still run into potential issues with case-sensitivity.
switch (myString)
{
case "Hello":
...
case "Goodbye":
...
}if (myString == "Hello")
{
}
else if (myString == "Goodbye")
{
}
else
{
}All of these statements evaluate to
call bool [mscorlib]System.String::op_Equality(string,string)
in IL. To get around the case-sensitivity and culture issues, you can usemyString.ToLowerInvariant()
, which will still result in the same call toop_Equality
. I know that switches are optimized for numeric comparison, but I think it is sometimes necessary to be able to do comparisons of this sort and I would much rather deal with reading a switch statement than a bunch of if/else if statements.----------------------------- In just two days, tomorrow will be yesterday.