How to recognize that short code blocks can be refactored into something cleaner? - language-agnostic

i have a bit of code that i wrote a few weeks ago (the code's purpose isn't so much important as its structure):
if (_image.Empty)
{
//Use the true image size if they haven't specified a custom size
if (_glyphSize.Width > 0)
imageSize.Width = _glyphSize.Width //override
else
imageSize.Width = _image.GetWidth;
if (_glyphSize.Height > 0) then
imageSize.Height = _glyphSize.Height
else
imageSize.Height = _image.GetHeight
}
else
{
//No image, but they can still override it with a custom size
if (_glyphSize.Width > 0) then
imageSize.Width = _glyphSize.Width
else
imageSize.Width = 0;
if (_glyphSize.Height > 0)
imageSize.Height = _glyphSize.Height
else
imageSize.Height := 0;
}
i was going over it tonight, and as i was cleaning it up, i realized that the cleaned version is must more concise:
//Figure out the final image width
if (_glyphSize.Width > 0)
imageSize.Width = _glyphSize.Width
else if (not _glyph.Empty)
imageSize.Width = _glyph.GetWidth
else
imageSize.Width = 0;
//Figure out the final image height
if (_glyphSize.Height > 0)
imageSize.Height = _glyphSize.Height
else if (not _glyph.Empty)
imageSize.Height = _glyph.GetHeight
else
imageSize.Height = 0;
Note: i've trimmed down the code to bare logical flow, and obfsucated the source language.
In the end i took the nested if's, and inverted them. Doing that allowed this shortening. My question is: how can i recognize this in the future?
What are the tell-tale signs that i've just written some code that can be refactored into something shorter?
Another example i had from a few weeks ago was something akin to a permission check: the user can perform an action:
if they have the permission they can do it
if they don't have the permission, but the override is in effect
Which i initially coded as:
if ((HasPermission || (!HasPermission and OverrideEnabled))
{
...do stuff
}
The logical conditions on that if clause seemed kind of wordy. i tried to reach back to my boolean algebra course to figure out how to simplify it. In the end i could do it, so i ended up drawing a truth table:
Permission Override Result
0 0 0
0 1 1
1 0 1
1 1 1
Which when i look at it is an OR operation. So my if statement became:
if (HasPermission or OverrideEnabled)
{
...
}
Which is obvious and simple. And so now i'm wondering how i couldn't see that to begin with.
Which brings me back to my SO question: What tell-tale signs could/should i be looking for in order to recognize that some block of code needs some TLC?

Here are some guidelines from Code Complete, off the top of my head. That is a good book to get for this sort of thing.
Nested if-else and repeated statements in blocks
Long for-loops
Repeated lines/statements or frequently used operations can be placed in a function
If for some reasons you are copying and pasting a line of code over and over again
I found discrete maths to have an influence in how I wrote if statements now. Usually, I see I am writing two same IF statements in 2 blocks, then I would do some mental 'factoring'.

Specifically related to boolean evaluation, it's worth noting that most(?) modern languages implement lazy evaluation.
That is, if "a" is true, then if(a) and if(a or b) are logically and functionally equivelant; the interpreter stops evaluating when it sees or after a true variable. This isn't very important when a and b are variables, but if they're callables [e.g. if(a() or b())], b() will not get evaluated when a is true.
You can save a lot of keystrokes (and processor time) by learning this well:
if(!userExists()):
if(!createUser()):
errorHandling()
else:
doStuff()
else: doStuff()
becomes
if(userExists() or createUser()): doStuff()
else: errorHandling()

Well done. Now, when I see this:
//Figure out the final image width
if (_glyphSize.Width > 0)
...
//Figure out the final image height
if (_glyphSize.Height > 0)
...
I think there is still more refactoring to do. Extracting code into methods isn't just a great way to eliminate redundant code. It's also a great way to make the code self documenting:
I'd be inclined to reduce the code to:
set_final_image_size
With set_final_image_size and its minions defined like so:
def set_final_image_size:
imageSize.Width = final_image_width;
imageSize.Height = final_image_height;
def final_image_width:
if (_glyphSize.Width > 0)
return _glyphSize.Width;
else if (not _glyph.Empty)
return _glyph.GetWidth;
else
return 0;
def final_image_height:
if (_glyphSize.Height > 0)
return _glyphSize.Height;
else if (not _glyph.Empty)
return _glyph.GetHeight;
else
return 0;

Now that you've separated the width and height logic, and noticed that it's identical - what if you were to add, say, getDimension(Direction direction) and setDimension(Direction direction, int length) to your classes? Now you've got
if (_glyphSize.getDimension(direction) > 0)
imageSize.setDimension(direction, _glyphSize.getDimension(direction))
else if (not _glyph.Empty)
imageSize.setDimension(direction, _glyph.getDimension(direction))
else
imageSize.setDimension(direction, 0);
Extracting the local brings us:
length = _glyphSize.getDimension(direction);
if (length > 0)
imageSize.setDimension(direction, length)
else if (not _glyph.Empty)
imageSize.setDimension(direction, _glyph.getDimension(direction))
else
imageSize.setDimension(direction, 0);
taking it a little further:
length = _glyphSize.getDimension(direction);
if (length == 0 && !_glyph.Empty)
length = _glyph.getDimension(direction);
imageSize.setDimension(direction, length);
Which, to my eyes at least, is starting to look pretty nice.

Related

Program won't call correct function based on input. No idea what I'm missing

EDIT: After playing around a bit in main(), it seems like the program is choosing whichever function is being called in the if/elif block regardless of input. I have no idea why it started doing this after working fine
I've gone over and over my code, and I can't figure out what I'm not seeing.
It's a number sequence game, and it asks the user to choose a difficulty between easy and hard. It was working just fine at one point, but now no matter what is selected, it goes to easy mode each time. Even you hit enter without any input at all.
#main program function and difficulty selection
def main():
print('-----------------------------------------------')
print('Please choose a difficulty.')
difficulty = str(input('(e)asy|(h)ard: '))
print('-----------------------------------------------')
if difficulty == 'easy'or'e':
easy()
elif difficulty == 'hard'or'h':
hard()
Then I have a function for easy and one for hard.
Hard is just the easy function, with only a change to the size of the sequence generated and nothing else. I've gone over each block and nothing is changed that would affect which function is called.
It happens regardless of how many times the game is played, so it has to be something wrong with my main() function
The rest of the code is here if that helps, maybe I'm missing something obvious.
import random
def easy():
print ('Easy Mode','\n')
#Generates inital number, step value, and upper limit
num_sequence = 5
numbers = random.randint(1,101)
step = random.randint(1,20)
#Accumulates and prints all but last number in sequence
for num_generated in range (1, num_sequence):
print(numbers)
numbers = numbers + step
#Sets tries allowed and subtracts wrong attempts
guesses = 3
while guesses > 0:
user_num = int(input('Next Number: '))
guesses = guesses - 1
if user_num != numbers:
if guesses == 0:
break
else:
print('Try Again (Attempts Remaining:', guesses,')')
if user_num == numbers:
break
#Prints appropriate message based on game results
if user_num == numbers:
print ('Correct','\n')
if user_num != numbers:
print ('Attempts Exceeded: The answer was',numbers,'\n')
#block for hard difficulty (same as above, sequence size changed to 4)
def hard():
print ('Hard Mode','\n')
num_sequence = 4
#main program function and difficulty selection
def main():
print('-----------------------------------------------')
print('Please choose a difficulty.')
difficulty = str(input('(e)asy|(h)ard: '))
print('-----------------------------------------------')
if difficulty == 'easy'or'e':
easy()
elif difficulty == 'hard'or'h':
hard()
#block for replay selection
replay = 'y'
while replay == 'y':
main()
replay = input('Play again? (y)|(n): ',)
print ('\n')
if replay == 'n':
print('-----------------------------------------------')
print('Goodbye!')
print('-----------------------------------------------')
break
hard() is the same code as easy() line for line after those first few
When you are making a compound comparison (using the or) both sides of the condition must be complete. In other words,
if difficulty == 'easy'or difficulty == 'e':
easy()
elif difficulty == 'hard'or difficulty == 'h':
hard()
Otherwise you are saying "if difficulty == 'easy' >> which is false, then assign difficulty to 'e'" which was not the intent.

Opposite of 'else' during a switch or conditional

I'm wondering if any programming language has an operator like so (ALWAYS is a placeholder--I'm asking what language has something like ALWAYS)
if a
doAStuff()
else if b
doBStuff()
ALWAYS
//runs if a or b is true
win()
else
doElse()
Basically, the opposite of else. It runs if something else in the statement ran.
logically, it would be like this
always = true
if a
doA()
else if b
doB()
else
always = false
doElse()
if always
win()
Does any language have that logic built into a keyword, such as ALWAYS from the first example?
Not really 'language-agnostic'. More like 'find-my-language'. With Forth and Lisp you can add such a construct naturally to the language, and it will work just like existing constructs. I'm not aware of any language that has it by default. If you have a less extensible language than Forth or Lisp, then the natural ways to do this are to use a local function (if you have first-class functions) or to set a flag as you show, or else to factor the code such that both conditions can be treated as pairs without a lot of repetition.
So, in JavaScript:
;(function() {
function both() { win(); more stuff, potentially }
if (a) { doA(); if (b) both() }
else if (b) { doB(); if (a) both() }
else neither()
})()
At upon reading that, it should be clear that the 'both' case is never going to happen in that second block. So this simplifies to:
;(function() {
function both() { win(); more stuff, potentially }
if (a) { doA(); if (b) both() }
else if (b) doB()
else neither()
})()
Which doesn't seem worth the effort. So it seems even less worth a language feature. Why not go further and write this?
if (a) { doA(); if (b) { win(); more stuff, potentially } }
else if (b) doB()
else neither()
If b is an expensive test, just save the result of it. If b must not be tested before a, save both results. Obviously, both tests must always be run anyway.
;(function() {
var a = testA(),
b = testB()
... as above ...
})()
As for the last option, "factor the code such that both conditions can be treated as pairs", what you're looking for is:
if (a && !b) doA()
if (!a && b) doB()
if (a && b) { doA(); doB(); win() } // or no doB() if you really want that
if (!a && !b) neither()
With else if if you like. I'd prefer this option actually in a pattern-matching language. Mercury will even throw an compile-time error if you forget one of the four possible outcomes.
Not sure if this is what you're looking for, but a simple do-while loop will ALWAYS run at least once in Java.

Keeping the variable 's value in recursive function, python 3.3

I managed to do it, some other way.
but I have a question, I had this code before
def jumphunt(start, mylist, count = 0):
if count < len(mylist):
place = mylist[start]
print(place)
if place == 0:
return True
elif start >= len(mylist) or start < 0:
return False
move_left = (start - place)
move_right = (start + place)
return jumphunt(move_right, mylist, count+1) or jumphunt(move_left, mylist, count+1)
else:
return False
but for some reason it's not trying both ways
to get to the last item on the list.
for example: [1,2,2,3,4,5,3,2,1,7,0] and ,start=mylist[0]
it supposed to jump like this (from 1-2-4-1-left to 2-left to 5-right to 0)
but it keeps trying to go right and then index is out of range etc.
I thought that if u use return of or this or that, it will try both until it reaches True, why won't it work here?
Thanks!
Include the value you want to keep as a default parameter for the method, like this:
def my_func(int, list, i=0):
a = (i + int)
if int == 0:
return True
elif a > len(list):
i -= int
else:
i += int
int = list[i]
my_func(int, list, i)
Bear in mind that it may not even always be possible to arrive at the end of the list doing the jumping pattern you describe, and even if it is possible, this method may choose the wrong branch.
A better algorithm would look like this:
def branching_search(list, start):
marks = [0]*len(list)
pos = start
while list[pos]!=0:
marks[pos]++
if marks[pos] % 2 == 0 and pos + list[pos] < len(list):
pos += list[pos]
elif marks[pos] % 2 == 1 and pos - list[pos] >= 0:
pos -= list[pos]
else:
return False
if all(item == 0 or item > 1 for item in list)
return False
return True
This way, if it comes to an item that it has already visited, it will decide to go the opposite direction that it went last time. Also, if it comes to an item that it can't leave without going out-of-bounds, or if there is not way to get to the end, it will give up and return.
EDIT: I realized there are a number of flaws in this algorithm! Although it is better than the first approach, it is not guaranteed to work, although the reasons are somewhat complicated.
Just imagine this array (the unimportant elements are left blank):
1, 2, , 5, , , , , 5, 0
The first two elements would get only one mark (thus the loop checking condition would not work), but it would still get stuck looping between the two fives.
Here is a method that will always work:
def flood_search(list):
marks = [[]]*len(list)
marks[0] = [0]
still_moving = True
while still_moving:
still_moving = False
for pos in range(0,len(list)):
if marks[pos]:
if pos + list[pos] < len(list) and not marks[pos + list[pos]]:
marks[pos + list[pos]] = marks[pos] + [list[pos]];
pos += list[pos]
still_moving = True
if pos - list[pos] >= 0 and not marks[pos - list[pos]]:
marks[pos - list[pos]] = marks[pos] + [-list[pos]];
pos -= list[pos]
still_moving = True
return marks[-1]
This works by taking every possible branch at the same time.
You can also use the method to get the actual route taken to get to the end. It can still be used as a condition, since it returns an empty list if no path is found (a falsy value), or a list containing the path if a path is found (a truthy value).
However, you can always just use list[-1] to get the last item.

Actionscript 3.0....x>y>z not working

probably a pretty simple question here, but I find it weird. Luckily I found a way around it, but the fact that what I did works and what I have in the title doesn't work is confusing the hell out of me!
I just have a simple if statement...then execute a function. This code works:
if (200 > (x-target.x) && (x-target.x) > 0)
fireWeapon();
yet this code doesn't!
if (200 > (x-target.x) > 0)
fireWeapon();
AS3 does not give me an error either....It just simply does an if statement for the condition
if (200 > (x-target.x))
and seems to ignore the statement where it must be greater than 0. I would like to use the shorter, more mathematically nice looking method in the future, so let me know if there is a way around doing the && sign! Thanks.
if (200 > (x-target.x) > 0) code is working. but what you think is different. computer in order to interpret one sentence. Is evaluated as follows.
1) 200 > ( x-target.x ) If 200 is larger than (x-target.x) return true, not false.
2) true(1) or false(0) > 0 If left-statement is true return true,(because 1 is larger than 0) not false.
As a result, If 200 is larger than (x-target.x) always return true, not false. In general, the syntax used in the computer language is not the same as mathematic syntax.
And you want x> y> z must change to x>y && y>z && x>z.

As3 strange If statement evaluation behaviour

I am writing a small game for a bit of fun. It's a simple turn based battle game kind of like Pokemon style battles but with stupid/joke characters.
I have some stuff on the main timeline for user interface but everything else is handled in external actionscript files. I have a class for a battle which has some battle related methods like attack etc and I also have characters as their own classes which inherit from an interface.
In my user interface there are some buttons and when a battle commences I have an event listener on my attack button which executes the following code each time:
public function attack(attacker:Character, defender:Character):void
{
var defenderHp:int;
var attackPower:int;
var postAttackHp:int;
defenderHp = defender.getHP();
attackPower = attacker.getAttack();
if (! passiveBlock(defender))
{
if (! criticalStrike(attacker))
{
trace("defender hp trace: " + (defenderHp - attackPower));
postAttackHp = (defenderHp - attackPower);
}
else
{
trace("defender hp trace: " + Math.floor((defenderHp - (attackPower*1.5))));
postAttackHp = Math.floor((defenderHp - (attackPower*1.5)));
displayText = attacker.getName() + " landed a critical strike!";
}
if (! postAttackHp > 0)
{
gameIsOver(attacker, defender);
}
else
{
defender.setHP(postAttackHp);
}
}
else
{
displayText = defender.getName() + " blocked the attack!";
}
}
The code gets called by the button fine every time, the problem lies in the if (! postAttackHp > 0) condition. For some reason only occasionally does the game over method get called when the defender's HP goes below 0. I am tracing the postAttackHp variable out each time and I can see every time that it is below 0 but the if statement more often than not skips down to the else section.
What is strange is that sometimes it works properly and sometimes it does not but it is more frequently not working.
Is there something fundamentally stupid about the way this is set up?
Thanks in advance for your help :)
I don't have Flash installed on this machine, or else I would try to see if this is the issue, but my first guess would be that
! postAttackHp > 0
is evaluating as (! postAttackHp) > 0. In this case, it would only be true if postAttackHp were == 0. Anything else, even a negative number, would evaluate to False, since ! -10 = False. False > 0 is False, since typecasting False would leave it as 0.
Try either,
if (! (postAttackHp > 0))
or
if (postAttackHp <= 0)