Experiences Reviewing Scientific C Code Marc Paterno f

  • Slides: 18
Download presentation
Experiences Reviewing Scientific C++ Code Marc Paterno f CD/Special Assignments

Experiences Reviewing Scientific C++ Code Marc Paterno f CD/Special Assignments

Outline Background n Abstraction n Need, use and misuse Libraries n n Standard library

Outline Background n Abstraction n Need, use and misuse Libraries n n Standard library HEP libraries

Most useful feature of C++ n Clearly, the most useful: support for abstraction, both

Most useful feature of C++ n Clearly, the most useful: support for abstraction, both in OO design and generic programming To appreciate this, let’s have a look at where we’re coming from… minimally structured FORTRAN.

SUBROUTINE DECOMP(NDIM, N, A, COND, IPVT, WORK) IMPLICIT DOUBLE PRECISION (A-H, O -Z) DIMENSION

SUBROUTINE DECOMP(NDIM, N, A, COND, IPVT, WORK) IMPLICIT DOUBLE PRECISION (A-H, O -Z) DIMENSION A(NDIM, N), WORK(N), IPVT(N)=1 IF(N. EQ. 1)GOTO 80 NM 1=N-1 ANORM=0. 0 DO 10 J=1, N T=0. 0 DO 5 I=1, N T=T+DABS(A(I, J)) 5 CONTINUE IF(T. GT. ANORM)ANORM=T 10 CONTINUE DO 35 K=1, NM 1 KP 1=K+1 M=K DO 15 I=KP 1, N IF(DABS(A(I, K)). GT. DABS(A(M, K))) M=I 15 CONTINUE IPVT(K)=M IF(M. NE. K)IPVT(N)=-IPVT(N) T=A(M, K)=A(K, K)=T C IF(T. EQ. 0. 0)GOTO 35 C DO 20 I=KP 1, N A(I, K)=-A(I, K)/T 20 CONTINUE C DO 30 J=KP 1, N T=A(M, J)=A(K, J)=T IF(T. EQ. 0. 0)GOTO 30 DO 25 I=KP 1, N A(I, J)=A(I, J)+A(I, K)*T 25 CONTINUE 30 CONTINUE 35 CONTINUE

40 45 50 55 60 DO 50 K=1, N T=0. 0 IF(K. EQ. 1)GOTO

40 45 50 55 60 DO 50 K=1, N T=0. 0 IF(K. EQ. 1)GOTO 45 KM 1=K-1 DO 40 I=1, KM 1 T=T+A(I, K)*WORK(I) CONTINUE EK=1. 0 IF(T. LT. 0. 0)EK=-1. 0 IF(A(K, K). EQ. 0. 0)GOTO 90 WORK(K)=-(EK+T)/A(K, K) CONTINUE DO 60 KB=1, NM 1 K=N-KB T=0. 0 KP 1=K+1 DO 55 I=KP 1, N T=T+A(I, K)*WORK(K) CONTINUE WORK(K)=T M=IPVT(K) IF(M. EQ. K)GOTO 60 T=WORK(M)=WORK(K)=T CONTINUE 65 70 80 90 YNORM=0. 0 DO 65 I=1, N YNORM=YNORM+DABS(WORK(I)) CONTINUE CALL SOLVER(NDIM, N, A, WORK, IPVT) ZNORM=0. 0 DO 70 I=1, N ZNORM=ZNORM+DABS(WORK(I)) CONTINUE COND=ANORM*ZNORM/YNORM IF(COND. LT. 1. 0)COND=1. 0 RETURN COND=1. 0 IF(A(1, 1). NE. 0. 0)RETURN COND=1. 0 E 32 RETURN END

The most problematical feature… n Unfortunately the most problematical feature of C++ has also

The most problematical feature… n Unfortunately the most problematical feature of C++ has also been abstraction, generally in the context of OO design. It is not always easy to determine the right level of abstraction for a given use. For many physicists, previous programming experience doesn’t apply -- new techniques have to be learned.

Common mistakes with abstraction n Missing the useful abstraction n Too many abstractions n

Common mistakes with abstraction n Missing the useful abstraction n Too many abstractions n n Classes used as structs, if used at all Procedural code, where OO would be better Many levels of inheritance Base classes never used Often, casting required Classes that are too large n n Too many tasks performed by a single class Resulting classes are difficult to understand use

Missing the Abstraction n Common Mistake #1: missing class n n n Common Mistake

Missing the Abstraction n Common Mistake #1: missing class n n n Common Mistake #2: do-nothing class n n n Set of functions pass around a common set of arguments, or perhaps an array Users have to keep track of the arguments themselves Contains set & get methods Users extract values, perform calculations themselves Often not hard to solve: refactoring

Missing class functionality XList* Alg: : create. XList(const Hit& hit 1, const Hit& hit

Missing class functionality XList* Alg: : create. XList(const Hit& hit 1, const Hit& hit 2) { XList* list = new XList; double x 1 = hit 1. pos(). x(); double y 1 = hit 1. pos(). y(); double z 1 = hit 1. pos(). z(); double d 2 = hit 1. hit(). drift(); double x 2 = hit 2. pos(). x(); double y 2 = hit 2. pos(). y(); double z 2 = hit 2. pos(). z(); double d 2 = hit 2. hit(). drift(); Point p 11( x 1, y 1 -d 1, z 1 ); Point p 12( x 1, y 1+d 1, z 1 ); Point p 21( x 2, y 2 -d 2, z 2 ); Point p 22( x 2, y 2+d 2, z 2 ); list->push_back(new X(p 11, p 21)); list->push_back(new X(p 11, p 22)); list->push_back(new X(p 12, p 21)); list->push_back(new X(p 12, p 22)); return list; }

Refactoring XList* Alg: : create. XList(const Hit& hit 1, const Hit& hit 2) {

Refactoring XList* Alg: : create. XList(const Hit& hit 1, const Hit& hit 2) { List* li = new XList; li->push_back(new X(hit 1. neg. Point(), hit 2. neg. Point())); li->push_back(new X(hit 1. neg. Point(), hit 2. pos. Point())); li->push_back(new X(hit 1. pos. Point(), hit 2. neg. Point())); li->push_back(new X(hit 1. pos. Point(), hit 2. pos. Point())); return li; } Exception safety is also a common problem

Too many abstractions n Common Mistake #3: unused base class n n n Abstract

Too many abstractions n Common Mistake #3: unused base class n n n Abstract base class introduced, but only one subclass is ever produced Cost both in program efficiency and maintenance Common Mistake #4: very deep hierarchies n n Add a new layer of inheritance for one or two new functions; no users are interested in the middle layers of the hierarchy Much more difficult for users to understand the code

Needless Abstraction Only one subclass of each abstract class exists n Users who get

Needless Abstraction Only one subclass of each abstract class exists n Users who get an Abs. Component* from the Abs. Thing interface have to (dynamic) cast before they can use it to get at function h(). n Abs. Thing +f() : Abs. Component Thing Abs. Component +g() : void Component +h() : void Needless complexity makes code harder to understand.

Classes that do too much n Fat interface n n n Scores of unrelated

Classes that do too much n Fat interface n n n Scores of unrelated functions Often, functions form several related groupings Multiple purposes n n Member datum that says if we are to perform task A or task B … even worse if we have to query this state from outside the class

A fat interface example “The [Base. Object] class provides default behavior and protocol for

A fat interface example “The [Base. Object] class provides default behavior and protocol for all objects … It provides protocol for object I/O, error handling, sorting, inspection, printing, drawing, etc. Every object which inherits from [Base. Object] can be stored in the … collection classes. ” n What happens when some subclass can’t sensibly implement the entire interface? We get functions that don’t make sense.

Abstraction: summary It seems to be quite difficult to find just the right level

Abstraction: summary It seems to be quite difficult to find just the right level of abstraction. Cases of too little abstraction seem easier to repair than cases of too much abstraction. This may be partially sociological. Wrong abstraction makes code that is difficult to understand -- and difficult to (re)use.

We need… a few good libraries n Dearth of high-quality scientific C++ libraries. n

We need… a few good libraries n Dearth of high-quality scientific C++ libraries. n n Many projects were started with early versions of C++. It has been difficult for these to catch up with modern C++: n n n Home-grown string, collection classes No use of exceptions -- query is. Good() to check objects Lack of exception safety No use of templates The result is often not robust, less efficient than possible, and more difficult to maintain than need be.

How is the Standard Library Used? n Containers are used frequently n n n

How is the Standard Library Used? n Containers are used frequently n n n Iterators are used simplistically n n n Except where use of some other library’s collection(s) have taken over! New users have some trouble choosing the right container from the Standard Library Commonly used in loops Rarely see a pair of iterators used as a range Algorithms are chronically under-used n Rarer still are user-invented generic algorithms

Summary We have made vast improvement over barelystructured Fortran. n Making good use of

Summary We have made vast improvement over barelystructured Fortran. n Making good use of abstraction is difficult. n We don’t take sufficient advantage of the Standard Library. n In short, we see too little use of modern C++.