Live data from Hacker News

Diminishing returns of static typing

blog.merovius.de

301–310 of 632 posts

Re: Diminishing returns of static typing

#301

What amuses me in all "static typing versus..." discussions, is that it usually it is the comparison between two camps: Camp A: Languages with mediocre static typing facilities, for example: -- C (weakly typed) -- C++ (weakly typed in parts, plus over-complicated type features) -- TypeScript (the runtime is weakly typed, because it's Javascript all the way down) Camp B: Languages with mediocre dynamic typing faciliti…

It's Camp D that I'm least familiar with here; outside of academic projects in lisp/scheme I've never used them for anything serious. What exactly does it mean to have "good dynamic typing facilities"?

>What exactly does it mean to have "good dynamic typing facilities"?

Picking Common Lisp as an example:

(NOTE: Some of the features are also present in good statically typed languages as well, so what I advocate is to use good, well-featured languages, not really static vs dynamic.)

(NOTE 2: I'm sorry for being such a fanboy, but that thing is addictive like a hard drug...)

0. Code is a first class citizen, and it can be handled just as well as any other type of data. See "macros" below.

1. The system is truly dynamic: Functions can be redefined while the code is running. Objects can change class to a newer version (if you want to), while the code is running.

2. The runtime is very strong with regards to types. It will not allow any type mismatch at all.

3. The error handling system is exemplary: Not only designed to "catch" errors, but also to apply a potential correction and try running the function again. This is known as "condition and restarts", and sadly is not present in many programming languages.

4. The object oriented system (CLOS) allows multiple dispatch. This sometimes allows producing very short, easy to understand code, without having to resort to workarounds. The circle-ellipse problem is solved really easily here. (Note: You can argue that CLOS is in truth a statically typed system, and this is partly true -- the method's class(es) need to be specified statically, but the rest of arguments can be dynamic.)

5. The macro system reduces boilerplate code to exactly zero. And also allows you to reduce the length of your code, or have very explicit (clear to read) code at the high-level. This brings down the level of complexity of your code, and thus makes it easier to manage. It also reduces the need for conventional refactoring, since macros can do much more powerful, automatic, transformations to the existing code.

6. The type system is extensive -- i am not forced to convert 10/3 to 3.333333, because 10/3 can stay as 10/3 (fractional data type). A function that in some cases should return a complex number, will then return the complex number, if that should be the answer, rather than causing an error or (worse) truncating the result to a real. Arbitrarly length numbers are supported, so numbers usually do not overflow or get truncated. (Factorial of 100) / (factorial of 99) gives me the correct result (100), instead of overflowing or losing precision (and thus giving a wrong result).

So you feel safe, because the system will assign your data the data type that suits it the best, and afterwards will not try to attempt any further conversion.

7. The type system is very flexible. For example, i can (optionally) specify that a function's input type shall be an integer between 1 and 10, and the runtime will enforce this restriction.

8. There is an extensive, solid namespace system, so functions and classes are located precisely and names don't conflict with other packages. Symbols can be exported explicitely. This makes managing big codebases much easier, because the frontier between local (private) code versus "code that gets used outside", can be made explicit and enforced.

9. Namespaces for functions and variables (and keywords, and classes) are separate, so they don't clash. Naming things is thus easier; this makes programming a bit more comfortable and code easier to read.

10. Documentation is built into the system - function and class documentation is part of the language standard.

11. Development is interactive. The runtime and compiler is a "living" thing in constant interaction with the user. This allows, for example, for the compiler to immediately tell you where the definition of function "x" is, or which code is using such function. Errors are very explicit and descriptive. Functions are compiled immediately after definition, and it can also be dissasembled (to machine language) with just a commmand.

12. Closures are available. And functions are first-class citizens.

13. Recursion can be used without too many worries -- most implementations allow tail call optimizations.

14. The language can be extended easily; the reader can also be extended if necessary, so new syntaxes can be introduced if you like. Then, they need to be explicitely enabled, of course.

15. There is a clear distinction between "read time", "compile time" and "run time", and you can write code that executes on any of those three times, as you need.

16. Function signatures can be expressed in many ways, including named parameters (which Python also has and IMO is a great way to avoid bugs regarding to wrong parameters / wrong passing order.)

Re: Diminishing returns of static typing

#302
post #200

Earlier quoted context omitted.

Perhaps it's because the languages you mentioned barely register in statistics(aside from Clojure maybe). Maybe it's simply hard to have both a good type system and a friendly learning curve?

>friendly learning curve To be honest, i love Common Lisp, it might be the most powerful programming language out there, but it's not easy to learn at all. In part because, being a truly multi-paradigm language, you should better make sure you are well versed in most programming paradigms first, otherwise you won't leverage the full power of Lisp. Not to mention the paradigm of meta-programming and DSLs, something th…

>Not to mention the paradigm of meta-programming and DSLs, something that is usually new to programmers foreign to Lisp.

Is it really? What about templates(as in C++ templates), macros, CSS and HTML? These are two examples of metaprogramming and two DSLs respectively.

> However, languages like Clojure and Smalltalk can be rather easy to learn, and they are fairly powerful.

It's not like I don't believe you, but if this is true, then where's the popularity? Why isn't it there? I'm asking because I genuinely don't know.

EDIT: punctuation.

Re: Diminishing returns of static typing

#303
post #288

Earlier quoted context omitted.

If you're just rewriting these Promises because the syntax is too verbose, you might be interested in checking out async/await as another alternative; I just rewrote some Promises to that recently, and it's really, really nice. Of course, if you prefer RX Observables, go right ahead :)

Thanks for the note, I am looking into it right now. One area that may grind my head with async await however is that there is a lot of Promise.all work in this codebase. Would you still use async/await constructs when you need to do a lot of fork/join/merge stuff? (sorry for the derail HN)

If you're using Promise.all to run code in parallel, then async await can't really replace that, as far as I know. But you can still use `await Promise.all(...)`, which will free you from having callbacks everywhere; running parallel code will no longer have to look so different from running it sequentially, which is quite nice.

Re: Diminishing returns of static typing

#304

Earlier quoted context omitted.

>Having to pollute my code with all that crap What crap? Types? >deal with a lot of dumb restrictions Like what?

What crap? Types? Types, especially those that could easily be inferred and that provide no value to the programmer. Writing types down can be useful - Python programmers do it too. Having to tell the compiler every little thing is crap. Like what? Type erasure. Having to treat primitives and arrays differently from other types. No first class functions or classes. I won't go on, the arguments are easy to find.

I won't deny that Java had some quirky design decision that the language is paying for (though some of those have been mitigated). But I can't find your criticisms very persuasive in a world where languages like JavaScript and PHP are popular. Even C and C++ have their own idiosyncrasies to contend with.

I am surprised though that you were completely ignorant of the benefits of static typing outside of Java. I would think that simply out of curiosity you would do a language survey just to get an idea of what else is out there.

Re: Diminishing returns of static typing

#305
post #200

Earlier quoted context omitted.

Perhaps it's because the languages you mentioned barely register in statistics(aside from Clojure maybe). Maybe it's simply hard to have both a good type system and a friendly learning curve?

The other possibility is that the industry suffers from anti-intellectualism, so we keep reinventing the same 2 languages.

Do you believe that this is plausible?

Re: Diminishing returns of static typing

#306
post #67

Earlier quoted context omitted.

I can do all of those things in Smalltalk, which is dynamically typed; these things are not byproducts of static typing, they're simply byproducts of mature tools. So no, these are not arguments in favor of static types.

>> finding all references to a function Yes, you can find all references to a method in Smalltalk -- but those references are not separated-out from all the references to other methods that happen to have the same method name but are defined on a different class. With type information for the receiver and method arguments, we can find just the references we're looking for.

Which is why Smalltalk's refactoring browser has a manual intervention step to allow you to see what it proposes to do, and remove any steps you don't agree with, as well as the ability to scope your refactorings to a package or class to limit the scope to more relevant data. Either way, it's sufficient to get 99% of the benefits of automated refactorings without the 100% guarantee static typing provides; good enough for me.

Automated refactoring was invented in Smalltalk, claiming it's a benefit only static typing provides is to not know history.

Re: Diminishing returns of static typing

#307

Earlier quoted context omitted.

>Static and dynamic typing each have their own benefits, I struggle to think of any benefits of dynamic typing on a reasonably sized code-base (e.g. 50k+ LOC).

>I struggle to think of any benefits of dynamic typing on a reasonably sized code-base Being able to define and initialize types at runtime offers more flexibility and it's quicker to develop in. I'm frankly surprised nobody brings it up more often but the prototypical example of "static typing done right" - Haskell - is talked about nearly constantly but when I look for actual software I might use that's written usi…

>Being able to define and initialize types at runtime offers more flexibility and it's quicker to develop in.

Quicker if you're writing shell scripts or a small single-purpose applications. Not quicker if you're adding to a codebase of any significant size.

Re: Diminishing returns of static typing

#308
post #248

Earlier quoted context omitted.

While it may be frustrating to novice programmers, the distinction between interfaces (List) and implementation classes (ArrayList) is quite valuable, especially when dealing with huge code bases that have to be maintained over decades. Those declarations help to establish an internal design contract and clarify the developer's intent . In this particular case, a future maintenance programmer could switch from ArrayL…

It’s not about having the difference, it’s about having to explain to Javac what I am using because it’s incapable of doing meaningful type inference.

Only in the case of generic erasure, which is a Java wart that we will, sadly, never eliminate.

Re: Diminishing returns of static typing

#309
post #150

Earlier quoted context omitted.

Actually, refactoring browsers were pioneered by Smalltalk people.

I don't understand this argument. In smalltalk the parameter names are part of the function name to reduce the likelyhood of name clashes. You still have the same problem when you have two functions with the same name and parameters.

You understand, someone will always claim that everything was invented by smalltalk at some point.

Re: Diminishing returns of static typing

#310
post #201

Earlier quoted context omitted.

> In dynamically typed languages you kind of just grep and hope the name is not too common. For four days, I spent debugging a python production script because in one place I had typo'd ".recived=true" on an object and just couldn't understand why my state machine wouldn't work. And very quickly, the whole team became fans of __slots__ in Python. I still write 90% of my useful code in python, but that one week of deb…

TXR Lisp, a dialect I created: $ txr This is the TXR Lisp interactive listener of TXR 185. Quit with :quit or Ctrl-D on empty line. Ctrl-X ? for cheatsheet. 1> (set a.b 3) ** warning: (expr-1:1) qref: symbol b isn't the name of a struct slot ** warning: (expr-1:1) unbound variable a ** (expr-1:1) unbound variable a ** during evaluation of form (slotset a 'b 3) ** ... an expansion of (set a.b 3) ** which is located at…

Plus you can eliminate all typos in any language with a simple statistical linter that you can implement in like an hour or two.
Post reply on HN