Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've been programming for over 20 years too, and I like dynamic languages. I like them a lot more when they're properly tested and well architected, but even the tire fire codebases are at least debuggable. The compiled stuff helps with types catching the trivial bugs, yes, but it's way too complicated to quickly debug things like seg faults. Dynamic languages let you introspect and modify things way more easily, and this makes things like fakes and mocks for testing way easier. It makes debugging easier. And not having to wait an hour for something to compile is nice.

That said, I love the speed of compiled languages. I once converted a simulation from Python to Cython and saw a 10000x performance boost because of CPU caches and all that. Usually the gains are closer to 10x to 20x, but in some rare moments it's like a rocket ship vs a hang glider.



EDIT: Reading again, I think you are comparing interpreted with compiled languages, not so much static with dynamic type systems.

Seg faults are a prime argument for static typing. The more static and stricter the type system, the less things like seg faults can even happen. Compare Rust to C (both are static, but one more than the other), and at the extreme end handwritten assembly (extremely dynamic). Those are languages used by kernel developers, where errant memory accesses of all kinds are a constant concern.

I don't know why dynamic languages would make introspecting things easier, or debugging in general. I agree that mocking can be easier with dynamic types. Compilation rarely takes long nowadays (incrementally it's usually just a few seconds), so the time saved in knowing that the code is still correct at least within the confines of the type system is well worth it.


As an kernel developer, would you want to take some of the many shell scripts that the kernel has and rewrite them in C?

Different tools for different purpose. Unless there ecosystem was really designed for it, I would not write a driver in a dynamic language. At the same time, I would prefer not to write all the bootstrap scripts during booting in C. If all I am doing is calling other programs, I use shell. If all I am doing is calling a bunch of low level system calls in a restricted environment I would use C. If I am doing a bunch of string editing, process flow management, data compiling with some calls to external programs, I would use a dynamic langue like Python.

I want add a personal opinion in regard to C. Every function gives out an return code which is a kind of "type" that does not get enforced by the compiler. The return code is defined by the manual page and it is up to the programmer to catch it and react correctly to it. If the wrong code occur and the program explode during runtime its the fault of the programmer for not write a program that manage the return code. I would claim that the wast majority of crashes that occur in programs written in C is because programmers failed to realize the full list of possible return codes and what they mean. Here I do prefer dynamic languages because they usually do not leave it up to the manual to defined what return code -42 means compared to -41, and debugging errors when the errors themselves have class names and inheritance tend to be a bit easier in my experience.


The kernel itself does not consist of any shell scripts. It may have them for building the kernel, but just like the shell scripts at boot, the problems solved there are much simpler (mostly call compiler and linker on a set of files). So I agree: For simple high level problems a dynamic language is sufficient.

As to your second paragraph, I do agree that C has a vastly insufficient type system from the 70s (even though I think better type systems were already available at the time, but the inventors of C might not have known or cared about that). Rust solves the problem you described, and what you complain about is actually that errors in C tend to be represented not statically enough.


That is an interesting aspect about rust I have not heard, and since over 50% of my C code tend to be about managing return codes with proper tear down, rust suddenly do look a bit more interesting. However doing a surface look, it seems that rust simply terminate the program when encountering some of the more critical return codes from syscalls, which does exactly feel like it solves the problem. I guess it is also a reason why the kernel might not switch to using rust any time soon, as oom should not cause drivers to just terminate hard. From my surface look, it also seems rust simply uses Result<> where in C you would store the value in an int, and both leaves it up to the user to read the manual and interpret the number into actually meaning. Of course I could be wrong.

In a way it also demonstrate a other line between when I would use shell, Python or C. With shell everything either existed OK or did not, and the return data is always strings, and so the programs written there is built with that in mind. With python I work with structured data, but I don't spend much work or thought on syscalls and what state the machine is in. With C, syscalls management and the state of the machine is the majority of the code. As such one pick the language based on what the code will be focusing on. Dynamic vs static basically becomes a shorthand for that focus.


Comment about seg faults. You can with a little upfront work trap them and pull enough information off the stack to know where that happened.

I find that 90% of the time I can figure it out via inspection of the offending code.

Opinion: The class of bugs that cause seg faults in some languages cause run time errors in other languages.


What's a seg fault? I jest, but static languages have come incredibly far since C++ (where they are already less common than in C) and I truly haven't dealt with a segmentation fault in the past many years working with static languages.


My c++ code has so many someptr!= null checks it’s not even funny. But js has those same checks. What languages don’t?


Haskell, Kotlin, Scala 3 (with a compiler flag) will all remove null from the set of values acceptable by type. (There are others as well) So a String can’t be null ever, you have to do ‘Maybe String’, ‘String?’ or ‘String | Null’ as a type respectively. If this is what you are asking.


Also, maybe it's pedantic, but leaving out null checks in js will not result in a seg fault, it will result in an exception.


And that is different how, as far as a sign the programmer didn’t think the code thru and maybe you can get around some security controls?


You're a python dev and never had to investigate a segfault in some buggy C module?


> but it's way too complicated to quickly debug things like seg faults

I know you've listed the common argument for static vs dynamic (dynamic -> so fast to code but slow to run, static -> way too complicated)but after a decade in SE I still have yet to see some good evidence of this.

Yes some static languages (like Java) will make developing certain things slower vs JS but is Java a good statically typed language ? Maybe these statements are "true" today with the current implementation of one or the other but there are a lot of languages that I just can't see getting in the way.

A new example of this: Kotlin and Swift are statically typed and I would love love to see where it slows these mythical developers that are so fast in a dynamic language but would be slowed down using them. There's obviously going to be a cost for the actual compile time but that should be minimal.

Unfortunately I'm starting to believe that this is just another case of certain developers are used to certain languages.

The trend of the JS move to TS also points to this. Basically JS looks very similar to Kotlin and Swift (TS is basically identical).

To look at your specifics > Dynamic languages let you introspect and modify things way more easily, and this makes things like fakes and mocks for testing way easier. It makes debugging easier. And not having to wait an hour for something to compile is nice.

> Dynamic languages let you introspect and modify things way more easily

In what way ?

> and this makes things like fakes and mocks for testing way easier

Fwiw this is what that fake/mocks look like for a static language `val x = mock<User>()`

To be fair that's using a library and maybe that's part of your criteria ?

> It makes debugging easier

? how, I can see the argument for the other way (one less thing the developer has to worry about - typing issues) but how is dynamic easier to debug ?

> having to wait an hour for something to compile is nice

Completely Fair. Now whether or not the thing you're working on would take an hour to compile I highly doubt. If you're working on a project that would hypothetically take an hour to compile then I really hope it's not written in a dynamic language.

Not trying to pick on you at all, I believe a lot of developers would agree with you but I'm starting to think that there are developers that are just used to one or the other. I have to point out that I could be thinking this way with respect to statically typed languages but I really have a hard time seeing this point (as I would be if I was falling into the same trap I'm "accusing" you of).


Also if you live near to high quality, it is easier to keep quality high. I worked in one place with a lot of C servers. Any time they segfaulted, the developer got an email with the back trace and a link to the core. Counts were kept and managers made sure people knew to fix them. For my code, it was always easy to fix each segfault. They were rare and usually the stack trace showed all that was needed.

I also worked in a place that was far from quality and they had totally given up on memory leaks and most segfaults. If the segfault happened deterministically enough, it might be fixed. infinite loops would be fixed. But sporadic segfaults were just ignored. It was too hard to get close enough to quality to make it worth fixing.


Read what they wrote again, but this time replace "static" with "compiled" and "dynamic" with "interpreted", and suddenly it made sense to me.

It's true that overall, compiled languages tend to be more static, and interpreted languages more dynamic (and there are good reasons for why they end up that way besides mere convention), but nevertheless that's not what this discussion is about.


As a Swift dev, the reason why it slows me down is that I often end up fighting the type system.

I start with a concept, design my data structures on the whiteboard in a way that makes sense, then I try to code it and because of some detail in the type system it doesn't work, and I end up spending huge amounts of times wondering how to translate my concept into code.

I don't have that issue in other languages.

Also, the Swift compiler is really really slow.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: