Computer Science Canada

Programming Efficiency (Lines of code vs Code run)

Author:  LegendsEnd [ Tue May 30, 2006 8:46 pm ]
Post subject:  Programming Efficiency (Lines of code vs Code run)

Just out of curiosity, I was wondering which way is the better way to program.

Main Code to Compare to:

code:

var text : string
get text
if text = "Hi" then
    put "Hi"
    put "Hi"
    put "Hi"
    put "Hi"
elsif text = "Hey" then
    put "Hey"
    put "Hi"
    put "Hi"
    put "Hi"
else
    put "Bye"
    put "Bye"
    put "Bye"
end if


First modified version, causes a 2nd if statement to be read, but shortens code.

code:

if text = "Hi" or text = "Hey" then
    if text = "Hi" then
        put "Hi"
    else
        put "Hey"
    end if
    put "Hi"
    put "Hi"
    put "Hi"
else
    put "Bye"
    put "Bye"
    put "Bye"
end if


Second modified version, shortens code but adds a useless procedure. Imagine a NPC that follows this code in an rpg with 10,000+ lines of code. In that sea of code, would it be efficient to create a procedure just to shorten the code a few lines for this one NPC? (I know it only shortens it by one line, just imagine it was Put10 or something. This is a tough example to show because with put text it's easy to do a loop, again, just imagine the put statements are a more difficult procedure that can't be looped easily Razz).

code:

procedure Put3 (word : string)
    put word
    put word
    put word
end Put3
var text : string
get text
if text = "Hi" then
    put "Hi"
    Put3 ("Hi")
elsif text = "Hey" then
    put "Hey"
    Put3 ("Hi")
else
    Put3 ("Bye")
end if

Author:  Tony [ Tue May 30, 2006 9:04 pm ]
Post subject: 

it's all on the same order of magnitude here. I suggest going with a version of the code that is easier to read, understand, and maintain.

Author:  Delos [ Tue May 30, 2006 9:10 pm ]
Post subject: 

This is a good question to raise, and I'm sure a lot of others will have some informative things to say on it. Here's my take:
- first off, read wtd's Tut on Premature Optimization. It's theory laden, code lacking, but will put you into the right mindset you need.
- in general, procedures and fcns are your friends. Moreso fcns, as recent waves have been propagating towards.
If you find yourself in a situation where you could either (semi-)hardcode certain values, or create a method that would handle them, and you find that that method would essentially be limited to that instance - chances are you're looking too closely. Take a step back and look at the broader picture. Are there other instances when your NPCs have a choice of things to say? Is it possible that these might also include some form of repitition in them? If so, then why not make a method that is a little broader in scope? Since you're working in Turing and fcn overloading is not possible, this will inevitably mean more paramters (check out the latest Tut by Cervantes for an intro to theoretical fcn overloading). This is not much of a problem, since you're working with a play-off: either more methods w/ fewer (more specific) parameters in each, or fewer with more (and potentially redundant/useless) parameters in each.
For instance, you might end up with a method that allows the NPC to say one of 3 things, to repeat certain things, to provide choices, to sell items. All of these could be encompassed in a single method that takes perhaps 4 or more paramters, or a couple of smaller methods. In all likelihood, you'll end up with a single "main" method that calls a number of other ones...
Where does this leave you? Aside from a bit of a headache trying to visualize my ramblings, it also gets you to realize that sometimes you really, really have to be creative!

In your example:
code:

proc puts (inStr : string, num : int)
    put repeat (inStr + "\n", num)..
end puts

var text : string
get text

if text = "Hi" or text = "Hey" then
    puts ("Hey", index (text, "Hey"))
    puts ("Hi", 3)
else
    puts ("Bye", 3)
end if

Sneaky, eh?

Author:  Cervantes [ Tue May 30, 2006 9:12 pm ]
Post subject: 

Technically a procedure call does slow down your program, but the difference is small compared to the task of outputting text, and is completely unnoticeable when you think of how fast all of that code is going by.

As Tony said, pick the coding style that is easiest to write, read, and maintain. This means picking the procedure one. It also means not hardcoding your dialogues into your program. Rather, use files. Do some research and find out popular styles of formatting files to create dialogues. Complex dialogue systems like those of the Baldur's Gate series (and its derivatives) would be cool to implement yourself.

When making your program,
1) Make it work
2) Make it work well
3) Optimize it

Tony Hoare wrote:
Premature optimization is the root of all evil.

Author:  LegendsEnd [ Tue May 30, 2006 9:15 pm ]
Post subject: 

Quote:
If you find yourself in a situation where you could either (semi-)hardcode certain values, or create a method that would handle them, and you find that that method would essentially be limited to that instance - chances are you're looking too closely. Take a step back and look at the broader picture. Are there other instances when your NPCs have a choice of things to say? Is it possible that these might also include some form of repitition in them? If so, then why not make a method that is a little broader in scope?


And if there are no other instances yet the lines of code is reduces by 10-20+ lines?

Author:  Cervantes [ Tue May 30, 2006 9:20 pm ]
Post subject: 

Delos wrote:

In your example:
code:

proc puts (inStr : string, num : int)
    put repeat (inStr + "\n", num)..
end puts

var text : string
get text

if text = "Hi" or text = "Hey" then
    puts ("Hey", index (text, "Hey"))
    puts ("Hi", 3)
else
    puts ("Bye", 3)
end if

Sneaky, eh?

Hurray for obfuscated code! Smile

Author:  LegendsEnd [ Tue May 30, 2006 9:20 pm ]
Post subject: 

Cervantes wrote:
Technically a procedure call does slow down your program, but the difference is small compared to the task of outputting text, and is completely unnoticeable when you think of how fast all of that code is going by.

As Tony said, pick the coding style that is easiest to write, read, and maintain. This means picking the procedure one. It also means not hardcoding your dialogues into your program. Rather, use files. Do some research and find out popular styles of formatting files to create dialogues. Complex dialogue systems like those of the Baldur's Gate series (and its derivatives) would be cool to implement yourself.


Sorry for the double post, didn't see this one until after my previous post. If the task was not outputting text, but rather say a large block of code that is repeated 3 times? Where the block of code has no relevence whatsoever however in other parts of the program and is insiginificant when compared to the program. Does this block of code deserve a procedure?

Also, I don't think I've ever heard of these complex dialogue systems, i'll try to take a look. If you have a link handy it would help, although I doubt I can learn and implement it in time. There isn't much time left before the end of the school year to hand in my program Sad.

Author:  codemage [ Wed May 31, 2006 8:23 am ]
Post subject: 

My $0.02

1) There is a school of thought that says that any large, continuous chunks of code should be removed from the main program area and placed in some sort of module (classes, procedures, functions.) I tend to agree - this makes your main program area very easy to trace through, and makes your code more modular in general.

2) There is nothing wrong with slick, tight, obfuscated code if
A - it actually makes your code run faster (if not - there's no real world point in showing off).
B - you comment it clearly

Author:  Delos [ Wed May 31, 2006 9:28 am ]
Post subject: 

Cervantes wrote:

Hurray for obfuscated code! Smile


Laughing Indeed. I just thought of a second streamline to it:

code:

proc puts (inStr : string, num : int)
    put repeat (inStr + "\n", num)..
end puts

var text : string
get text

puts ("Hey", index (text, "Hey"))
puts ("Hi", 3 * index (text, "H"))
puts ("Bye", 3 * index (text, "Bye"))



And to answer codemage's request for commenting...
- the proc outputs inStr a number of times, ordained by num. Additionally, it places each one a new line (+ "\n").
However, the use of the '..' (forget what it's called) allows the next output afterwards to be placed on the line directly after, as opposed to after a break. i.e.:
Output wrote:

Hey
Hi
Hi
Hi

vs.

Hey

Hi
Hi
Hi


The actual puts() lines are the fun ones! I've been able to eliminate the need for an if clause by use of the conditionality intrinsic to the words themselves. If the string "Hey" is found, index will return 1. Hence "Hey" will be outputted once.
If an "H" is found, index will return 1, this will be multiplied by 3, and hence outputted 3 times. "H" is used as opposed to "Hi" since "Hi" ought to be outputted even if "Hey" is inputted.
The "Bye" call is analagous.

Of course this is a very limited situation. It works in this case, and only in this case. Which illustrates another point quite succinctly. codemage said to comment your code - even more so importantly and descriptively if it is obfuscated (as this is). You may find when you're going back that certain optimizations can only be applied to a miniscule area of your code. Commenting them will alert you of this, and save you having to try to decypher then implement such methods elsewhere, where they'd be doomed to fail.
Case in point: the above method only works when the valid inputs are {"Hi, "Hey", "Bye"}. It would not do what it's supposed to if "Oh, Hey" was an option...for index()ing reasons.
It was an awsome solution to the problem, but I lost the ability to further it without having to do a major REWRITE.

Does this sound like a contradiction of what I said before? I seem to be saying "It's good to tighten up segments of code, even if it means using methods not applicable elsewhere" when previously I was saying "try your darndest to use methods as widely applicable as possible!". There is obviously truth in both paradigms - and moreso in the words expressed by Tony and Cervantes (legibility, maintenance, understanding trump) - but as this was a question about optimization I will say this: code with a sound plan in mind (and on paper!) so as to avoid bulk, debug and optimize with generality in mind, then if time presents itself (and it rarely does) go for the satisfying hunt of individual optimizations.

I'm curious to know what others think of this stratagem. How important are elegant solutions to your coding, if it does mean few outside applications? Would you sacrifice clarity for the sake of a more complex, 'smarter', and potentially code-shortening solution? Of course timing plays into this, but who's to say which of the two methods would be faster...

Author:  LegendsEnd [ Wed May 31, 2006 10:38 am ]
Post subject: 

codemage wrote:
My $0.02

1) There is a school of thought that says that any large, continuous chunks of code should be removed from the main program area and placed in some sort of module (classes, procedures, functions.) I tend to agree - this makes your main program area very easy to trace through, and makes your code more modular in general.


What constitutes large? In a program with 2000 lines of code, would a chunk of code that is 6 lines being repeated 3 times be a candidate to be removed and modulized?

Author:  codemage [ Wed May 31, 2006 1:01 pm ]
Post subject: 

I was taught that anything over 5 lines is a good candidate, but I'm of the impression that a lot of professors are far more anal-retentive than the industry norm.

Something that is frequently repeated is a candidate at any length. For example, a 3-line swap with a temp variable is common enough in some apps that a separate proc is warranted.

For linear sections of code, I'll usually code a function / proc for something that is 20 lines-ish, just to clean up the main program area.

I'm sure there are 1000 different opinions on this. A few of them are probably justifiable. Wink

Author:  md [ Wed May 31, 2006 1:07 pm ]
Post subject: 

There are these nifty thigns called inline functions in many languages. They look like functions, but when you compile the code is inserted inline removing the costly function call. You get the added maintainability of a function with the speed of inline code.

Author:  wtd [ Wed May 31, 2006 1:28 pm ]
Post subject: 

Two words for this thread:

Premature. Optimization.

Author:  Cervantes [ Wed May 31, 2006 6:16 pm ]
Post subject: 

codemage wrote:
I was taught that anything over 5 lines is a good candidate, but I'm of the impression that a lot of professors are far more anal-retentive than the industry norm.


Five lines? I'd use subroutines far more lavishally than that. But I guess it does somewhat depend upon the programming paradigm you're working with. Object oriented programming or functional programming encourages the creation of subroutines (methods / functions), whereas imperative programming less so. Still, whenever a subroutine takes a parameter and does something important with it, you're not only reducing the number of lines of code, you're reducing the amount of hardcoding you're doing.


: