Live data from Hacker News

Diminishing returns of static typing

blog.merovius.de

441–450 of 632 posts

Re: Diminishing returns of static typing

#441

Earlier quoted context omitted.

A lot of the same refactoring is possible in dynamic languages as in static ones. I recommend reading up on Term to see what's possible to do with JavaScript http://marijnhaverbeke.nl/blog/tern.html I use Cursive https://cursive-ide.com/ for working with Clojure, and it can do safe refactoring for symbols by doing static analysis of the source. It can show all usages of a symbol, rename it, do automatic imports, and…

For someone only passingly familiar with Spec, what's the benefit of Spec over just using a property based testing framework like Haskell's QuickCheck (and I think Clojure's test.check)? I can encode all those invariants as QuickCheck properties and have them automatically tested against random inputs on every test run. It's still all runtime verification, but with random inputs I actually have more confidence of hit…

Think of QuickCheck/test.check but with better integration into the language.

This makes it much more likely to be used but it's fundamentally the same set of ideas.

A really cool idea I'm playing with at the moment is using fuzzing/static analysis based generators to feed spec/test.check.

I think it will help get past the, imo, biggest issue with generators in that they can miss exceptional cases in the code.

E.g. If (x=="jack and Jill) {exceptional case} is unlikely to be triggered with standard generators but "easy" for static analysis tools to solve.

> Also, with enough heavy lifting you can actually encode all of that in the types in a dependantly typed language like Idris [1]

In theory. In practice it is multiple orders of magnitude harder to prove properties in Idris than it is to spec them using property based testing.

Re: Diminishing returns of static typing

#442

Earlier quoted context omitted.

I mean... I don't really think that's a strong case for calling C's type system weak.

I would say it's mostly a matter of use: In C you deal with void* or typecasts all the time, whereas in higher level languages it's much less common, either because the type system is smarter, or the constraints that it does have are more strictly enforced. For example: you can happily compare a char* and an int in C, but other languages like python might error at the thought.

C is incredibly permissive with regard to its types which are themselves very anemic. With the exception of the numeric primitives, C really only has a single type, the pointer, everything else is just syntactic sugar for various forms of pointer arithmetic. For instance arrays in C are just a shortcut for some pointer plus an offset multiplied by a constant determined at compile time based on what you've claimed is the underlying struct or primitive of the array. Importantly C is perfectly happy to take any random pointer into arbitrary memory and allow you to map any set of offsets into it. It's worth looking at for instance Rust that at least in theory allows the same thing to be done, but only by explicitly opting out of static checks via unsafe declarations. In normal safe code Rust will statically verify that a given reference (pointer more or less) is in fact referring to the type you're code is expecting it to, rather than the C approach of simply assuming the program is correct. Looked at another way, as far as the C compiler is concerned nearly everything is a pointer, and one kind of pointer is entirely exchangeable with another kind of pointer (with at most a cast being required, but probably not even that if it's the entirely too common case of being a void pointer). This is in contrast to nearly every other statically typed language that will either at compile or runtime verify that any given reference is the appropriate type before dereferencing it. C++ nominally at least has a more powerful type system, but since it was designed (in theory at least) as a superset of C, C's permissivity blows a giant gaping hole in its type system.

Re: Diminishing returns of static typing

#443

Earlier quoted context omitted.

I would say it's mostly a matter of use: In C you deal with void* or typecasts all the time, whereas in higher level languages it's much less common, either because the type system is smarter, or the constraints that it does have are more strictly enforced. For example: you can happily compare a char* and an int in C, but other languages like python might error at the thought.

/t/tmp.1q8r9dZAtX > cat test.c int main() { char *test = "test"; int i = 10; return test == i; } /t/tmp.1q8r9dZAtX > cc test.c test.c: In function ‘main’: test.c:4:14: warning: comparison between pointer and integer return test == i; ^~

    $ python -c '"test" == 10'
    $

Re: Diminishing returns of static typing

#444
post #401

Earlier quoted context omitted.

> It is not impossible to prove, and verify mechanically, that a particular program halts. OK, let's put that to the test. Here is a particular program: let x = 6 let y = 3 while true: if y>x then halt if is_prime(y) and is_prime(x-y) then x = x + 2 y = 3 else y = y + 2 endif Can you tell me if it halts or not? > The state of the art is not up to proving every desirable property of every program that we would like to…

I think you have missed my point. I am not saying that humans are able to solve the halting problem! Nor am I saying that static verification is always better than testing. I am saying that you don't need a halting oracle to express and verify arbitrary properties in a static type system, because a static type system can and will reject programs that would not have type errors dynamically. If you write this program i…

> you don't need a halting oracle to express and verify arbitrary properties in a static type system

Replace the word "arbitrary" with "some" and I'll agree with you. There are some things a static type system will tell you. Some of those things are even useful things to know. But there are some things a static type system will not tell you, and cannot tell you, and some of those things are useful things to know too.

Furthermore, the way static type systems are used in practice, they don't just tell you things. They will actually refuse to let you run the program unless it conforms to some preconceived notion of correctness that is built in to the type system. Personally, that's the part that rubs me the wrong way. It is sometimes useful to me to run a program even if I know that it has certain kinds of errors in it.

> it will not type check

I'm pretty sure it would. Why do you think it would not?

Re: Diminishing returns of static typing

#445
post #48

In this thread: people will bring out the same tired arguments for or against static typing, without commenting on the actual content of the post, which was quite good! I have come to see type systems, like many pieces of computer science, can either be viewed as a math/research problem (in which generally more types = better) or as an engineering challenge, in which you're more concerned with understanding and balan…

I think this post was extremely hand wavy. It stated the same divide that is already known, but doesn’t actually make any arguments to why Go or whatever lies on some part of the curve, because it assumes that the way you program at different points on the curve are roughly the same but with more type boilerplate. Higher kinded types offer entirely new ways to program, and stuff like optional typing in Python makes i…

I agree. The graph of static checking vs. lines of code should really be factored into static checking vs. amount of annotations to achieve that level, amount of annotations to write vs. how much that slows you down, and amount of annotations that are already written (in your own code or libraries you use) vs. how much that speeds you up. And those will vary wildly depending both on the language and the programmer.

Re: Diminishing returns of static typing

#446

Earlier quoted context omitted.

Yup, love that about statically typed languages. This happens all the time for me in C#. I have several libraries I like that do a lot of code generation. When the project is young, directly handling the generated classes works well but as the project grows, I inevitably want to wrap the handling of the generated classes. It's awesome to be like, welp... it's time to handle this one type differently. Change the retur…

I’d argue that code generation is an anti—pattern that is only necessary because of static typing. A dynamic language would let you change the implementation of all generated objects simultaneously.

A lot of generated code could be done with reflection or meta-object protocols.

There's a good reason people generate code instead (in statically and dynamically typed languages!): performance.

Re: Diminishing returns of static typing

#447

Earlier quoted context omitted.

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…

It seems to me that you've just invented a static type checker. (Combined with a run-time type checker.) Am I mistaken? I mean, we can argue the semantics of what, exactly "static type checker" means, but...

Static checking doesn't make a "static language".

A "static language" occurs when we have a model of program execution that involves erasing all of the type info before run-time. Or most of it. (Some static languages support OOP, and so stuff some minimal type info into objects for dispatch.)

Note how above, my expression executes anyway; the checks produce only warnings. The warning for the lack of a binding for the a variable is confirmed upon execution; the non-existence of the slot isn't since evaluation doesn't get that far.

If we retain the type info, we have dynamic typing. There is no limit to how much checking we can do in a dynamic setting. The checking can be incomplete, and it can be placed in an advisory role: we are informed about interesting facts that we can act on if we want, yet we can run the program anyway as-is.

Re: Diminishing returns of static typing

#448
post #414

Earlier quoted context omitted.

4. Performance. There is software that can't be slow.

Incredulous that people would downvote this.

Seriously with the downvotes? Dynamic languages are obviously slower than static languages in general. Some special cases aside.

Performance is a concern for some projects - you wouldn't write an OS, database kernel, or mainstream game engine in a dynamic language.

How is that not a valid concern in the dynamic vs static typing argument? The parent comment has a legitimate point.

Re: Diminishing returns of static typing

#449
post #415

There are 3 main areas of interest in the discussion of benefits of static vs dynamic typing. - Quality (How many bugs) - Dev time (How fast to develop) - Maintainability (how easy to maintain and adapt for years, by others than the authors) The argument is often that there is no formal evidence for static typing one way or the other. Proponents of dynamic typing often argue that Quality is not demonstrably worse, wh…

These are good points, but what about considering replaceability as an alternative to maintainability? I personally find dynamic languages allow for easy replacability, as there's less explicit references of types. However this is highly dependent on the system being somewhat modular I suppose.

This is basically why erlang's hot code reloading would be impossible as a general solution in a statically typed language

Re: Diminishing returns of static typing

#450
post #448
post #414

Earlier quoted context omitted.

Incredulous that people would downvote this.

Seriously with the downvotes? Dynamic languages are obviously slower than static languages in general. Some special cases aside. Performance is a concern for some projects - you wouldn't write an OS, database kernel, or mainstream game engine in a dynamic language. How is that not a valid concern in the dynamic vs static typing argument? The parent comment has a legitimate point.

Technically, this is a strong/weak type distinction. Dynamic but strongly typed languages like Julia and erlang can be quite performant when given strong fences around the types their functions are passed.
Post reply on HN