ifs considered harmful - sddconf.com

33
ifs considered Harmful Or; how to eliminate 90% of your bugs and 99% of your technical debt in one easy step. Jules May JulesMay.co.uk

Upload: others

Post on 14-Nov-2021

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: ifs considered Harmful - sddconf.com

ifs considered Harmful

Or; how to eliminate 90% of your bugs and 99% of your technical debt in one easy step.

Jules MayJulesMay.co.uk

Page 2: ifs considered Harmful - sddconf.com

Codebase survey

n ~2.5 million linesn 5 years developmentn 6-25 developers

Bugs: secondaryBugs: primary

Bugs: all

Page 3: ifs considered Harmful - sddconf.com

goto considered harmful

Edsger Wybe Dijkstra (1930-2002)

EWD 215: A case against the goto statement (1968)

https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF

“Goto statement considered harmful”, Commun. ACM 11 (1968), 3: 147–148.

Page 4: ifs considered Harmful - sddconf.com

goto considered harmful - why?

What a program looks like: What a program means:

n Static mapn Spatial - locations

n Dynamic processn Temporal - instants

Execution coordinate

Page 5: ifs considered Harmful - sddconf.com

Execution coordinate10: a=10;11: b=20;12: c=a+b;13: print (c);14: d=sqrt (c);15: end;

Page 6: ifs considered Harmful - sddconf.com

Execution coordinate10: a=10;11: b=20;12: c=a+b;13: print (c);14: d=sqrt (c);15: end;

10:11:12:13:14:15:

Rt:4124:Rt:4126:Rt:4125:Rt:4128:Rt:4127:

Rt:9178:Rt:9179:Rt:9180:

Page 7: ifs considered Harmful - sddconf.com

11(1):11(2):11(3):15:10:

12:13:14:

Execution coordinate10: a=10;11: for b=(1..3) {12: c=a+b;13: print (c);14: d=sqrt (c);15: }

Page 8: ifs considered Harmful - sddconf.com

Execution coordinate - fail?

10:11:12:13:14:15:16:17:18:19:

10: a=9;b=-1011: if b=11 goto 18;12: b=b+1; 13: if b>12 goto 10;14: c=a+b;15: if c<0 goto 11;16: print c;17: d=sqrt (c);18: goto 12;19: end;

Page 9: ifs considered Harmful - sddconf.com

Execution coordinate

n Coordinate is tuple of (location or repetition)q e.g. [11(2), 13, Rt:4126]

n Shows us (for structured code):q Location in codeq Moment in execution timeq Entire history leading up to that moment.

n Not all gotos violate ‘structure’:q return, continue, breakq loopsq assembler

- take-away

Page 10: ifs considered Harmful - sddconf.com

Execution coordinate - the problem10: for b=(-1..1) {11: if (b<0) 12: print (GORED);13: else14: print (GOBLUE);15: print (b);16: if (b<0)17: print (‘ DR\n’);18: else19: print (‘ CR\n’);20: }

Page 11: ifs considered Harmful - sddconf.com

Execution coordinate - the problem10: for b=(-1..1) {11: if (b<0) 12: print (GORED);13: else14: print (GOBLUE);15: print (b);16: if (b<0)17: 18: else19: 20: }

10: for b=(-1..1) {11: if (b<0) {12: print (GORED);13: print (b);14: print (‘ DR\n’);13: } else {14: print (GOBLUE);15: print (b);16: print (‘ CR\n’);19: }20: }

print (‘ DR\n’);

print (‘ CR\n’);

>

Page 12: ifs considered Harmful - sddconf.com

Execution coordinate

goton Destroys temporal identityn Destroys historyn Creates flow ‘spaghetti’

Imply goto from code structure

n Not all gotos are evil

if..ifn Conflates temporal identityn Destroys historyn Creates flow ‘wormholes’

Imply decision from code structure

n Not all conditions are evil

- summary

Page 13: ifs considered Harmful - sddconf.com

ifs considered harmful

n Need a new notion of ‘if-structure’:q Conditions are ‘concentrated’q Decisions are implied

n Need new mechanisms for if q Don’t overstay your welcomeq Specialist classes & downcasting

n Need to express those in conventional languages

Page 14: ifs considered Harmful - sddconf.com

ifs considered harmful

Assert

Page 15: ifs considered Harmful - sddconf.com

ifs considered harmful - assertfloat sqrt (a) {

assert (isNumeric (a)) or error (‘Numeric type required’);assert (a>=0) r = // do some computation on areturn r;

}

or error ()or throw DomainError (…);

n Principle: not to control the flow, but to abort it.n Species:

assert (…) or return (); -- return default value or null objectassert (…) or throw …; -- refuse to process; contract violationassert (…) or die (); -- do shutdown or recovery processassert (…) or error (); -- Generate compile-time error (if possible)

Page 16: ifs considered Harmful - sddconf.com

ifs considered harmful

In practice:n It’s easy:

q if (!condition) throw …;

n assert () or error needs compiler support.

- assert

Page 17: ifs considered Harmful - sddconf.com

ifs considered harmful

Don’t overstay your welcome

Page 18: ifs considered Harmful - sddconf.com

ifs considered harmful - Values

number fact (number n) {if (n==1)

return 1;else

return n*fact(n-1);}

fact (1)=1;fact (number n)=n*fib(n-1);fact (string s)=“Can’t fact ”+s;

string fact (string s) {return “Can’t fact ” + s;

}

Page 19: ifs considered Harmful - sddconf.com

ifs considered harmful - Valuesfor b=(-1..1) {

if (b<0) print (GORED);

elseprint (GOBLUE);

print (b);if (b<0)

print (‘ DR\n’);else

print (‘ CR\n’);}

for b=(-1..1) {print fmt (b);

}

string fmt (number b<0){return GORED + b + ‘ DR\n’;

}string fmt (number b){

return GOBLUE + b + ‘ CR\n’;}string fmt (number b=0){

return GOBLACK + ‘nil\n’;}

Page 20: ifs considered Harmful - sddconf.com

ifs considered harmful - Values

In practice:n Do conditions before anything else,

q e.g. fact examplen Use ordinary polymorphism over specialist

classesq e.g. fmt (plusMoney (b)) {…};

n Use Haskell!

Page 21: ifs considered Harmful - sddconf.com

ifs considered harmful

Specialists

Page 22: ifs considered Harmful - sddconf.com

ifs considered harmful - specialists

class littleClass {}

class bigClass {littleClass c = null;

bigClass () {} // ctor. might set c;

bigMethod () {if (isNull (c)) {

// do something}else {

// do something similar involving c;}

}}

Page 23: ifs considered Harmful - sddconf.com

ifs considered harmful - specialistslittleClass c = 4; -- means: c = littleClass (4);littleClass c = null; -- means c = null;

-- should mean: c = littleClass (null);

Null objectn Exposes the class interfacen Can be used naively

n All uses can be checked at compile time

Null pointern No interface at alln Needs if !isNull() on

each usen All uses must be checked

at runtime

Page 24: ifs considered Harmful - sddconf.com

ifs considered harmful - specialists

class littleClass {}

class bigClass {littleClass c = null;

bigClass () {} // ctor. might set c;

bigMethod () {if (isNull (c)) {

// do something}else {

}

-- now means: c = littleClass (null);

// do something involving c

}}

littleClass (null);

Page 25: ifs considered Harmful - sddconf.com

ifs considered harmful

Specialists and downcasts

Page 26: ifs considered Harmful - sddconf.com

ifs considered harmful - downcasts

class littleClass {private littleClass () {…}

class littleNull:littleClass {littleNull () {…} //ctor// implementations

}

class littleInt:littleClass {littleInt (int k) {…} //ctor// implementations

}

class littleThing:littleClass {littleThing (object obj) {…}// implementations

}

// declarations// methods

}littleClass ()

-> littleNull ();littleClass (int k)

-> littleInt (k);littleClass (object obj)

-> littleThing (obj);

Every method has an implied condition: if (this.isInstanceOf (thisClass)) {…}

Page 27: ifs considered Harmful - sddconf.com

ifs considered harmful - downcastsfor b=(-1..1) {

if (b<0) print (GORED);

elseprint (GOBLUE);

print (b);if (b<0)

print (‘ DR\n’);else

print (‘ CR\n’);}

for b=(-1..1) {print (money (b));

}

class money:number { //string number:toString () inheritedprivate money (number (n)) {}

private class plusMoney:money {toString () { return GOBLUE + :toString() + “CR\n”);}

}private class minusMoney:money {

toString () { return GORED + :toString() + “DR\n”);}}money (number n) -> n>=0 ? plusMoney (n) : minusMoney (n);

}

Page 28: ifs considered Harmful - sddconf.com

ifs considered harmful

In practice:n Use abstract base classes with static factory

methods,q e.g. x=myclass:new (…);

n Expose the subclasses directlyq e.g. money b = plusMoney (4);

n Precompileq e.g.

abstract downcastable class myclass {…};new myclass(…) -> myclass:factory (…)

- downcasts

Page 29: ifs considered Harmful - sddconf.com

ifs considered harmful

n goto is harmful.

n It causes spaghetti code, which is unreliable.

- Summary

n Actually, it was always if that was harmful.

n It causes wormhole code, which is unreliable.

Page 30: ifs considered Harmful - sddconf.com

ifs considered harmful - Summary

n The antidote to goto is ‘flow-structure’

n Structured languages replace goto with:q for

q while

q throw

n The antidote to ifis ‘decision-structure’

n A decision-structured language would replace if with:q assert () or …

q value-polymorphismq downcasts

Page 31: ifs considered Harmful - sddconf.com

ifs considered harmful - Summary

n If you’re careful, you can do structured programming with gotos.

n If you’re careful, you can do decision-structured programming with ifsq …while you’re waiting for

language technology to catch up.

Page 32: ifs considered Harmful - sddconf.com

Take-aways

n (Misuse of) if causes more bugs than all other causes combined.

n This shouldn’t be news – it’s goto all over again;

n We need decision-structured language constructs;

n In the meantime, good programming hygiene helps.

Page 33: ifs considered Harmful - sddconf.com

ifs considered harmful

Questions?

JulesMay.co.uk

Bugs: secondaryBugs: primary