Live data from Hacker News

Diminishing returns of static typing

blog.merovius.de

531–540 of 632 posts

Re: Diminishing returns of static typing

#531

Earlier quoted context omitted.

>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.

Decent programmers compose code bases of "significant size" from many small, loosely coupled single purpose applications. Yes, IME it's still quicker. OTOH, if you're using "codebase of significant size" as code for "big ball of mud", static typing certainly helps, but integration tests are the real lifesaver.

>OTOH, if you're using "codebase of significant size" as code for "big ball of mud", static typing certainly helps, but integration tests are the real lifesaver

No. I mean when the codebase is of a certain size, new features require some thought and planning. Features may span multiple-modules. They may require partial or full rewrites or the refactoring of any number of sub-components to support the new behaviour. This means that you proceed carefully because you may not want to introduce regression bugs. This costs time. At that point, you're not limited by your typing speed as you may be putting in net 10 lines of code a day. There is just no benefit to dynamic typing at that point. Worse for dynamic languages, this is where improved tooling and static type constraints start paying extreme dividends.

Re: Diminishing returns of static typing

#532
post #472

Earlier quoted context omitted.

Don't mutable and immutable references with lifetimes count? Sure, one could argue whether the borrow checker is really part of the type system, but it's a compile-time check either way. Yes, in the standard library, an immutable object can hide mutable state in e.g. a 'Mutex', and effects to the external system aren't wired through anything like monads or unique objects. I see those as compromises Rust makes in the…

Right, but you are addressing only part of the story to side-effects. IO is another story, which rust doesn't address.

The standard library doesn't, and most crates don't, but I'm pretty sure nothing prevents you from writing libraries in a style where all IO requires mutable access to some explicit unique "World" object, similar to Clean.

Passing a unique world object around is effectively the same as composing with the IO monad, and borrowing 'f(&mut world)' is basically equivalent to 'let world = f(world)'.

Maybe someone will one day write a standard library in that style.

Re: Diminishing returns of static typing

#533

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…

10-20 years?! Holy Cow! Other than huge software projects (like Word or Mac OS - and even then...) is there really software that still has that kind of maintenance window? I've worked for a Fortune 150 company for nearly 2 decades. There is not a single piece of software at the company that has not been rewritten from scratch (usually due to business changes) at least once every 10 years. I can't even imagine somethi…

I'm working for a healthcare insurer and I don't believe anything has been rewritten since they went from mainframe to .Net.

The previous application I worked on is over a decade old (and it shows). The current application I'm working on is about 8 years old.

Neither applications has any sign of being replaced. Which would be insane, as they both have roughly a decade of laws & regulations and business lessons embedded in them. Despite the state of especially the older application, I don't see how rewriting the entire application would fix anything.

At best parts would be rewritten. And the parts I'm thinking about wouldn't be rewritten because of technical reasons, but because of the way they work. The prime example is a part that only 1 person, a business user, understands.

Re: Diminishing returns of static typing

#534

Earlier quoted context omitted.

Not sure about LINQ, I thought that was "just" syntactic sugar for a bunch of collection methods. Are you refering to extension methods as an unfortunate prerequisite? But I think I get your general point: things like 'Control.Concurrent.Async' ('async'/'await') and 'Control.Monad.Coroutine' ('yield') are libraries that implement some and very generic type classes: 'Functor', 'Applicative', 'Monad'. This then lets yo…

Just like async/await, LINQ (and even enumerators) are tied to special syntax in the C# language. HKTs allow Haskell to provide very general resuable syntax, such as do notation. What I meant by "polymorphic programs" as an alternate to DI, is something like this: doStuff :: HasLogger m => Input -> m Output The effectful function "doStuff" above is polymorphic with respect to which logging implementation is used, it…

Ok, the point about special syntax is fair, but as I said, I'm happy with the use cases that have trickled down to mainstream, and I'd argue there aren't _that_ many truly useful ones. I realize this is very analogous to how the Go programmer is somehow happy with the few generic collections they are granted :)

Your DI example seems to be an example of my earlier point about "emulating things you could do with side-effects". No HKTs are needed when you just pass an impure side-effectful Logger object. Or, as discussed in another subthread, you could do side-effect management with Rust-style uniqueness typing, which results in a less elegant but arguably easier to use type system. It's debatable, but it seems people struggle less with the borrow checker than with advanced Haskell.

Re: Diminishing returns of static typing

#535

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…

10-20 years?! Holy Cow! Other than huge software projects (like Word or Mac OS - and even then...) is there really software that still has that kind of maintenance window? I've worked for a Fortune 150 company for nearly 2 decades. There is not a single piece of software at the company that has not been rewritten from scratch (usually due to business changes) at least once every 10 years. I can't even imagine somethi…

> I can't even imagine something that would still be useful after 10 years

Ah the HN perception bubble.

Good code last longer than that. Bad code gets replaced.

Re: Diminishing returns of static typing

#536

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.

You can actually do a huge amount of metaprogramming in dependent type systems and still have the the power of static checking. We're still figuring out how to improve the ergonomics to the level that it matches macros and other code-gen methods, but it's super exciting stuff.

Re: Diminishing returns of static typing

#537

Earlier quoted context omitted.

Just like async/await, LINQ (and even enumerators) are tied to special syntax in the C# language. HKTs allow Haskell to provide very general resuable syntax, such as do notation. What I meant by "polymorphic programs" as an alternate to DI, is something like this: doStuff :: HasLogger m => Input -> m Output The effectful function "doStuff" above is polymorphic with respect to which logging implementation is used, it…

Ok, the point about special syntax is fair, but as I said, I'm happy with the use cases that have trickled down to mainstream, and I'd argue there aren't _that_ many truly useful ones. I realize this is very analogous to how the Go programmer is somehow happy with the few generic collections they are granted :) Your DI example seems to be an example of my earlier point about "emulating things you could do with side-e…

I don't see how passing in a logger object explicitly is the same, this is what OO DI frameworks try to avoid, otherwise you'd also have to pass it down to other functions used inside. The example above works just like a Reader Monad, but we are not tied to any specific logging implementation.

I guess the side effecting version is just to use some global registry to look up the logging implemention to use. But such code does not compose.

Re: Diminishing returns of static typing

#538

Earlier quoted context omitted.

10-20 years?! Holy Cow! Other than huge software projects (like Word or Mac OS - and even then...) is there really software that still has that kind of maintenance window? I've worked for a Fortune 150 company for nearly 2 decades. There is not a single piece of software at the company that has not been rewritten from scratch (usually due to business changes) at least once every 10 years. I can't even imagine somethi…

> I can't even imagine something that would still be useful after 10 years Ah the HN perception bubble. Good code last longer than that. Bad code gets replaced.

Good code is replaceable. Bad code is hard to get rid of.

Some code sticks around because it's great at what it does. Some code sticks around because it works if you don't touch it and is impossible to delete due to various kinds of dependencies.

Re: Diminishing returns of static typing

#539
post #237

Earlier quoted context omitted.

OK, but that wasn't the original question. (There are also all sorts of optimizations that can't be done statically, so I guess there's that.)

The original question asked whether static typing is needed when maximal performance is required. If we understand "maximal" to mean literally, "no more performance can possibly be squeezed out", then it simply is. Static typing might not be sufficient for this case, but it is necessary.

I think those few, crucial pieces of hand-written assembly language one sees from time to time disagree with you. (Modulo your observation that assembly languages are trivially statically typed.)

Re: Diminishing returns of static typing

#540

Earlier quoted context omitted.

Just like async/await, LINQ (and even enumerators) are tied to special syntax in the C# language. HKTs allow Haskell to provide very general resuable syntax, such as do notation. What I meant by "polymorphic programs" as an alternate to DI, is something like this: doStuff :: HasLogger m => Input -> m Output The effectful function "doStuff" above is polymorphic with respect to which logging implementation is used, it…

Ok, the point about special syntax is fair, but as I said, I'm happy with the use cases that have trickled down to mainstream, and I'd argue there aren't _that_ many truly useful ones. I realize this is very analogous to how the Go programmer is somehow happy with the few generic collections they are granted :) Your DI example seems to be an example of my earlier point about "emulating things you could do with side-e…

Looks like we reached maximum thread depth so replying here.

I agree, the side-effectful choices are either a global, some DI container, or just passing it down.

For loggers, I think global lookup from some (pluggable) logging library is justified because logging is probably the most ubiquitous cross-cutting concern ever. For pretty much everything else, I think passing as a parameter is actually the best option. It's explicit and simple, and you don't even need to explicitly pass it around _that_ much if you store it in a field of a class that plays the role of a module. Most uses of the dependency will be in non-static methods, lambdas, or inner classes.

I dislike Reader because it's similar to a DI container (or a global) in that it's more work to figure out, for a given call site, what the last value written to it was. With parameters, you just climb the call chain.

Post reply on HN