1.

Solve : Programming Elegance?

Answer»

Alright, so the other day I was talking to C# programmers about C#.
They think my style of code is really ugly and horrid. I don't believe it to be so.
So I would like to know what you guys think about my style and their style and its readability/elegance/usefulness.

I think it's humanly more easily readable if I write comparison like this:

if (a == 10) { b=30; }
if (number==42) { number2 = 43; }
if (test) { a=10; }

This is how they would write it (not the same statements, but the same idea, other style):

bool b = a == 10;
myList.Where(e -> e == 42);

I'm sorry but, it's quite confusing to me to write
bool b = a == 10;
just to say "if a equals 10 then make b true".
Maybe I'm just not used to that style but I find it ugly.
They, on the other hand, find my style ugly, which I think is pretty readable:

if (a==10) { b = true; }

So, do I have the horrid code or what?
I don't get what's so bad about my style but anyway.
Same counts for ternary operators rather than if/else..

Here is an example of my 'horrid' code.. :
Code: [Select]
class DialogBox
{
#region "Properties"
private Color bgColor, fgColor;
private Vector2 textPos, bgPos;

#endregion

public DialogBox()
{
bgColor = Color.Blue;
fgColor = Color.White;

}

public Vector2 BgPos
{
get;
set;
}

#region "Methods"
public void Say(string output, ref Vector2 stringLoc, Rectangle rect,
SpriteBatch sprites, SpriteFont sfont, Texture2D txtr, Vector2 bgPos)
{
//Draw the background texture
this.bgPos = bgPos;
sprites.Draw(txtr, bgPos, null, Color.White, 0.0f, new Vector2(0f, 0f), 25f, SpriteEffects.None, 0);

char[] chars = output.ToCharArray();
string tempChars=chars[0].ToString();
Console.WriteLine("textPos.X: "+textPos.X);
float textPosCopy = textPos.X;
char[] charss = null;

for (int i = 1; i<chars.Length-1; i++)
{
//foreach (char c in chars)
//{
Vector2 measure = sfont.MeasureString(tempChars);

if ((stringLoc.X + measure.X) > (rect.X + (rect.Width) * 25)+5)
{
int icopy = i; //31
int y = 0; //31
y = icopy; //31
Console.WriteLine("textPos: " + textPos.X);

char[] newChars = new char[chars.Length-y];
oldChars = new char[chars.Length];
Array.Copy(tempChars.ToCharArray(),oldChars,tempChars.Length);
Console.WriteLine("i: "+i);
Array.Copy(chars,y,newChars,0,chars.Length-y);
tempChars += "\n";
tempChars = "";
textPos.X = textPosCopy;

for (int x = 0; x < newChars.Length; x++)
{
oldChars[y] += newChars[x];
}
}
else
tempChars += chars[i];
#region "Console test"
//chars = tempChars.ToCharArray();
Console.WriteLine("StringLoc: " +stringLoc.X);
Console.WriteLine("StringLoc+width: " + (stringLoc.X + measure.X));
Console.WriteLine("Dialog Width: " + (rect.X + (rect.Width*25)));
Console.WriteLine("Char: " +tempChars);

Console.WriteLine("\n");
//}
#endregion

}

//Draw the text
textPos = new Vector2(bgPos.X + 15, bgPos.Y + 15);
Vector2 textTestPos = new Vector2(bgPos.X + 15, bgPos.Y + 40);

sprites.DrawString(sfont, , textPos, fgColor,0.0f,new Vector2(0f,0f),
1.0f, SpriteEffects.None, 0);
#region "Testing"
/*sprites.DrawString(sfont, "Text \n next line Text",textTestPos,fgColor,0.0f,
new Vector2(0f,0f),1.0f,SpriteEffects.None,0);*/
//Console.WriteLine("TempChars: " +tempChars);
#endregion

}
#endregion
}

I'm sure many of you could write this code a lot better and shorter than me, but I'm just not a good programmer. =P

don't worry, your style is the one i prefer as well. Your fellow C-sharpers just want to be cool that's all. But coolness does not equal readable or maintainable. I do something similar in VB6, instead of, for example:

Code: [Select]if A or B and (Not A and B) then
...

I would do:

Code: [Select]if a Xor b then

simply because that's the definition of xor, of course.

use of assignment operators in expressions only reduces readability for those who don't use it very often; since many languages don't actually implement assignment as a part of an expression it can seem foreign or strange.

But this is about style, not ugly code. Your style differs from theirs, that is all.

All I can really say about the code you display is that it has an awful lot of Console writes for what appears to be debugging purposes, you could add the System.Diagnostics via a using directive and replace those with Debug.Print statements, and then when it's compiled for release none of the Debug statements are effective.

Consider the translation of steps for both, for yours:

Code: [Select]if (a==10) { b = true; }
This translates to at least one Jump instruction, and an assignment, and then a jump out of the IF block (of course this would be IL and I'm not familiar with the particulars of it)

the way they have theirs, there is no jump instruction; one a comparison and an assignment of that result to another variable. Depending on the context this can have a influence on the branch predictor of either the CLR or the processor (I don't know how it translates, really) for native code, the branch predictor adds the assignment to the prediction queue; this saves time when it turns out that a is indeed 10, but if it's not, the entire queue needs to be flushed and a new prediction queue built up from that point. if you do this in a tight loop it can have a perverse affect on speed, sometimes an order of magnitude. Of course since C# is actually executed by IL I really have no idea how it would convert any of that to machine code or wether the branch predictor is relevant, since such prediction will apply pretty much SOLELY to the interpreter.

My personal use of such constructs depends solely on context; for example, in my Expression Evaluator (which served as an impromptu base for "BCScript" a rather silly scripting language that came about purely by accident) I have a "RipFormula" procedure whose task is to take the expression and build a Expression Stack from it. Several important optimizations took place during my creation of this routine. At first, I had a small segment of code that got executed via a "GoSub...Return"... I did this purely for convenience sake at the time. Some time later, I replaced this with a separate routine.

The speed increase was dramatic. Of course this is because GoSub and Goto are adversely affected by Native code COMPILATION for whatever reason.

Additionally, I often use similar techniques if only to increase readability. When you're already nested in several ifs, a Case statement, and a few loops it's best to avoid unnecessary further control blocks. Also, it's easier to integrate; if I want A to be the same as B*-1 only if C is less then Y, and otherwise set it to 0, for example, we do this:
Code: [Select]if C<Y then A=-B else A=0

which is certainly reasonable. But consider for a moment that A is actually just being used for that particular IF and is really intended as part of some calculation- say the next line is something like:

Code: [Select]FOO=100*T.Size/len(T.Filename) /A
eliminating that variable entirely may not have a huge performance impact but annihilating the entire code branch from the loop can. I did this in several places, actually. It translated into this:
Code: [Select]FOO=100*T.Size/len(T.Filename)/((C<Y)*B)
of course such things receive comments to that regard and what they do. And it's a rather contrived example; I added the negative requirement simply because it saved a "abs() call. but remember that Visual Basic "Classic" is rather alone in using 0 to indicate false and -1 (well, strictly speaking anything but 0 is true, but true is returned as -1), most other languages/environments use 1, which can be more helpful in use of similar constructs.

Using Booleans in arithmetic expressions seems unnatural, but once you realize that boolean expressions are just as powerful outside the brackets of the if as they are elsewhere it can become very useful to prevent long code branches and deeply nested ifs that account for all sorts of different conditions.

Very nice. =PTreval , you have style. I don't want people to say that just to patronize me. =PMy statement was only about your code.
Show me your Avitar. Must be ugly.Quote

Treval , you have style.

I read a very good book in the 1980s, still a classic, and often used in programming courses - "The Elements of Programming Style" by Kernighan and Plauger. Brian Kernighan is the famous Unix (he coined the name) and C pioneer (He is the K in AWK). P. J. Plauger is an author. He founded Whitesmiths, the first company to sell a C compiler and Unix-like operating system (Idris). He is also a science fiction writer; he won the John W. Campbell Award for Best New Writer in 1975, notably beating John Varley for the award.

The book is well worth acquiring. There is a PDF extract containing 56 "rules of programming style" available on many college websites including here

http://cs.boisestate.edu/~amit/teaching/handouts/style.pdf

some apt quotes...

Quote
1. Write clearly don't be too clever.
2. Say what you mean, simply and directly.
3. Use library functions whenever feasible.
4. Avoid too many temporary variables.
5. Write clearly - don't sacrice clarity for "efficiency".
6. Let the machine do the dirty work.

Quote
11. If a logical expression is hard to understand, try transforming it.

So, I have style according to points 5 & 6? =P
Then I still have to work on the rest of the points because I have too many temp vars.
What if it's the case that you have no other choice but to choose temp vars (for example, you need a variable to be initialized with a particular value according to a particular item in a foreach)?
Using library functions? You mean the .NET framework funcs? Such as Math.Floor()?
What's an example of point 5?

Thanks for the book.Quote from: Treval on April 11, 2010, 04:32:56 AM

What's an example of point 5?


I should think point 5 maybe covers situations where the programmer gets "clever" and writes code which gets the desired result maybe in one line instead of ten, but which is not immediately understandable to anybody else, (or, often, the same programmer six months later!) I believe the author put the word "efficiency" in quotes to point up the idea that code can be efficient in a trivial sense, i.e. in terms of machine resources, source code size, memory/cpu usage, etc, but be a horror to maintain and debug, thus consuming more than its proper share of human time and resources.Yes that is a good point.
I also try to be firm and clear about my commenting the code. =)Quote from: Treval on April 11, 2010, 05:44:50 AM
Yes that is a good point.
I also try to be firm and clear about my commenting the code. =)

This is one thing I am trying to do more; sometimes I write the comments first.
I use temporary variables all the time. But not too many of them.

I use them to store the result of a function when I need to refer to that result in multiple conditions. A prime example is, for example, a function in my Expression Evaluator called "GetOperator" My first iteration of the code for some reason was calling the function with the same parameters multiple times to decide what to do, so I replaced it with a single call that assigned it to a temporary variable and used that result instead. I did this as well with a few other intensive functions in various locations of the code, and caused a noticable speed improvement. I think it's important to simply not use too many of them at the same time. I often use the
Code: [Select]foreach(typename varname in collection)
{

}
syntax myself in C#, I don't consider it a "temporary" variable, but rather a variable local to the foreach() block, since outside the block it isn't defined.



Re: comments: needless to say, they are important. USUALLY, when I start any non-trivial function, I try to write some sort of "preamble" comments that indicate what it will do, and possibly how that will be done. This is especially useful in that I can decide wether certain portions might be better served as separate functions, as well as prevent errors. I just checked and most of my projects have around 25% of their lines as comment lines. some of those are commented out code though.


Discussion

No Comment Found