#22293 - MumblyJoe - Thu Jun 17, 2004 4:57 am
I was just thinking earlier about the ?: operators, and thought I would try something. Consider this working code:
Code: |
#include <iostream>
#define MYWAY
int func1(){return 1;}
int func2(){return 2;}
int main()
{
using namespace std;
cout << "Function 1 or 2:";
int what;
cin >> what;
#ifdef MYWAY
cout << (what==1?func1:func2)() << endl;
#else
if(what==1)
cout << func1();
else
cout << func2();
cout << endl;
#endif
return 0;
} |
if you can see what i am doing you can see what i am trying to do, and see that it works as long as the functions have the same signiture. I cant decide which one has what benifits (besides clearness of code) but I am playing with borland compilers now to see.
Tell me what you think... useless confuscation or genuine useful coding practice.
PS. I know indexing into an array of functions would be faster in some cases but not if you want 1==func1 and everything else == func2 because you still end up checking for that before indexing into the array and would need code like func[(what==1)]() anyway...
_________________
www.hungrydeveloper.com
Version 2.0 now up - guaranteed at least 100% more pleasing!
#22294 - jma - Thu Jun 17, 2004 5:21 am
This is a very common practice in the Lisp/Scheme worlds:
Code: |
((if flag + -) a b) |
Hence, if flag is true, then it will return a+b, otherwise a-b. However, this would be a bad idea in the land of C/C++. Not because it isn't do-able, but because your compiler isn't designed for it. You'll get very sub-par assembly code out of it.
Jeff
_________________
massung@gmail.com
http://www.retrobyte.org
#22295 - DiscoStew - Thu Jun 17, 2004 5:31 am
To me, the line...
Code: |
cout << (what==1?func1:func2)() << endl;
|
...just looks odd. Then again, I've never tried something like that, let alone see if it even works. In my head, I could see this piece work...
Code: |
cout << ((what==1) ? func1() : func2()) << endl;
|
Not only would it not confuse the compiler, but each function could have separate parameters if you wanted.
I'm more into readable code than tricks until I know exactly how it works. I even keep my original piece of code in comments if I were to try to change something, just so that I can see what I tried to do before making any tricks. Plus, I can go back to my original if I need to.
I very rusty with pointer to functions, so I can't really help you there at the moment.
_________________
DS - It's all about DiscoStew
#22297 - sajiimori - Thu Jun 17, 2004 5:56 am
DiscoStew's second method is a good replacement from a technical standpoint.
But as far as style, I'm most inclined to do it the unclever way:
Code: |
int i;
if(what == 1)
i = func1();
else
i = func2();
cout << i << endl;
|
#22298 - sgeos - Thu Jun 17, 2004 6:18 am
MumblyJoe wrote: |
Code: | cout << (what==1?func1:func2)() << endl; |
if you can see what i am doing you can see what i am trying to do, and see that it works as long as the functions have the same signiture. |
Of course. I'm not a C++ guy, but in C func1 is the same as &func1 (is different from func1() ). You are having your (?:) select a funtion pointer. Then you pass parameters to your chosen function. Neat!
It even works in C:
Code: |
#include <stdio.h>
int normal(int a) { return a; }
int twotimes(int a) { return a << 1; }
int half(int a) { return a >> 1; }
int square(int a) { return a*a; }
int main(int argc, char **argv)
{
printf
(
"%d\n",
(
argc < 2 ? normal :
argc < 4 ? twotimes :
argc < 6 ? half :
square
)(5)
);
return 0;
} |
MumblyJoe wrote: |
PS. I know indexing into an array of functions would be faster in some cases... |
In the cases when an array is faster than (?:).
-Brendan
#22300 - Abscissa - Thu Jun 17, 2004 6:30 am
Its a useless obfuscation. The ?: operator is literally nothing more than shorthand for if-else, so the assembly generated is going to be extremely similar, if not identical. The second way (the common way) is going to be 10x easier to read, debug and maintain. The only "benefit" you'd get from the ?: style would be smaller C file, but that hasn't been remotely important in the last 20 years.
Since ?: is basically just an if-else with syntax that's better for numerical expressions than execution logic, it should only be used when it makes the code clearer (or at least doesn't make it any less clear). Such as this example:
Quote: |
int bestScore;
// Simple and Concise
bestScore = (score1 > score2) ? score1 : score2;
// Needlessly Verbose (But still perfectly ok)
if(score1 > score2)
bestScore = score1;
else
bestScore = score2;
// Note that both of the above will most likely generate
// the same assembly code.
|
#22302 - sgeos - Thu Jun 17, 2004 9:33 am
Computer crashed before I finished posting. Short response mode on!
Abscissa wrote: |
The ?: operator is literally nothing more than shorthand for if-else, |
Disagree. ?: is an expression. Code: |
#define MIN(a,b) ((a) < (b) ? (a) : (b)) |
Please convert this to if-else form.
[quote]so the assembly generated is going to be extremely similar, if not identical.[quote]Agree. Quote: |
The second way (the common way) is going to be 10x easier to read, debug and maintain. |
Agree in most cases. Note: verbosity of a function should be inversly proportional to its length. Quote: |
The only "benefit" you'd get from the ?: style would be smaller C file, but that hasn't been remotely important in the last 20 years. |
Disagree. Note verbosity above. An ?: chain can be used as a terse version of a switch statement that processes logic. (No fall through.) Code: |
#include <stdio.h>
int main(int argc, char **argv)
{
char c = '0';
/* switch-like */
if (1 < argc)
c = argv[1][0];
'0' <= c && c <= '9' ?
printf("numeral") :
'a' <= c && c <= 'z' ?
printf("lower") :
'A' <= c && c <= 'Z' ?
printf("upper") :
' ' == c ?
printf("space") :
/* default */
printf("other");
return 0;
} |
Quote: |
it should only be used when it makes the code clearer (or at least doesn't make it any less clear) |
Good advice for any language feature. Quote: |
int bestScore;
// Simple and Concise
bestScore = (score1 > score2) ? score1 : score2;
// Needlessly Verbose (But still perfectly ok)
if(score1 > score2)
bestScore = score1;
else
bestScore = score2;
// Note that both of the above will most likely generate
// the same assembly code.
|
I think ?: makes the code less clear. The example is too short. Short functions should be verbose, long functions should be terse (but not cryptic).
-Brendan
#22304 - Sweex - Thu Jun 17, 2004 10:24 am
I'd say use if instead of the boolean operation. Easier to understand.
_________________
If everything fails, read the manual: If even that fails, post on forum!
#22318 - sajiimori - Thu Jun 17, 2004 5:55 pm
Quote: |
Code: | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | Please convert this to if-else form. |
Both C and C++ are weak in this regard (no lambdas, only lexical macros). C++ can almost do it clumsily as follows:
Code: |
template<class T> inline T& min(T& a, T& b)
{
if(a < b) return a;
return b;
}
|
However, the 2 parameters can't be of different types because there's no way to specify which type is returned. *sigh* At least it's "type safe", for what little it's worth.
Quote: |
Note: verbosity of a function should be inversly proportional to its length.
|
That's a new concept for me. Can you qualify it?
#22319 - isildur - Thu Jun 17, 2004 7:09 pm
Another clever way is to use an array of function pointers like this:
Code: |
#include <iostream>
int func1(){return 1;}
int func2(){return 2;}
typedef int (*intFuncPtr) (); // create a int func() type
// an aray of 2 function pointers
intFuncPtr intFuncPtrArray[2] = {func1, func2};
int main()
{
using namespace std;
cout << "Function 1 or 2:";
int what;
cin >> what;
// of course, you would have to validate the user input
cout << intFuncPtrArray[what-1]();
return 0;
}
|
#22320 - sajiimori - Thu Jun 17, 2004 7:37 pm
isildur, maybe you're lost. Did you mean to go here? =)
Last edited by sajiimori on Thu Jun 17, 2004 10:33 pm; edited 1 time in total
#22321 - isildur - Thu Jun 17, 2004 7:48 pm
sajiimori wrote: |
isuldur, maybe you're lost. Did you mean to go here? =) |
lol
#22322 - Miked0801 - Thu Jun 17, 2004 10:29 pm
lol. Great link :)
Though tables of function pointers have their place in the C coding world, I don't believe this is one of them :)
#22323 - sgeos - Fri Jun 18, 2004 12:13 am
sajiimori wrote: |
Quote: | Note: verbosity of a function should be inversly proportional to its length. | That's a new concept for me. Can you qualify it? |
A person can only keep so much in his or her head at a time. This mental limit is a little different for each person. As one approaches that limit, figuring something out becomes more difficult.
If a function is far below that limit, being more verbose will make it clearer. If one is near or at that mental limit, the extra verbosity will be more that the reader has to keep track of. That pushes that person to their mental limit faster. After one reaches his or her mental limit, that person has to page up and down to figure out what is going on.
Consider a function that consists of nothing more than an if-else clause. Three extra local variables are declared because it makes the code clearer. A 25 line comment block is above the if statement, and another 25 line comment block above the else statement.
Now consider a function that consists of nothing more than a 200 case switch statement. Let's do the same thing. Three hundred extra local variables are declared because it will make the clearer. A 25 line comment block is above each case.
Nobody would be motivated to go to the second extreme. Does it illustrate the point? Keep in mind that being terse and obfuscating code are different. The line between making something terse and obfuscation is a little blurry. Adding extra parentheses when they don't do anything is an obfuscation: Code: |
for (((((((i)))=(((0))))));((((((i)))<(((256)))))); ((((((i)))++)))) {{{
// /* /* /* Do Stuff */ */ */
}}} |
It makes the code confusing.
I have intentionally not memorized C's precedence of operators. Multiplication before division, parentheses around everything else. When hard core hackers read my code, I get comments like "you know that you don't need parentheses there, right?" and "if you use one set of parentheses, why not use twenty?" To them, those are "extra parentheses that don't do anything". After I add the parentheses, I know the order of execution and I know that anyone reading the code can figure it out. (I only need one set to achieve my goal.)
Eliminating whitespace would make one's code terser. Having the entire file on one line is clearly an obfuscation. Turning code into ascii art is even worse. Consider happy main(): Code: |
/*~*/ /*~*/
int main
( void
/*===============*/
/* Hello World! */
) //^^^^^^^^^^^^^^^^^
/* */
/* */
{return 0 ; } |
Certainly not terse.
Because the computer is going to figure the code out, the goal is to make the code generally easier to read and comprehend:
Take large functions and break them into smaller functions
Make the intent of small functions crystal clear
Strip verbosity from larger functions so they are easier to comprehend
I hope that is an adequate qualification.
-Brendan
#22324 - isildur - Fri Jun 18, 2004 2:47 am
Miked0801 wrote: |
Though tables of function pointers have their place in the C coding world, I don't believe this is one of them :) |
Of course using tables of function pointers are "pointless" in that example. :)
#22325 - MumblyJoe - Fri Jun 18, 2004 2:49 am
isildur wrote: |
Code: |
// of course, you would have to validate the user input
cout << intFuncPtrArray[what-1]();
|
|
Exactly. It certainly saves us from using ?: but yeah, still have to validate the input in some way if you want 1 to call something and anything else to call something else.[/code]
_________________
www.hungrydeveloper.com
Version 2.0 now up - guaranteed at least 100% more pleasing!
#22331 - sajiimori - Fri Jun 18, 2004 7:36 am
Thanks, sgeos. I think I understand your reasoning. My perspective is exactly the opposite.
For functions that have few elements, I can afford to be terse because it won't put additional stress on the reader. Here is an example from a stupid assignment for a software engineering class I'm in:
Code: |
static void move_to_floor()
{
Elevator* e = elevators.get(get_elevator_num());
cout << "Floor: " << flush;
e->move_to_floor(get_int());
}
|
Since the reader can hold all the elements of the function in mind at once, it makes sense to put it all within their visual field for very fast reading. All things being equal, a shorter program is preferred to a longer one, so I can consider this terseness pure profit in lines of code.
For functions with many elements, first double check that there is no convenient way to split it into multiple functions. If splitting it up wouldn't help (or if it would only make matters worse), then keep in mind that your reader is already under stress due to the number of elements. Writing tersely creates an additional stress, which may put the reader over their limit, forcing re-readings and possibly misinterpretation.
Here is a function whose logic is not immediately apparent, and it has several elements. With these stresses in mind, the code is written to allow the reader to think about only a subset of the problem at a time.
Code: |
void FreightElevator::set_door_state(DoorState state, DoorSet set)
{
if(set == INNER_DOORS)
{
if(state == OPEN)
{
if(outer_doors == CLOSED)
{
cout << "Freight outer doors must be opened "
<< "before inner doors" << endl;
return;
}
control->open_inner_doors();
}
else
control->close_inner_doors();
inner_doors = state;
}
else
{
if(state == OPEN)
control->open_outer_doors();
else
{
if(inner_doors == OPEN)
{
cout << "Freight inner doors must be closed "
<< "before outer doors" << endl;
return;
}
control->close_outer_doors();
}
outer_doors = state;
}
}
|
#22333 - sgeos - Fri Jun 18, 2004 9:25 am
sajiimori wrote: |
My perspective is exactly the opposite. |
I think we agree that the goal is code another person can understand. Putting stress on the reader is counter to that goal- especially when a function gets long. sajiimori wrote: |
For functions with many elements... Writing tersely creates an additional stress... |
I disagree. Writing in an obscured fashion puts extra stress on the reader. Expanding the information the reader needs to keep track of also increases stress.
Code does not ever want to be terse to the extent of being obscure. Again, there is a blurry line in sand. There are times where one wants to make their code extra verbose. I do not think that long functions are place for this. Short functions are the place for extra verbosity. Trivial functions are self documenting in general and do not need anything extra.
Your example fits on a page or two. It is not trivial, nor is it truly long. I'll also argue that it could probably be broken up. At the very least I'd comment the else clauses. Code: |
if(set == INNER_DOORS)
...
else /*(set == OUTER_DOORS)*/
... |
That way your reader/maintainer knows your assumptions, at the very least.
-Brendan
#22338 - sajiimori - Fri Jun 18, 2004 8:21 pm
I don't understand this idea that small functions want to grow and large functions want to shrink, as if all functions should drift toward a particular length.
Quote: |
For functions with many elements... Writing tersely creates an additional stress... |
Let me clarify this. Writing more tersely always creates an additional stress, not just for long functions. This is because more elements of the problem have to be held in mind at once. Writing verbosely allows the reader to reach an understanding in smaller increments. It's the same reason you break large functions into small ones -- the reader doesn't have to think about the whole problem at once.
I don't know if you know Lisp, but code written in that language in particular has a seemingly unlimited potential for being extremely terse, without ever becoming obfuscated (due to its self-similarity at all scales).
Some Lisp gurus (notably Paul Graham) believe that you can recognize good Lisp code by the shape of it on the page. Good code will flow gracefully, like the following Scheme that produces all the permutations of a list:
Code: |
(define (perms items)
(if (null? (cdr items))
(list items)
(let ((positions (range 0 (sub1 (length items)))))
(apply append
(map (lambda (rst)
(map (lambda (pos)
(insert (car items) pos rst))
positions))
(perms (cdr items)))))))
|
I don't believe this code is obfuscated (because it is clean, and it doesn't use any funny tricks), but a lot of things are happening at once, and I personally feel that burden while reading it.
The code's shape is determined by indentation, and indentation is used according to the nesting of expressions. So, code that flows this way is really just deeply nested. The alternative is to declare a series of local variables and then apply them on the last line, which would make the code more vertically shaped.
It would also make the code longer. You can tell how terse a bit of Lisp code is by how deeply nested it is. If you see a local variable declared and only used once, the code could be made more terse by inserting the variable's value where it is used and eliminating the declaration. The above example can be shortened by one line by eliminating the local declaration of 'positions' and inlining its assigned value, but that would make the expression even more deeply nested.
To a certain extent, this is also true of code written in a language from the C/Algol family. My example of a short, terse function has 2 nested expressions. How would the code be different if I had used local variables to capture return values instead of passing them straight to the next function? There are 2 main differences:
- The code would be longer.
- The reader could focus on smaller parts at a time.
To summarize, terseness is a stress, but I use it when I can afford to because all things being equal, short code is better than long code.
#22339 - dagamer34 - Sat Jun 19, 2004 12:10 am
MumblyJoe wrote: |
I was just thinking earlier about the ?: operators, and thought I would try something. Consider this working code:
Code: | #include <iostream>
#define MYWAY
int func1(){return 1;}
int func2(){return 2;}
int main()
{
using namespace std;
cout << "Function 1 or 2:";
int what;
cin >> what;
#ifdef MYWAY
cout << (what==1?func1:func2)() << endl;
#else
if(what==1)
cout << func1();
else
cout << func2();
cout << endl;
#endif
return 0;
} |
if you can see what i am doing you can see what i am trying to do, and see that it works as long as the functions have the same signiture. I cant decide which one has what benifits (besides clearness of code) but I am playing with borland compilers now to see.
Tell me what you think... useless confuscation or genuine useful coding practice.
PS. I know indexing into an array of functions would be faster in some cases but not if you want 1==func1 and everything else == func2 because you still end up checking for that before indexing into the array and would need code like func[(what==1)]() anyway... |
Premature optimization is the root of all evil.
_________________
Little kids and Playstation 2's don't mix. :(
#22353 - sgeos - Sat Jun 19, 2004 5:27 am
sajiimori wrote: |
I don't understand this idea that small functions want to grow and large functions want to shrink, as if all functions should drift toward a particular length. |
It certainly makes more sense to me than the notion that small functions should be smaller and large functions should larger.
sajiimori wrote: |
Writing more tersely always creates an additional stress |
Quote: |
...all things being equal, short code is better than long code. |
You seem to be arguing both that terse code is stressful, and that short code is better. The way I see it, terse code always shorter. If terse code is always more stressful, how is short code better?
All things are never equal. Why don't we just keep making our code more and more verbose until it is not at all stressful to read?
-Brendan
#22358 - sajiimori - Sat Jun 19, 2004 6:05 am
Quote: |
It certainly makes more sense to me than the notion that small functions should be smaller and large functions should larger.
|
I would never claim such a thing.
Quote: |
You seem to be arguing both that terse code is stressful, and that short code is better. The way I see it, terse code always shorter. If terse code is always more stressful, how is short code better?
|
I said all things being equal short code is better. If being shorter means sacrificing something, then that has to be taken into account.
Quote: |
All things are never equal.
|
It's an idealization.
Quote: |
Why don't we just keep making our code more and more verbose until it is not at all stressful to read?
|
Length has its own costs.
#22360 - poslundc - Sat Jun 19, 2004 6:46 am
I don't understand what is so difficult about this.
Code should be kept clear and concise. The two do not always agree, so finding a balance between the two is where style is derived from.
There is no single pure style of coding that I am aware of. So long as obfuscation is minimized, though, I don't see a problem.
Dan.
#22363 - sgeos - Sat Jun 19, 2004 11:36 am
sajiimori wrote: |
Quote: | It certainly makes more sense to me than the notion that small functions should be smaller and large functions should larger. | I would never claim such a thing. |
I don't think you are. I can't tell if you are claiming that verbose is always better, or if shorter is better, or both. I suspect that you are implicitly claiming that one needs to try to find a balance between the two.
Quote: |
Why don't we just keep making our code more and more verbose until it is not at all stressful to read? |
Length has its own costs.[/quote]The cost that length has is the reason that I claimed that the verbosity should be roughly inversely proportional to its length. Are you familiar with the concept that a function should do one thing and do it well? Rarely does a function need to be long and complicated to do one thing well. A compact expression, or a long repetitve setup (switch) are both ways of doing (completely different kinds of) single thing(s) well.
It seems that to directly state that a function's verbosity should be inversely proportional to it's length is a flawed simplification. A function's verbosity should be proportional to its complexity. If a function does one job, and does it well, it's length will usually end up being inversely proportional to its complexity. Therefore a function's verbosity should usually be inversely proportional to its length. poslundc wrote: |
Code should be kept clear and concise. The two do not always agree, so finding a balance between the two is where style is derived from. |
I know that, and I suspect that sajiimori knows that. My goal in this discussion is to stop operating under flawed assumptions, if indeed I am. Alternatively, if there is something imporatant that I have not been exposed to before and do not understand, then I'd like to know about it. Last, if I ever end up programming with sajiimori (or anyone he ends up training), I'd like to do my best to ensure that the logic behind his coding procedures is at the very least acceptable. (It is far better than just acceptable.) poslundc wrote: |
There is no single pure style of coding that I am aware of. |
If I knew of a "single pure style of coding" then I would surely have more important places to be than this forum. poslundc wrote: |
I don't understand what is so difficult about this. |
Evidently your goals in a discussion are different from mine, or you failed to see my goals given either the context or my presentation.
-Brendan
#22378 - sajiimori - Sat Jun 19, 2004 7:24 pm
Quote: |
I can't tell if you are claiming that verbose is always better, or if shorter is better, or both.
|
I can pretty much sum things up this way: Make things as short as you can, and only as verbose as you must.
Imagine you have a function that you can write in many different ways. Each way is acceptable from an efficiency standpoint, and each one could be considered "well written" (i.e. none would be called "obfuscated"). The various methods result in code ranging from 5 lines to 20 lines.
The difference between each version is their density. There is currently no consensus on whether it is better to be dense or sparse. Lisp programmers often believe in dense code, while Python comes with a built-in philosophy that "sparse is better than dense" (just type 'import this' at the command line).
One of the best arguments I've heard in favor of dense code is this: When you are reading dense code, you feel like you're going slower because your eyes are crossing the page more slowly. While reading equivalent sparse code, you feel like you're reading fast because you never pause for long on any given line. In actuality, the speed is about the same, or even slower for sparse code because you have to scroll or turn pages to bring more into your field of vision. You simply cover more material per line in dense code.
One of the best arguments I've heard in favor of sparse code is this: I've had a harder time reading dense code. In reality, dense programs use fewer named variables and more nested expressions, which forces me to hold a larger part of the problem in my head at once. If there is too much for me, I have to mentally or actually rewrite the function in a more sparse manner, doing only subsets of the problem at once and naming the results.
So, I wouldn't argue for density or sparseness for their own sake. I would only argue for short code -- as short as you can while staying within the mental limits of your audience (even if it's only yourself).
Have you ever had to read a textbook that was very sparse? Most of my first-year college books were this way: It seemed like I had to read a whole page before I got any useful information. This is because the author was assuming that giving more information at once would overload his freshman audience. The result is that each sentence has very little content and so very little to keep in mind at once.
Have you ever read a scientific paper or an advanced textbook? People think the main difference is in how big the words are, but that's just a side-effect of the important difference: The author assumes the reader can handle more information at once, and so writes densely (choosing words carefully for maximum effect, even if the words are obscure or long).
Anyway, this post is getting verbose so I'll leave you with that. =)
#22391 - dagamer34 - Sun Jun 20, 2004 12:26 am
sajiimori wrote: |
Quote: |
I can't tell if you are claiming that verbose is always better, or if shorter is better, or both.
|
I can pretty much sum things up this way: Make things as short as you can, and only as verbose as you must.
Imagine you have a function that you can write in many different ways. Each way is acceptable from an efficiency standpoint, and each one could be considered "well written" (i.e. none would be called "obfuscated"). The various methods result in code ranging from 5 lines to 20 lines.
The difference between each version is their density. There is currently no consensus on whether it is better to be dense or sparse. Lisp programmers often believe in dense code, while Python comes with a built-in philosophy that "sparse is better than dense" (just type 'import this' at the command line).
One of the best arguments I've heard in favor of dense code is this: When you are reading dense code, you feel like you're going slower because your eyes are crossing the page more slowly. While reading equivalent sparse code, you feel like you're reading fast because you never pause for long on any given line. In actuality, the speed is about the same, or even slower for sparse code because you have to scroll or turn pages to bring more into your field of vision. You simply cover more material per line in dense code.
One of the best arguments I've heard in favor of sparse code is this: I've had a harder time reading dense code. In reality, dense programs use fewer named variables and more nested expressions, which forces me to hold a larger part of the problem in my head at once. If there is too much for me, I have to mentally or actually rewrite the function in a more sparse manner, doing only subsets of the problem at once and naming the results.
So, I wouldn't argue for density or sparseness for their own sake. I would only argue for short code -- as short as you can while staying within the mental limits of your audience (even if it's only yourself).
Have you ever had to read a textbook that was very sparse? Most of my first-year college books were this way: It seemed like I had to read a whole page before I got any useful information. This is because the author was assuming that giving more information at once would overload his freshman audience. The result is that each sentence has very little content and so very little to keep in mind at once.
Have you ever read a scientific paper or an advanced textbook? People think the main difference is in how big the words are, but that's just a side-effect of the important difference: The author assumes the reader can handle more information at once, and so writes densely (choosing words carefully for maximum effect, even if the words are obscure or long).
Anyway, this post is getting verbose so I'll leave you with that. =) |
I wonder if your post was sparse or dense... :)
_________________
Little kids and Playstation 2's don't mix. :(
#22393 - sajiimori - Sun Jun 20, 2004 1:12 am
Yours was definitely very sparse -- you took almost 30 lines just for a simple question! :O
#22395 - dagamer34 - Sun Jun 20, 2004 3:56 am
sajiimori wrote: |
Yours was definitely very sparse -- you took almost 30 lines just for a simple question! :O |
That's the way to do it! :)
_________________
Little kids and Playstation 2's don't mix. :(