3 ms·
I agree with this for really large codebases, but I think you can get a surprising amount done before your program becomes "non-trivial" using a good dynamic la
by thurn 6y ago
I agree with this for really large codebases, but I think you can get a surprising amount done before your program becomes "non-trivial" using a good dynamic language. For example, the website you are writing this comment on has been perfectly maintainable in lisp without any static typing for the past 15 years.
- darksaints 6y agoIt also hasn't changed much in 15 years. Now that could be (and probably is) a deliberate decision. But there are more than enough cases of projects that haven't changed because they can't...they've painted themselves into a corner, and every time they try to change something, something else breaks. I've felt this way with Python and Ruby and Node projects (it is a major complaint in the RoR community), but have never felt that way with Scala, Java, C#, F#, Rust, or OCaml. Most of the time, when I need to make a change, I just change it, iteratively eliminate any type errors, and once the type errors are gone, the tests magically pass too.
- throwaway894345 6y agoI get the feeling that lisp doesn’t produce as many runtime type errors as Python or JS and I’m not really sure why that would be. Maybe there’s something to a functional style of programming that improves quality even apart from type checking?
- remexre 6y agoArc "feels" a lot more Scheme-like than Common Lisp-like, but pg is a CL guy afaik; my observations on the two: Scheme avoids type errors by writing programs which could be given static types with a sufficiently powerful type-checker. If a Scheme programmer needs to define two aggregates, both of which have a property "name," they're likely to define two different functions, foo-name and bar-name, to get at them. This, though it's noisy, makes type errors more obvious. CLOS helps avoid type errors too, since it encourages thinking not about how code interacts with a single type, but instead how it interacts with a whole _protocol_ of methods. I think multimethods in general are a powerful design tool that help avoid type errors in a dynamic setting, but I haven't had a chance to try them out in a language other than CL. Many CL implementations also have static type-checking. For example, when I try to define a function with a type error in SBCL: * (defun f (x) (+ 1 x (car x))) ; in: DEFUN F ; (CAR X) ; ; caught WARNING: ; Derived type of X is ; (VALUES NUMBER &OPTIONAL), ; conflicting with its asserted type ; LIST. ; See also: ; The SBCL Manual, Node "Handling of Types" ; ; compilation unit finished ; caught 1 WARNING condition CL's philosophy here differs a bit from most typed languages: SBCL will emit a warning (not an error!) for code it can statically show is impossible to run without getting a type error, while e.g. GHC gives an error for any code it can't statically show doesn't get a type error. However, in my experience, many type errors are obvious enough that SBCL warns about them (e.g. passing a vector where a list was expected, a string where a symbol was expected, nil where a non-nil value was expected, etc.), so this helps quite a bit, especially when combined with the interactive editing one gets through SLIME/slimv. One can also attach type annotations to functions [0], and SBCL (and probably other implementations) will add a runtime CHECK-TYPE [1] unless you tell it to optimize for speed enough. [0]: http://www.lispworks.com/documentation/HyperSpec/Body/d_ftype.htm http://www.lispworks.com/documentation/HyperSpec/Body/d_ftyp... [1]: http://www.lispworks.com/documentation/HyperSpec/Body/m_check_.htm http://www.lispworks.com/documentation/HyperSpec/Body/m_chec...
- eyelidlessness 6y agoThis is partly right. FP approaches do tend to reduce the volume of mistakes, and reduce the kinds of mistakes you can make. But that’s not because type errors are less likely. For dynamic functional languages they’re only less likely because the implicit contracts tend to be more general and the data structures tend to support a high degree of polymorphism. The reason FP approaches tend to reduce mistakes is mostly that managing state is hard, and pure functions are easier to reason about.