This page is an experiment, I hope. We're going to try switching roles and see if we learn something. I've learned things already.
Arguments for StaticTyping
made by a DynamicTyping
Please don't add to this list unless you are actually convinced static typing brings little or nothing to the value equation. Please don't add to this list unless you can make a convincing argument for it.
But do correct things that are clear errors, regardless of what you're convinced of.
- Static typing gives more information to the tool writer. Writing a RefactoringBrowser ought to be easier in a statically typed language. It would be easier to ensure that the refactorings were safe [yes], and more of them would be possible [why? I don't see this - exactly the same set of refactorings should be possible.].
- Manifest static typing communicates more information to the programmer (he knows for sure that this variable is a Foobar) and makes it easier to reason about the program. (This is a fallacy; static typing rejects a whole space of programs, leaving a remainder that is easy for a very dumb piece of software to reason about! [No, it's not a fallacy. It is an oversimplification, because it incorrectly implies that ManifestTyping is the only way to extract such information. Anyway, it's never easy to reason about non-trivial programs, regardless of the type system.] That rejected space contains useful software. [That depends on how expressive the static type system is. If it has an 'any' type, then there is no rejected space.] Also, it's very easy to retrofit an ad-hoc dynamic typing system within a statically typed program; this is manifested all the time. See GreenspunsTenthRuleOfProgramming. Thanks to Turing equivalence, programmers can still reach the "forbidden" spaces, using indirect and complicated workarounds. [ 'any' types are not complicated (especially if the default type annotation is 'any', as in SoftTyping - although that's just a syntax issue).] When programmers do that, they do a half-baked job, because their real goal is to get some software out the door and not to implement a mature dynamic language. So their dynamic hacks are poorly optimized, poorly error-checked, etc).
- Static typing allows the compiler to generate faster code. (This is the real reason for the existence of static typing [no, it is only one reason], but must every line of code in the whole system be optimized? Optimizations sometimes make the code larger - loop unrolling, cache block alignment, choosing several simple fast instructions over a complex one, etc. If you optimize a function that is called only once, you are just adding to the bloat. [If your compiler isn't optimizing according to the time/space trade-off settings you want, change the settings or get a better compiler.] Whereas programs often spend a large proportion of time in a small fraction of the code, bloat is not thus localized. All we can say about bloat is that 100% of the program's size is represented in 100% of the code. Dynamic typing does add overhead to the data; one advantage of static typing, the only one really, is space-efficient in-memory representation of types, and the ability to conform to externally imposed layouts, like memory-mapped I/O registers, binary records from files and such). [The space cost of type tags is small; this cost is not really important.]
- Not everybody writes UnitTests. If I've got to work with code written by a team that doesn't, I'd be glad to at least have some kind of a safety net. (What if your code is written by a team that drums up an ad-hoc dynamic system within the static language? If you used a mature dynamic language in the first place, you'd have a high quality safety net which is built into that language. Will your ad-hoc dynamic typing hacks adequate safety nets?)
- Static typing lets the compiler do completeness tests. For example, gcc, with the right flags, will warn you if you have a switch statement over an enum type that misses one of the enum-erands. (What if you add a case, and don't recompile that code? Makefile dependency generators are not part of the C language yet. [[Who said anything about C? I thought this was supposed to be a language-independent discussion; anyway, C hardly has a shining example of a well-designed static type system.]] (Just for the record: gcc includes a Makefile dependency generator: -MD) In a quality dynamic language, if you don't recompile something, there is still a safety net there. In Lisp we use the ECASE construct, which will signal an error condition at run-time if none of the cases matches the input value.)
- TypefulProgramming: for some people, it might be easier to have every object have its own type - some values will be in inches, some in centimeters, and you will have a conversion routine. I like it better when ItJustWorks, but maybe sometimes this approach helps. I heard that there are many MlLanguage programs written in this style.
- Interfaces can be a nice way to document, well, interfaces that classes share that don't result from inheritance. And the interface can't be wrong or the compiler will complain.
, AnonymousSarcasmDonor? (Sorry, whoever you are. I rewrote the rules to clarify them.)
Arguments for DynamicTyping
made by a StaticTyping
Please don't add to this list unless you are actually convinced dynamic typing brings little or nothing to the value equation. Please don't add to this list unless you can make a convincing argument for it.
Again, don't let this stop you from correcting clear errors.
- You don't have to think too far ahead about what you're doing or do too much planning -- you can just code away, and keep what makes the code better.
- Interfaces can be conceptually evasive and difficult to codify. Identifying the interfaces in a collection of classes and giving them distinct types isn't necessarily worth the effort.
- Uninteresting type declarations make code more verbose and add "noise" that distracts the reader from the essence of an algorithm. This is particularly true if all the variables you're dealing with have the same type. This isn't an argument against StaticTyping, is it? This sounds more like an argument against ManifestTyping.
- With dynamic types, you can easily build a "replacement class". Say you want to stub something out, or you have code that expects to be passed a file to read from but instead you want to feed it content from a string. You can build a new class which provides the necessary functionality (e.g.: whatever methods of File are actually used by the code you're invoking), and just pass it, since the type isn't checked. Subclassing is often not really a viable option. [ This is an argument for static typed interfaces. Using interfaces you can always stub something out - plus it is also ensured all the necessary methods are there. ]
- Dynamic typing lets you concentrate on the conceptual essence of your program, instead of keeping you busy with what often just amounts to "administrativia" to keep the compiler happy, such as casting.
- With static typing, it's easy to fall into the trap and make a contract too narrow, such as requiring an Integer as a parameter where any kind of Number would work.
- With static typing, the types of every parameter of a function is fixed. If I want to do the same sort of thing with a completely different type, I have to copy-and-paste a fresh copy of the function and manually change that type. Any errors I discover in either function require me to manually fix both functions. With dynamic typing, I can just call the single function with all kinds of different parameters, and I can fix bugs in that function OnceAndOnlyOnce. For example, a function to sort an array of integers, another to sort a linked-list of string pointers, and a third used as part of a routine to show all the printers in a dabase sorted by price [This example is contradicted by Haskell. It has static type-checking, and can easily do array-sorting on anything declared with a less-than method. C++ template functions also can do this with compile-time checks.].
- Static typing makes PredicateTypes hard (if not impossible) to implement reasonably. For example, we might define the predicate class Circle as "any Ellipse e where e.minor == e.major". A dynamic type system will simply check if a given Ellipse is a Circle at run time. A static type system must solve the halting problem to determine whether an Ellipse is a Circle. [Pattern matching may be able to work around this.)
This experiment already appears to be failing, and I only created the page a few hours ago. Why is this so hard? -- AdamSpitz
It's failing because anyone who can see the merits of both "sides" (i.e. who doesn't agree either that static or dynamic typing "brings little or nothing to the value equation"), is excluded from participating. Most programming languages in practice use a combination of compile-time and run-time checking (and in some cases type inference), so the assumption that languages, much less programmers, must be on one side or the other is a gross oversimplification. -- DavidSarahHopwood
How is it failing? My own (possibly conceited) opinion is that the existence of the page is a big win in itself. The problem I
have is figuring out which side of the question I should argue (or maybe stay on the sidelines). -- LaurentBossavit
It looks to me like people aren't trying to figure out what's good about the other side; they're trying to figure out how to phrase insults in positive form. But maybe it'll get better. Thank you for deleting the sarcastic ones. -- AdamSpitz
I can tell you why I haven't yet come up with something to write in the second half (pro-dynamic.) Every example I think of is perfectly easy to do in C++ - just use casting. What's the difference? Static type safety is optional (and all too easy to avoid using) and so I can't think of an example that means that not
having it available is an advantage. -- DanielEarwicker
Casting excessively means you don't want static typing. So, if your solutions involve casting away the type system, the static type system isn't doing anything for you--just getting in your way.
Think harder. No, I don't really mean that. I don't know what it means that (apparently, and at the moment) there is more to be said for StaticTyping by DynamicTyping advocates than the reverse. Maybe it's because StaticTyping does indeed have no cost and all benefits, and those thoughtful folks in the first half are actually loopy. But maybe the effort of coming up with an alternate explanation could yield some insight. And... thank you for being willing to try.
I'm making the effort, believe me! I'm just going round in circles. Maybe I need more concrete examples. I've long suspected that all competent people will adjust their working methods to make the best use of the tools they have, because that is always cheaper than making the big leap to a different tool. So my way of working fits StaticTyping
. I need to see an example of a little design situation in which static typing would have just "got in the way,"
so I can learn (at least temporarily) to think in the same way as someone who thinks in terms of dynamic typing. (In fact I'm almost convinced that those who develop large, complex programs without type safety may even be using the concept of a type in an entirely different way that I do!) - I propose you an example of what you can do easily with dynamic types and I think in a more complex way with static. Imagine you have an application in production that takes incomings data from users, you can avoid to checks the entry and just let crash the request in case of unsupported request- no line of code is needed for that. Some time later you want to support new request (for example support lists of requests), just add the code to manage the new requests, no change is needed in the existing code (so very few risk of regression), and load the code into your running application (Some of you may have guessed that I am using Erlang), that's done. Ok these are only few words with no real proof of the real simplicity or complexity, but maybe you will be interested in looking forward, I did this effort and it took me several days before I can really appreciate the advantage of this concept. Also in is not only the dynamic typing in action here, but the whole language paradigm. There's a book I recommend : 7 languages in 7 weeks by Bruce Tates
Well, I think it's right to adjust to your working environment. So maybe the SimplestThing is to change your working environment for a short while. Download SqueakSmalltalk or DolphinSmalltalk, play with it on your spare time, then pick a very small task which gives you a chance to implement something useful with it. Maybe it's not worth the effort, and maybe it is. I can speak only for myself, but believe I would be a slightly worse programmer today if I hadn't given it a try.
Here's a hint: C++ templates (and generics, in general) aren't static types. Furthermore, they take dynamic types as parameters (i.e. the parameter types need only be Liskov substitutable). Discuss.
C++ templates effectively use SignatureTyping. (Hmm, no page yet for SignatureTyping. There should be.)
-- That speaks volumes to me. The substantial complaints I've heard against static typing all seem to be answered by templates. BUT - they are
static type safety. The type-correctness is validated in a static analysis. The explanation for all this? Well, one suggestion (and that's all it is) is simply that most of the people who are disaffected with static typing are not aware of how generics work. The typical complaint against static typing appears to be formed without any knowledge of templates/generics.
Well, first, they aren't static type safety. Often templates instantiate on things you wish they wouldn't (because the type parameters are dynamic), and that takes forever to hack out a fix for. This is only a problem because the templates then force the dynamic type to operate in a statically typed environment, forcing conversions where you don't want them.
Speaking of which, templates have vast problems of their own. Consider compiler time, code size, recursion limitations, code complexity (unless you like PrologLanguage), and debugging complexity. I'll twist your last statement around, "the typical arguments for static typing appear to be formed without any knowledge of dynamic types."
Uhh...maybe I'm missing something because I don't do C++, but parameterized types in SML are fully type-safe. Maybe it isn't that parameterized types aren't type-safe, it's just that C++'s sloppy/flexible implementation is.
Before I programmed in Smalltalk, I programmed in Pascal. While programming in Pascal, I never once lamented the fact that I had to declare variable types. But after programming in Smalltalk, when I switched from Smalltalk to Java for six months, I would curse every day about having to declare types.
And during all the years I programmed in Smalltalk, I never once lamented the fact that I had to use a keyboard to enter code instead of speaking it into a microphone. I never once lamented the fact that I did not have automatic code refactoring. I never once lamented the fact that I didn't have four voice-activated computer screens in front of me so I didn't have to keep jumping between windows on the same little screen.
Can you, as a single-screen-viewing manual-refactoring code typer, name the benefits of being able to speak your code instead of using a keyboard? The benefits of automatic refactoring? The benefits of using four computer screens at the same time?
Multiple computer screens makes life a damn sight easier. I'd use one for viewing the code, another for the continuously-running build/test cycle (it would flash at me when it's broken), another for viewing the documentation, and the fourth (seeing has how you've been generous enough to give me) for all the non-coding things; email, browsing wiki, video-conferencing, etc. Right now, I cope with them all on the same monitor, but I'm always hiding things and bringing them back up. The extra screen real-estate would be nice. While I'm at it, I'll make all but the last one A4-sized and shaped; the length is useful, but the width becomes superfluous with all the extra monitors. As a single-monitor user, I regularly lament not having a second monitor.
You can get the same effect using VirtualDesktops
. It's one feature from Linux that I miss most on Windows.
OffTopic comment: you can have virtual desktops on windows. Just use ObjectDesktop? or Litestep.
OffTopic as well... virtual desktops are a poor substitute for an actual second monitor... try it, you'll understand
I am not sure what the purpose of this debate is. If you program in a language that supports the static typing model, use static typing. Likewise, if your program in a language that supports the dynamic typing model, use dynamic typing. It doesn't matter whether you prefer to drive a standard or automatic transmission. If you have a car with a standard transmission, use the clutch and don't complain about it.
And how do you know which language to pick, all other things being equal? When you design a language, how do you know which to choose? If you don't understand the limitations of the tool you are currently using, how will you know when it's no longer the right tool for the job?
The question debates like this are trying to answer is this:
Are we comparing two things that are
- comparable, like an automatic versus a standard?
- or, drastically different, like a pair of concrete boots versus a jet pack?
Or perhaps we are trying to argue about a continuum; the degree of static typing in a language versus the degree of dynamic typing. For example, C provides a limited scope dynamic typing through unions and also through conversion of the basic numeric types. In C++ (and most object oriented languages), limited scope dynamic typing can be achieved through base classes. Every language had to pick where it would lie on the continuum of static to dynamic typing. This was unavoidable. To argue about that choice after the fact is kind of pointless. Learning the benefits of both and how to apply them appropriately in your current programming environment is valuable.
Some of my takes on "dynamic" typing here:
There are complex tradeoffs to both approaches. I think the BenefitsAreSubjective
on this one, and it is thus prime for HolyWar
rants. It is one of those topics that usenet groups create 1000+ messages over, and nobody ever agrees in the end.
I also think it may be possible to come somewhat close to getting the best of both worlds by having a "lint" utility that can flag "suspicious" usage in dynamic languages. One can then inspect the indicated spots, and add them to the "lint ignore" list, or fix them.
You mean SoftTyping
I think a better question might be WhyCorporationsLikeStaticTyping
Why not TypeInference
? Then you don't have to type functions, the compiler does it for you. The benefit is that you can write generic functions.
In Java, you know all those abstract classes you create? Those are so you can write generic functions that work for all subclasses. TypeInference
does this for you so you don't have to create abstract classes. You only type the methods specific to the new class you created, and let the typing system figure out what classes all those genericts apply to. All those OO newbies who spend their days thinking up massive unmanageable class hierarchies can get some work done. See NeedleLanguage
Originally, that up there said 'Smalltalk' instead of 'Java'. Smalltalk doesn't have 'virtual classes'. The intent of the author seems to be to gripe about the funny dances you have to do with abstract base classes in languages like Java and C++. These things are not necessary in languages with DynamicTyping or TypeInference. Someone clever is invited (if the original author above doesn't mind) to make sense of this.
- Sorry meant abstract classes. I fixed it. - But you left 'Smalltalk', so I changed it to Java again.
This page certainly seems like an interesting idea. How about trying the SixThinkingHats
trick with this topic? I guess that would be DynamicTypingSixThinkingHatsDebate?
. -- DavidPlumpton
See Also: ThereAreNoTypes