3 ms·
TypeScript abstracts away details that systems programming usually wants/needs to precisely control. For example, in TypeScript you don't need to care whether
by pornel 4y ago
TypeScript abstracts away details that systems programming usually wants/needs to precisely control.
For example, in TypeScript you don't need to care whether a closure captures any variables or not, and whether these variables are primitive copyable values (like integers) or objects. It works all the same in TypeScript, but at the low level these are different cases, which can be implemented in different, incompatible ways with varying performance.
When a closure doesn't capture anything, it can be simplified to a plain function pointer. If it captures some variables, it needs to carry the data context, and that requires a (pointer, data) pair that has a different representation in memory. If the data it carries can't be trivially copied, then it also needs extra code inserted to keep this data allocated and freed at appropriate time.
TypeScript makes all these 3 cases invisible to you, so it needs no syntax for each of these, but it comes at a run-time cost (a closure may end up represented in its fattest, costliest representation, and you never get the faster/leaner representation).
There's a trope of a Sufficiently Smart Compiler that could in theory figure all these details out for you, and in this case see if your closures never use context, and use the cheaper pointer-only representation instead of always using a costlier object representation. The problem with this is that nobody has written a Sufficiently Smart Compiler yet. These smarts end up needing to analyze the whole program, which at very least is pretty slow to do, and in some cases is even provably impossible to do when program's flow depends on run-time/unknown values.
So the best solution we have is to offer more syntax to the programmer to say exactly what they want.
- grumblingdev 4y agoAnd the syntax could be backwards compatible TypeScript is what I am saying, instead of an entirely new syntax, package manager, etc.
- pornel 4y agoTypeScript's syntax as it exists today wouldn't be usable. TS's type system isn't sound — a valid TS program may still have type errors. This is not a big deal for a dynamic JS VM, but in natively-compiled code it can cause crashes and security vulnerabilities. TS doesn't have syntax for value vs reference types or memory ownership/lifetimes. It relies on a garbage collector to "guess" the information missing from the syntax, but systems programming languages almost by definition do not want to do depend on this. TS's syntax for immutability is almost non-existent. There's no syntax for compile-time vs run-time evaluation distinction. You may be severely overestimating how much it would help you to know syntax of a system's programming language without knowing systems programming (very little, because syntax is the easy part). At best TS's syntax could used as a starting point for a new syntax of a new language, not compatible with TypeScript in any useful sense, with changes and extensions for all the features that low-level programming needs. But if you kept the syntax similar to TS, then new features may end up looking bolted on and forced to use less convenient syntax, since all the most convenient syntax is already taken by TS. This is why Objective-C looks so bizarre — it tried to be a superset of C, but C features already took all the nice syntax. C++ also suffered a lot by trying to be a syntax superset of C and older versions of itself. Building on a wrong syntax as a base leads to poor defaults, confusing recycling of old keywords, and traps caused by having convenient syntax for features you're not supposed to be using any more.
- grumblingdev 4y ago> This is why Objective-C looks so bizarre Interesting point, hadn't thought about this before. > TS doesn't have syntax for value vs reference types or memory ownership/lifetimes...if you kept the syntax similar to TS, then new features may end up looking bolted on and forced I would argue that the vast majority of code in a low-level language doesn't care about manual memory access or pass by val/ref. It's all abstracted away into libraries. It just comes down to a different syntax, but they are all doing the same thing. As seen here: https://rosetta.fiatjaf.com/compare/TypeScript/Rust/ https://rosetta.fiatjaf.com/compare/TypeScript/Rust/. Most of the time we are just passing around references anyway. So why no make this the default implicit case, and then when you need something exotic, add syntax then.
- nyberg 4y ago> I would argue that the vast majority of code in a low-level language doesn't care about manual memory access or pass by val/ref. > Most of the time we are just passing around references anyway. So why no make this the default implicit case, and then when you need something exotic, add syntax then. This depends on what the language is being used for. If it's to write high level glue code then passing references/pointers around is likely the norm. However the majority of cases you will care about how things are passed, how they're allocated, where they're allocated, and so on. If you don't care you're often using the wrong tool for the job or you're writing inefficient messy code. Writing allocators (arena/bump, heap, gc, rc, memory pools, etc) requires control more often than not and applications which desire performance often need to write their own tailored to their usage patterns (e.g you don't want it to free things at the wrong time). Data layout and alignment of said data play a key role in keeping the application performant along with the ability to reinterpret memory without copying values which is something TS lacks. Access to inline assembly for the cases where the compiler generates undesirable code or where what you want to do can't be expressed in the language itself. The above applies to quite a few domains and especially to embedded where you often have limited resources (time, memory, code size, etc). It may seem like a rare case but if you look around your at your everyday appliances around your home, sensors in your car, your headphones, and so on, you'll see that it's a rather common case. It would be good for you to try such languages for a while so you can see why the features presented to you exist and try to develop something which touches the different areas where it's used. Embedded is a nice start with especially dealing with MMIO.