on the static versus dynamic typing debate

The sta­tic and dynamic typ­ing debate con­cerns sev­eral inde­pen­dent decisions:

  • When to pro­vide feed­back about type errors (at com­pile time or runtime)
  • When to pro­vide the pro­gram­mer with an exe­cutable (in the pres­ence of “errors” or “not”)
  • When to do type check­ing (at com­pile time, run­time, ship time, check-in time…)

The extreme case sta­tic typ­ing claims that both of these should be at compile-time. The extreme case of dynamic typ­ing says do all of these at run­time and always pro­vide the exe­cutable.
There are many exam­ples between these two extremes. For exam­ple, Java in Eclipse always gives an exe­cutable, pro­vides feed­back at com­pile time and run­time, by com­pil­ing meth­ods that do not com­pile as meth­ods that sim­ply throw a com­pile error.
I pro­pose that we do type check­ing and feed­back at com­pile time, but always pro­vide an exe­cutable for test­ing, giv­ing the devel­oper the option to ignore the feed­back selec­tively. For exam­ple, sup­pose you make a change to data struc­ture D, which breaks A, B, and C, accord­ing to the compiler’s type checker. By pro­vid­ing the exe­cutable even in the pres­ence of type errors, the pro­gram­mer don’t have to waste time fix­ing func­tions B and C if A needs to be tested in order to accept or reject the change to D. This way, the pro­gram­mer can deter­mine the short­est path to rec­og­niz­ing a prob­lem with the change to D, with­out hav­ing to fix all errors.
If the com­piler does not pro­vide an exe­cutable when pos­si­ble, the pro­gram­mer has to fix all asso­ci­ated with A, B, and C, before being con­fi­dent that the change to D is ade­quate. In other words, the com­piler is in charge of how pro­gram­mers and teams decom­pose their tasks, rather than the pro­gram­mers and teams, and yet the com­piler has no knowl­edge of their con­straints.
I’m not propos­ing that we defer type check­ing or error feed­back. Check­ing and feed­back are great, as long as the devel­op­ers are in charge of whether they can ignore them. Thus, to some extent, I’m propos­ing that whether a type check­ing prob­lem is a warn­ing or an error (in the con­ven­tional sense of whether an exe­cutable is gen­er­ated), should not be up to the com­piler and its flags, but up to the devel­oper.
I’m not propos­ing that we ship code with type errors. But a team should be able to defer fix­ing these prob­lems until the appro­pri­ate time. They should even­tu­ally be fixed in case they’re a prob­lem, and prefer­ably as soon as it is known whether the changes that caused the warn­ings are accept­able.
There is the seem­ingly orthog­o­nal issue of false pos­i­tives in type check­ing. In cer­tain cases, type check­ers will gen­er­ate feed­back that spec­u­lates about a prob­lem (in some cases it can­not be cer­tain about cor­rect­ness). This is another issue in the sta­tic and dynamic typ­ing debate. The dynamic pro­po­nents argue that false pos­i­tives waste devel­op­ers’ time. But I would argue that they waste no one’s time as long as such false pos­i­tives can be ignored, and the exe­cutable can still be tested.
One dan­ger with my pro­posal is that if you give devel­op­ers the free­dom to ignore type check­ing prob­lems, they may never attend to them. But who really deserves to make this judge­ment? Com­piler design­ers or the devel­oper them­selves? Shouldn’t a devel­oper be allowed to trade cor­rect­ness and guar­an­tees for ship time if it allows them to show a pro­to­type to a client faster or test the fea­si­bil­ity of a design faster? Again, com­pil­ers and com­piler design­ers have no knowl­edge about a developer’s con­cerns or pri­or­i­ties and yet implicit in the compiler’s design is a judge­ment about the devel­op­ers’ pri­or­i­ties. Com­pil­ers enforce this naive value sys­tem by plac­ing cor­rect­ness require­ments in the inner loop of soft­ware development.