Hacker News new | past | comments | ask | show | jobs | submit login

Dynamic types are considerably more flexible than static types. It's not just about typings them out. There are lots of types that you just can't have in static languages (that exist so far), because the language doesn't have the vocabulary to describe them.

Code in dynamic languages typically takes advantage of the flexibility to do meta-programming, which can significantly both the amount of code required to complete a task and its complexity.




I keep hearing that, but in practice one can have macros/code generation in a static language. Maybe meta programming takes a bit more effort, but it's the kind of thing best done in a well tested library.

A lot of modern typed languages have got pretty decent meta programming: rust procedural macros, nim, D, crystal, Zig... Where's the equivalent of serde in python? It's mostly runtime type driven deserialization that is orders of magnitudes slower.


hyperjson? (Python bindings for Rust’s serdes-rs).

It’s not really a cheat answer - what if you could iterate quickly and launch 5 startup ideas in the time to launch 1 written in Zig but when one of your 5 turns out to be the next Youtube / Instagram / Facebook / [insert other huge traffic site launched on a “slow” backend here] then you have the freedom to glue in some optimised native code in the hot path?

I haven’t gotten to macros yet in my Rust playtime so far but Rust does seem like a really nice complement to Python. Go/Swift strike me as a faster Python - nothing wrong with that, Rust strikes me as a different kind of tool, that appeals. Zig / nim are too bleeding edge for me, when i saw the cool kids start to decry Rust, that was my cue to finally go order the O’Reilly book and dig in (i’ll admit to reading up about comptime to see what the fuss was about - cool idea, i’ll stick with trying Rust for now).


That's interesting. The recent post about a fast dataframe library in rust (polars, I think) and its python bindings is also telling. Py3O might be a rust+python kind of secret weapon in terms of speed and productivity... And it's based on the procedural macros I was mentioning :-).


Just anecdotally, I used to work with a lot of dynamic languages, and in static languages I don't miss the dynamism at all. But when I go back to dynamic languages, I miss the type checking a lot.


From my highly biased experience, I miss the dynamism all the time, but only for the specific reason of code hotloading.

I love Emacs for its extensibility and the capability to make changes to the system and see them immediately. Until programming languages like Mun catch up, I doubt it would be possible to replace Emacs Lisp with a statically typed language and retain the same amount of extensibility. Part of the requirements would be having the ability to replace the implementation of any function in the system at runtime, and that's the kind of thing you have no choice but to design your language from the ground up to include.

I guess what I mean to say is that it's not static languages that make me miss dynamic language features, it's that there's no statically typed language that supports the runtime hotloading that I can accomplish with a few Lua scripts (and has enough community traction to support something like LÖVE 2D).

Steve Yegge wrote an article related to this. He suggests that people who use static type systems are mostly trying to catch errors at compile time, errors which have no relevance after the typechecking is over with and the code is run (in the sense that machine code has no understanding of types). Static and dynamic languages will both ultimately output machine code that does the same thing, but one language incurs a massive penalty to flexibility of change. It's a rant, but it made me think that maybe you could have the type checking to catch errors at the time you're specifically looking for errors, and use the dynamism of the underlying implementation later on.

http://steve-yegge.blogspot.com/2007/01/pinocchio-problem.ht...


Just in terms of my subjective experience, the main benefit of type checking is that it codifies intent into the implementation. In many cases it feels like you can obviate unit tests, because the compiler can now verify that your code can do what you intend it to do.

But I do disagree with one of your assertions:

> Static and dynamic languages will both ultimately output machine code that does the same thing, but one language incurs a massive penalty to flexibility of change.

In my mind, this is a clear win for static languages. As you have said, it's all machine code in the end - but for static types the compiler can often make more precise decisions about the size of a stack frame, for example, where in the dynamic case it's not so easy. Dynamism doesn't come for free, and probably most of the time we don't need to do fancy type manipulation or dynamic dispatch at runtime, so it doesn't make sense to pay that fixed cost on all my code for something which is done only rarely.

Also I have never really understood the lack of "flexibility" imposed by a type system. Sure if I add a field to a type it might break some code elsewhere in my program, but I don't see that so much as inflexibility as much as the compiler catching a bug I would have been scratching my head over at runtime.


> probably most of the time we don't need to do fancy type manipulation or dynamic dispatch at runtime

The fact is, I really wish there were a way to have the ability to build systems that you can recompile at runtime that had types. The recompilation itself is the "problem," or at least an inconvenience. You have to interrupt your flow in order to test even the smallest change. Yes, this is a selfish programmer desire to make building things easier.

The general consensus is that it's not worth having flexibility over the stability that types enforce, and for most cases I would agree. It would be ridiculous to program critical systems like financial software with the expectation you'd be able to walk right up to it and deploy changes whenever you want. There isn't a need for extensibility with that use case. But there are some cases where extensibility is a key part of the development cycle, like Emacs or Excel or game development. Iteration is important in those cases, seeing that you can make some changes and test them out, "teaching" the program what you want until it's just right. My experience is that this is an optimal development cycle, where I'm not prone to be distracted easily and lose more time than I needed to when I intended to just compile something.

It's just that I'm not seeing why having types means you must use a machine-compiled language, meaning you now have to reboot the program to see your changes. I wish there was a best-of-both-worlds solution that works in the weird way I expect. The closest thing I know of is Teal, which compiles to Lua, but it will be a while before it's production-ready.


>> In many cases it feels like you can obviate unit tests

And that is the trap. So far each time I’ve come across someone who’s fallen down the types all the way down hole, they’ve shared a view like this.

In the times where i’ve dug deeper, they were applying a bad unit testing strategy where they aimed for 1:1(+) ratio of methods to unit tests - save that granular level of testing for really specific cases. The heuristic to use is “can i refactor my code without changing a single test?” - if your refactor commit has changes to tests then you’re not refactoring your just changing. Your unit test suite is too tightly coupled and is going to cost a fortune to maintain, even more so in a statically typed language.


I don't know what the " the types all the way down hole" is, but you sure seem to be ascribing a lot of views to me which I don't hold. I also don't know what this tangent into unit testing strategies has to do with any of the prior points about type systems.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: