Live data from Hacker News

Why static languages suffer from complexity

hirrolot.github.io

71–80 of 306 posts

Re: Why static languages suffer from complexity

#71

So whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.p…

The real power of dynamic languages is being able to do: const foo = JSON.parse(arbitraryJsonString); and not having to worry about the structure up front.

> The real power of dynamic languages is being able to do: const foo = JSON.parse(arbitraryJsonString); and not having to worry about the structure up front.

That's not power, that's a shotgun aimed at your crotch whose trigger is connected to a cosmic ray detector.

Re: Why static languages suffer from complexity

#72
post #44

Earlier quoted context omitted.

What the heck is 'bar' and 'baz'? So there's no docstring? And the actual variables are that random and indecipherable? Sounds like the problem is that you're tasked with looking at code written by someone who is either inexperienced or fundamentally careless. When dealing with reasonably maintained codebases, this kind of situation would seem pretty rare. In modern python we now have type hints of course, which have…

> In modern python we now have type hints of course, which have helped quite a lot. I had to laugh, hard. If your Python program uses any library whatsoever, chances are that library won't have types, so you can't really use them. Even super widely used libraries like numpy don't have good support for types, much less any library that consumes numpy for obvious reasons.

I had to laugh, hard.

It's fine if you want to insulate yourself. But I don't see that you're making much of a point here.

Re: Why static languages suffer from complexity

#73
This entire article can be summarised as "compile time stuff should use the same language as run time".

I guess the author just hasn't encountered Nim before, where anything becomes compile time by just assigning to a const, and macros have access to the real AST without substitution. Macros also allow compile time type inspection, as they are a first class citizen rather than tacked on.

The compile time print, AFAICT, already exists in Nim as the `&` macro in strformat. That lets you interpolate what you like at compile time, and supports run time values too.

Re: Why static languages suffer from complexity

#74

So whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.p…

Indeed. An interesting reading is https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ...

Re: Why static languages suffer from complexity

#75

So whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.p…

Static languages unfortunately don't save you from that. You find automatically inferred types, or types that refer to some abstract interface or template-class-mess but you have no idea where the actual implementation lives until you compile with RTTI and run it under a debugger... and as tfa posits, people working with the limitations of static languages often end up reinventing a dynamic structure. Is this somehow…

> Static languages unfortunately don't save you from that.

While you still can make a static language that is confusing, it's a lot harder... I challenge you to write a function signature in Rust that is both:

1) Useful

2) As opaque as the python signature above.

> You find automatically inferred types

A minority of static languages do type inference in function signatures. I think it's a bad idea for exactly the same reason the python code is bad. On the other hand, every dynamic language allows you to omit any information about a type signature.

Re: Why static languages suffer from complexity

#76

So whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.p…

Static languages unfortunately don't save you from that. You find automatically inferred types, or types that refer to some abstract interface or template-class-mess but you have no idea where the actual implementation lives until you compile with RTTI and run it under a debugger... and as tfa posits, people working with the limitations of static languages often end up reinventing a dynamic structure. Is this somehow…

They usually save you from that particular pitfall, but not always of course.

Static vs dynamic makes for such difference in the detailed workflow, both in terms of changing existing code & in terms of writing new/(more) from scratch code, yet they can both be quite fruitful, and can both be abused in absurdum.

It seems like people naturally fall into one of the two camps (either by personality or by training), and the other side just seems kind of insane: "how can you even work that way!?". Then culture and idioms emerge over time and strengthen the tribalism.

I've gone back and forth between the two over the course of my career, and it's quite a mind-shift when switching, with a fair bit of pain involved ("but it would be so easy to do this in [old language]", or "what the hell is this garbage anyway!?") and then eventually it settles in and it's not all painful, all the time ;)

(Going back and forth between Scala and Python right now, so this hit a bit of a nerve)

Re: Why static languages suffer from complexity

#77
I think the comparison between printf in Idris and Zig is a little off, since the Idris version defines an intermediate datastructure, and hence requires extra parsing and interpreting functions for it. That's a nice approach, but the Zig version is operating directly on characters, so it's a bit apples-to-oranges.

We can get a more direct Idris implementation by inlining the parser (toFmt) into the interpreter (PrintfType). That lets us throw away `Fmt`, `toFmt`, etc. to just get:

    PrintfType : (fmt : List Char) -> Type
    PrintfType ('*' :: xs) = ({ty : Type} -> Show ty => (obj : ty) -> PrintfType xs)
    PrintfType (  x :: xs) = PrintfType xs
    PrintfType [] = String

    printf : (fmt : String) -> PrintfType (unpack fmt)
    printf fmt = printfAux (unpack fmt) [] where
      printfAux : (fmt : List Char) -> List Char -> PrintfType fmt
      printfAux ('*' :: fmt) acc = \obj => printfAux fmt (acc ++ unpack (show obj))
      printfAux (  c :: fmt) acc = printfAux fmt (acc ++ [c])
      printfAux []           acc = pack acc

Re: Why static languages suffer from complexity

#78

So whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.p…

The real power of dynamic languages is being able to do: const foo = JSON.parse(arbitraryJsonString); and not having to worry about the structure up front.

You can trivially do exactly the same thing in Haskell, so I think you’re suggesting that dynamic languages have no “real power”.

Re: Why static languages suffer from complexity

#79

Earlier quoted context omitted.

> Static languages unfortunately don't save you from that. You find automatically inferred types, Oh yes, they do. Even inferred, the types are there and pretty easy to locate, even if you're not using an IDE.

The types are there.. but you don't know which one it is that your program is dealing with. You could have dozens of implementations for any given abstract interface. One gets picked up at run time.

You don't need to know which one, because the abstract interface tells you how to use it...

Re: Why static languages suffer from complexity

#80

So whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.p…

The real power of dynamic languages is being able to do: const foo = JSON.parse(arbitraryJsonString); and not having to worry about the structure up front.

Rust:

    let foo: serde_json::Value = serde_json::from_str(arbitraryJsonString)?;
There, just as powerful [1]. But you know what's even more powerful? After you've done your dynamic checks, you can do this on the entire JSON tree, or on a subtree:

    let bar: MyStaticType = serde_json::from_value(foo)?;
and you get a fully parsed instance of a static type, with all the guarantees and performance benefits that entails.

[1] Value represents a JSON tree: https://docs.serde.rs/serde_json/enum.Value.html

Post reply on HN