4 ms·
After my experience with swift and the bone headed decisions made in lower level design items of the language to make it more 'ergonomic' at the expense of comp
by novok 3y ago
After my experience with swift and the bone headed decisions made in lower level design items of the language to make it more 'ergonomic' at the expense of compile speed and debug-ability, I worry about chris latner making the same mistakes again.
Swift literally took 10x more time to compile than equivalent objective-c code for not much benefit when it first came out, along with a debugger that to this day is significantly slower, unreliable and is still buggier than the objective-c one. It also does not scale linearly in compile time speed when you throw more cores to it, unlike c, c++ & objective-c, and linking is pretty much solved now with the mold linker.
There are / were huge chokepoints in the compiling chain that caused many of these regressions, that when I learned the minor benefits they brought made me do a facepalm. So many literal expensive megayears of life wasted for so little benefit.
%80 of the benefits of swift that were cheap to implement could've been ported over something equivalent to objective-c for little to no compile time penalties with the new ergonomic language syntax, such as strong nullables and enum ADT types. To this day, it's you still have to codegen mocks. It's frustrating.
I would wait and see what benefits that mojo will actually bring, and I hope that chris and the team there has learned from their mistakes with swift, and chose compile speed over little features that many could live without.
I also hope they use this as an opportunity to solve pythons horrible package management issue and copy ideas from rust's cargo liberally.
- chrislattner 3y agoI have literally the same experience about slow and overly complex type systems and too much sugar as you're pointing out. I've learned a lot from it, and the conclusion is "don't do it again". You can see a specific comment about this at the end of this section: https://docs.modular.com/mojo/notebooks/HelloMojo.html#overloaded-functions-methods https://docs.modular.com/mojo/notebooks/HelloMojo.html#overl... ``` Mojo doesn’t support overloading solely on result type, and doesn’t use result type or contextual type information for type inference, keeping things simple, fast, and predictable. Mojo will never produce an “expression too complex” error, because its type-checker is simple and fast by definition. ``` It's also interesting that Rust et al made similar (but also different) mistakes and have compile time issues scaling. Mojo has a ton of core compiler improvements as well addressing the "LLVM is slow" sorts of issues that "zero abstraction" languages have when expecting LLVM to do all the work for them. -Chris Lattner @ Modular
- novok 3y agoHope it works out!
- throwaway894345 3y ago> Mojo has a ton of core compiler improvements as well addressing the "LLVM is slow" sorts of issues that "zero abstraction" languages have when expecting LLVM to do all the work for them. This sounds super interesting. Is there a good write up about this, or about the specifics of what specific type system features tend to make languages like Rust/Swift slow? Is it constraint-solving stuff? Exhaustive pattern matching?
- chrislattner 3y agoWe are a bit overwhelmed at the moment, but sure, this is something we'd eventually give an llvm devmtg talk about or something. Broadly speaking, there are three kinds of things that matter: 1) Type system. If you go with a constraint based hindly milner (https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_sy...) type system and then add things like overloading etc, you quickly get into exponential behavior. Swift has been fighting this for years now to tamp down the worst cases. This isn't good; don't do that. 2) Mid-level compilation model. "Zero cost abstraction" languages including C++ (but also more recent ones like Swift and Rust and now Mojo) rely in massive inlining and abstraction elimination to get "zero cost" behavior. LLVM can do inlining and simplification and all the other stuff, but it is a very low level of abstraction - generating a TON of IR and then asking LLVM to delete it for you is very slow, and shows up in the profile as "llvm is slow" because you're creating all the llvm ir nodes ("LLVM") and then asking llvm optimization passes to delete them for you. It is far better to not generate it in the first place. 3) Code generation: Reasonable codegen is O(N^2) and worse in core algorithms like register allocation and scheduling. This is unavoidable if you want high quality of results (though of course, llvm is also far from perfect). LLVM is also very old and single threaded. If you don't do anything to address these issues, you'll be bottlenecked in this phase. These all have good solutions, but you have to architect your compiler in anticipation of them. Mojo isn't just a syntax or PL step forward, it is a massive step forward in compiler architecture. -Chris
- kenjackson 3y agoDon’t C/C++ scale linearly with more cores because you just compile different compilands on the cores? Wouldn’t that be the same for Swift? Note, I’ve never used Swift.
- novok 3y agoNope it doesn't work that way for swift, stuff has to repeat on multiple cores per file within a single module, leading to being less compute efficient the more cores you add, unless you force everything into a single thread with WMO mode, but then you have manually manage your build graph very carefully to stay compute efficient. It could've changed since I've last looked, but there are still things like that are lurking around. https://github.com/apple/swift/blob/main/docs/CompilerPerformance.md https://github.com/apple/swift/blob/main/docs/CompilerPerfor...
- rfoo 3y agoBut the same also applies to C++. A boatload of my compile time is spent on expanding, parsing the same header files again and again in different compilation units. This can be solved by precompiled headers, yeah. But then again a boatload of the compile time is spent on instantiating the same templates in different compilation units again and again and again. It's just that the fact that the language is cursed from the beginning gives an illusion of "linear scaling".
- pjmlp 3y agoNot if extern templates are used, at least for the common types.
- boxed 3y agoSwift has this weird thing where a two files next to each other can use the symbols from their neighbors without any import. I find this... disturbing.
- adql 3y ago
- vaughan 3y ago> compile speed and debug-ability I wish people would prioritize this more. With every new langauge that comes out, sure it brings a few interesting features, but it always takes 5+ years for IDE support, a good debugger, and compile speed (if ever) to arrive. Good debugging tooling and compiler speed probably outweighs all the other benefits in the long run. Rust is a good example. JavaScript transpiling too. And once it arrives, people will probably be onto the next new language that barely has IDE syntax highlighting ready. > pythons horrible package management It really is terrible. The import system is so convoluted, but I guess it's quite old. Python really needs a good monorepo-friendly package manager like Node's pnpm. Even though the ESM transition is a clusterfuck, the new module system is actually quite nice and straightforward if you don't need to touch older code.
- throwaway894345 3y agoGo does very well here (maybe less so on the debugger, but the simplicity of the language makes me lean on the debugger a lot less than in more complex languages).
- Koshkin 3y ago> Swift literally took 10x more time to compile than equivalent objective-c Same with C++ vs. C
- KerrAvon 3y agoThat depends on the sourcebase and compiler. Anyone who used Metrowerks C++ back in the 90’s can attest that C++ compilation doesn’t have to be slower than C. Swift has baked compilation slowness into the type system, and it will never be as fast to compile as C/C++ on the same hardware. The compiled code might be faster, though.
- FpUser 3y ago>"at the expense of compile speed and debug-ability" To me reduced "debug-ability" is one of the primary reasons to ignore any language however "beautiful" it is
- teleforce 3y agoPerhaps other system programming languages can learn from D language where the DMD, D's reference compiler, compile itself and the entire standard library in less than 5 seconds, with parallelism turned off [1]. [1] Ask HN: Why do you use Rust, when D is available? https://news.ycombinator.com/item?id=23494490 https://news.ycombinator.com/item?id=23494490