I never dreamed that software developers would manage to make things slower still (by orders of magnitude) by throwing everything onto the 'net and using multiple round-trip web-api calls to do the most trivial things. I just didn't anticipate that this source of inefficiency was there to be harnessed.
(This came to a head for me recently when I was trying out planner apps for my phone. It boggled my mind that, even on a dual 1.8 GHz processor, Asana and MS Planner do not respond instantly.)
The Dylan folks were all trained computer scientists, mostly MIT PhDs, almost all with years and even decades of experience in writing garbage collected languages on resource-constrained machines (e.g. MACLISP). By contrast many of the apps you write are written by much less trained folks using a lot of automation and boilerplate.
While I personally prefer to write tight, clean code directly to the underlying system, I am really glad for this democratization of programming which has lead not only to good careers for people who didn't get to go to MIT/CMU/UCB but also lead to a profusion of great apps. Not everybody has to design TCP but everybody gets to use it.
And note that Dylan had little impact on society while Tinder sure has.
Don't know what I was thinking.
But it also means there's some relatively low-hanging fruit these days if you find a niche where performance is much more important than accessibility :)
We think we have been optimizing for those things, but I don't know that we actually have. Does Ruby/Python really help you get to market faster than would similar languages with static typing and compilers or JITs? (Kotlin, C#, F#, Nim, etc)
There is research that suggests not, certainly I don't think the effect is large if it even exists. Many people use TypeScript because they feel it is a productivity boon over Javascript. We might one day leverage that and use the static types to compile TypeScript more efficient WASM or something, win win situation.
- Garbage collection make performance unpredictable because of collection spikes.
- If you use a big library, you now have to load the library, which is an extra time-sink.
- Likewise for frameworks.
- Optimizing compilers optimize the 80% of our programs that don't need optimizing, and under-optimize the 20% that do.
(This is DJB's argument.)
That might be what he's saying. He didn't say anything about dynamic vs. static typing.Also, there's a counter-argument to this, that writing non-garbage-collected code might result in security bugs (to do with memory management). And security is a non-functional requirement that some might say is more important than speed. It's hard to judge though; there are loads of requiremenets in software dev, and it's hard to balance them.
That's falacy. Don't mix "fully manual memory management" with "I have no GC". Those are 2 totally unrelated topics. GC is one of the way to manage memory automatically. There is hundreds with their own plus-sides and downsides. Here's the least unpopular:
* Stop the world and incremental GC: Makes it easy to write simple code. Doesn't really make the lifecycle explicit so when the codebase grow larger you start to have boilerplate code to manage/close connections/files/transactions. (all toys languages, also Java and Go).
* Reference counting: Can be made fast enough by using some of the pointer 64bits to store its state. A giant problem is that all your libraries have to support compatible "smart pointer" formats or the whole thing become unmanageable. (Modern C++)
* Contacts/Lending: Does it's job, is safe but makes the code more complex by making a lot of implicit things explicit (Rust, Modern C++)
* Explicit ownership + message passing: works well enough for GUI because just like HTML everything is less or more a tree. Also consuming messages allow "higher level" objects not to have to care about pointers. For backend code it's not very good. (Qt-C++)
* Pure functional: Everything is a copy, they get freed when out of scope. Works well for some domain, but gets in your way for more stateful constructs.
* Copy-on-Write: Pass everything by reference (and count them). Copy when they are modified, otherwise point to the real memory. Only solves half of the problem. Assuming most allocations are containers it works well enough. It doesn't attempt to solve objects management.
* Pipelining: Get input, process them, pass them on or free them. The processing should not have to dynamically allocate at all (Bash, Erlang).
* Pre-allocation: Allocate everything at compile time and use buffers big enough for your use case. (C)
* State machines: Encode the object lifecycle as a series of state changes. Release when it reaches end-of-life. Great for protocols, parsing, transactions. You usually can use code generators to generate proven safe C from an higher level format or proof. However it doesn't scale and only matches a subset of programming projects. It's also hard to learn for non EE programmers because it doesn't map perfectly on the iterative Von Neumann CPU. Easy to read but hard to write.
No-GC != security-bugs because of memory management. If a C program uses pre-allocated buffers, then the security issues is because the language is unsafe, not because it has no GC.
I think we can go even stronger than 'probably' - we know that there are people who do work to these constraints, and it's mostly experienced devs from a few starting tracks working on years-long projects.
As far as I know, NASA's coding standards haven't slipped from their famous "0 bugs per 500,000 lines", and that code (along with JPL, Orbital, SpaceX, etc) is often written to harsh physical constraints. Systems like the Mars entry controller have to operate unsupported in environments where slowness, power, and weight are all serious limiting factors. For all that the IoT is a disaster, embedded control software for non-consumer projects is often concise, fast, and reliable.
It would probably be possible to train a lot more high-performance developers than we have now, but the demand certainly hasn't been present and even if we could there'd be a real price exacted in lost development time and features.
It'll be interesting to see what happens as chip speedups become increasingly unavailable; it's possible we'll revisit the old stuff and make it faster, but so far the leading answer appears to be falling back on networking to handle tasks on bigger hardware.