8 ms·
For a contrary perspective, see my blog-post "We can’t afford to write safe software" (http://reprog.wordpress.com/2010/06/05/we-cant-afford-to-write-safe-softw
by MikeTaylor 13y ago
For a contrary perspective, see my blog-post "We can’t afford to write safe software" (http://reprog.wordpress.com/2010/06/05/we-cant-afford-to-write-safe-software/ http://reprog.wordpress.com/2010/06/05/we-cant-afford-to-wri...) in which I make the rather obvious point that all the scaffolding you have to erect in statically typed languages is itself a cost, and that ignoring that is misleading. ("You have to fill in a form in triplicate before you can throw an exception", as one of our poets has written.)
Please note (if you can't be bothered to read the actual post before responding), I am _not_ saying that static typing has no value. I'm saying it has both a value _and_ a cost, and too many arguments seem to consider only one of these.
- ggchappell 13y agoI don't think you are really arguing against static type checking in that post, but rather the explicit type declarations that often accompany it. These are not the same thing. See Haskell for a counterexample. EDIT: I see that Haskell is mentioned in the comments. Still, I don't see any understanding there that static vs. dynamic is not the issue.
- Buttons840 13y agoHaskell is inspiring, I did the interactive "Try Haskell" tutorial and though "Oh, it's dynamically typed." Later I found it it's just really good and inferring types. From what I've read, it sounds like good Haskell practice is explicitly declare types on functions, but otherwise never declare types. The compiler can then use the few explicit declarations you have made to infer all the other types.
- IsTom 13y agoMost of the time compiler can do without most top-level declarations too. They're a form of documentation enforced by the compiler.
- asdasf 13y agoThe compiler can already infer all the types anyways, you don't need to declare types. It is considered good practice (and -Wall warns for it) to provide types for top level definitions, as they are usually important enough to warrant this form of machine checked documentation. note: Yes I know the compiler can't actually infer all types all the time, but the exceptions are obvious and require type information in dynamically typed languages too (ie. convert a string to an int: you have to tell it you want an int, you can't just say "convert this string" and have it guess what you want it converted to).
- ent 13y agoBut the cool thing is that in many (most?) cases you can actually infer the type of reading from a string. You are going to do something with that value right? So you can say 1 + (read "1") and the compiler will know that you must want to read "1" as a number and does that!
- deleted 13y ago[deleted]
- platz 13y agoThat kind inference only works because + is defined to work on Nums only (importing only prelude). You don't even need the initial 1. A nice trick but these are rather small details.
- dllthomas 13y agoYeah, I most commonly hit "oh, I need to annotate that" when I'm building some expression piece by piece in ghci, and so effectively what I'm doing with that value is "print it, as appropriate to the type" - which doesn't tell us much about what type it is.
- tel 13y agoIt's also pretty easy and useful to step out of the HM, inferable fragment using any number of popular language extensions. I'm not arguing that it's a problem, but it's disingenuous to suggest that anything resembling all code can be type-inferred.
- deleted 13y ago[deleted]
- jarrett 13y agoI'm admittedly new to the language, but my convention has been as follows: Declare types of all named functions (i.e. not lambdas). This serves two purposes. First, it makes your code more self-documenting. When I look at a function, probably the first thing I want to know is: "What are its parameters?" Type declarations on functions give you a trustworthy and highly readable answer to that question. Second, it makes type errors easier to understand. If you don't explicitly declare types, the compiler will perform type inference. When your code has a type error, the compiler can infer a nonsensical type for a function, yielding a hard-to-understand error message. If your function has a type declaration, the error message is more likely to point you to where your actual mistake is. Rarely declare types on anything that's not a top-level function definition. For example, if I want to call (foo (bar baz)), I don't need to add separate type declarations to baz, (bar baz), and (foo (bar baz)), even though each quite possibly has a different type. On the other hand, if you want to remind yourself of the type of some inner expression, or you think it'll make the type errors more readable, you can add the declaration. It won't hurt you.
- ixmatus 13y agoI've gotten in the habit of explicitly declaring the types of everything I can. As you already mentioned it's a form of (excellent) documentation that I find myself missing in many languages - when writing Python I get frustrated because I have to go dig or debug the type of a value when in Haskell I can simply look for the type declaration (happily Python I think is considering type annotations). If you use Emacs, haskell-mode and ghc-mod + ag or grep have some awesome features for finding type definitions in source, querying hoogle, and lambdabot style de-sugaring and queries. While type inference is cool, it's only really useful when I'm playing inside GHCi. Also - it can often improve the quality of a program a lot by thinking about your types first, declaring them, then filling out the function definitions (that is often how I do it).
- dllthomas 13y agoOn the flip side, I tend to declare types mostly at the top level. It's nice to be able to change just a few types and have everything else work itself out. There are times it doesn't work and I don't hesitate to add more type annotations then, and when I get weird type errors my first response is go through and decorate it piece by piece.
- humanrebar 13y agoThe counter argument is the main argument for clean code and documentation -- code is consumed much more than it is produced. You can hack code together and forgo documenting it, but it's a form of technical debt. When creating a minimum viable product for a startup, taking on some forms of technical debt probably makes sense, but by the time you're talking about huge code bases, you're probably past the startup phase (I hope) and you're already up to your neck in technical debt.
- hyp0 13y agoRelated: static typing is itself documentation (low-cost, machine-checked documentation).
- brudgers 13y agoWhen the static type checking system has an inference engine there is a strong incentive not to document types on the part of programmers. Conversely, a requirement that for explicit type declarations makes the use of generics more cumbersome.
- Peaker 13y agoFortunately, your IDE can use inference to add a type signature with a keystroke.
- steveklabnik 13y agoAnd now you've added the cost of mandating an IDE, and someone has to write that feature for the IDE in the first place.
- Peaker 13y agoThe feature exists in emacs and vim, and is nice but not mandatory. It should be easy to integrate into any editor.
- stefantalpalaru 13y agoThe cost is significantly reduced by type inference (see Go and Vala).
- jerf 13y agoGo does not do type inference, it just does type deduction, a much weaker thing that at least relieves some basic tedium, but still leaves the source code fairly full of type declarations.
- mightybyte 13y agoYou're right that it has a cost (although type inference can significantly reduce that cost). But... From TFA: "They write test cases for every identifier ever used in the program. In a world where misspellings are silently ignored, this is necessary. This is a cost." So in a dynamic language the cost is still there. In fact, it's probably higher than in a static language because you have to build at least some of the infrastructure yourself. Well, I imagine some people would argue that in a dynamic language the cost is optional. And again, I point to type inference where sophisticated static languages achieve the same thing.
- andybak 13y ago> In a world where misspellings are silently ignored, this is necessary. How does "dynamic typing"="misspellings are silently ignored"? Maybe in some languages but that's not a corollary of dynamic typing. Disclaimer: Haven't read TFA so shoot me down if the context makes this clear
- mightybyte 13y agoTFA was talking specifically about Javascript there. But I think the overall point about the cost of testing applies to dynamic typing across the board.
- nailer 13y agoHow would one consider JS to silently ignore misspellings?
- marcosdumay 13y agoExcept that'll write those same tests on staticaly typed languages (except Haskell), because their typing system isn't powerfull enough to detect most bugs. And yes, you'll need to do a little bit of infrastructure on the test cases, but you'll gain the extra power that comes with dynamic types, that makes everything (even writting tests) much easier. And, of course, your codebase can be much less "huge" with that extra power. Anyway, all that thing is a big red herring. Nobody decides to create a huge codebase.
- gclaramunt 13y agoAny modern type system barely require scaffolding, lowering the cost and providing a way more value (see Haskell or ML, or even compare Java with Scala)
- asdasf 13y ago>in which I make the rather obvious point that all the scaffolding you have to erect in statically typed languages You mean "in which I pose the rather obvious strawman". What scaffolding? What is this mysterious "extra stuff" people give vague names like "scaffolding" to that I've never encountered despite programming in a statically typed language all the time?
- rpedela 13y agoI think he means having to implement toString() ten times to handle all the various types that need to be converted to strings. toString() is a trivial example because most languages have that built-in to some degree. But there have been several times where I would have to write the same C/C++ function again and again to support a new type.
- mightybyte 13y agoTry "deriving (Show)". And stop using the C/C++/Java straw man as the basis for arguing against static type systems.
- rpedela 13y agoI don't know what your first sentence means. As for the second, I was explaining what I thought the author meant by "scaffolding" not making an argument for or against anything. Now here is an argument for you: shouldn't two of most widely used languages be included in an argument about static vs dynamic typing?
- tel 13y agoThe first sentence is a hint toward Haskell's wonderful derivation system which tells the compiler to write the "obvious" code for all kinds of common scaffolds. It's almost always all you need for equality, showing, ordering, hashing. There's also the GeneralizedNewtypeDeriving which allows you to inherit instantiation of types into all kinds of structurally equivalent types. And while it's valuable to talk about popular languages in terms of the kind of static typing people are likely to encounter... they also have really outdated static type systems. While you can argue that it's likely that you'll bump into Java/C/C++ when working with static types, it's pretty invalid to argue generally about static type systems using them as examples. Things have just come a really long way.
- ww520 13y agoI view the extra scaffolding as writing unit tests. The type definitions are just a way to specify unit tests in a formal way. The compiler does the rest of unit testing using the type definition, at compile time. With the correct tools a lot of the scaffolding are automated and kept to a minimum so not much is loss.
- banachtarski 13y agoThe op is arguing that static typing is correlated with project scalability (due to language support for a number of other features that help encapsulation, modularity, etc). Not that static typing by itself is what makes it easier to scale project complexity. For C++, note the now accepted use of `auto` and `decltype` which together remedy a number of issues from C++03 and prior.
- revelation 13y agoA contrary perspective? Even the original post is a dubious argument to the effect of "it's not that the language is dynamic, it's that dynamic languages lack X or Y!". For me, I've looked inside one of the biggest Python codebases in existence (the EVE Online client). It's a freaking mess. A simulation of static typing but mostly they just passing freaking tuples around. Everything is a tuple in a tuple in a dictionary in a tuple in a homegrown table.
- midas007 13y agoThat might be one of the reasons that type information is optional in Erlang, and what makes it fairly expressive at the cost of some static analysis.
- awj 13y agoYou're confusing static typing with explicit typing. This is static typing's version of the "dynamic typing doesn't have to be weak typing" argument. There are a variety of languages that don't impose explicit typing on you to enable static typing. OCaml and Haskell are popular options. Scala makes the compromise choice of having explicit function signatures with inferred typing elsewhere. If the only thing you're using the type system for is to make sure arguments line up, you're barely using it at all. When your types can encode (and thus, ensure) aspects of your program logic, that is when static typing becomes useful.