Oldschooling
Sep. 15th, 2014 03:13 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
It's XXI century. We have flying cars now. What we also have, is a lot of research in programming languages. We have heavy books on refactoring. We have tons of "best practices". And then...
You know, a while ago I bitched about generics in Rust not being really generics, but rather templates, as they are specialized for every type they are used with. In fact, they are more limited than templates, as they don't allow partial specialization.
A few days ago I got wind that they finally woke up and implemented generics as, well, generics. I've checked immediately, and, no, we are still at the same spot.
But then another thought came: how can they specialize generic functions for types they know nothing about? I mean, if module A defines a generic function, and module B uses it with the type also defined in B, and A is compiled first — there is no possible way to specialize this function for the type defined in B, right? C++ avoids this by having all templates implemented in header files, so that they are available when compiling B — which really means that the function is NOT compiled with A (unless it uses it with some other type), but rather with B. Rust can't do that, after compiling the module you can safely remove the source code, and it will work fine.
And somebody answered my question with this: http://www.reddit.com/r/rust/comments/2c6pn0/how_does_rust_implement_calling_generic_functions/cjcio0p
Yep. They keep the source code in the compiled file.
Well, not EXACTLY the source code — the AST. But the difference is, in my book, négligeable.
Yeah. It's THAT bad.
On the other hand, there is Go — which is another new language, intended to fill the same niche as Rust — or at least a close one. It solves the problem with generics elegantly and efficiently — by not having generics. At all.
Which is fine, if there were hope that generics would emerge in some later version — like it was with Java. But it seems that Go people rather enjoy not having generics: "Lack of generics has bothered me a little, but copy and paste with a multiple-cursor editor really makes short work of it."
Yes, its XXI century, and the earth is doomed.
You know, a while ago I bitched about generics in Rust not being really generics, but rather templates, as they are specialized for every type they are used with. In fact, they are more limited than templates, as they don't allow partial specialization.
A few days ago I got wind that they finally woke up and implemented generics as, well, generics. I've checked immediately, and, no, we are still at the same spot.
But then another thought came: how can they specialize generic functions for types they know nothing about? I mean, if module A defines a generic function, and module B uses it with the type also defined in B, and A is compiled first — there is no possible way to specialize this function for the type defined in B, right? C++ avoids this by having all templates implemented in header files, so that they are available when compiling B — which really means that the function is NOT compiled with A (unless it uses it with some other type), but rather with B. Rust can't do that, after compiling the module you can safely remove the source code, and it will work fine.
And somebody answered my question with this: http://www.reddit.com/r/rust/comments/2c6pn0/how_does_rust_implement_calling_generic_functions/cjcio0p
Yep. They keep the source code in the compiled file.
Well, not EXACTLY the source code — the AST. But the difference is, in my book, négligeable.
Yeah. It's THAT bad.
On the other hand, there is Go — which is another new language, intended to fill the same niche as Rust — or at least a close one. It solves the problem with generics elegantly and efficiently — by not having generics. At all.
Which is fine, if there were hope that generics would emerge in some later version — like it was with Java. But it seems that Go people rather enjoy not having generics: "Lack of generics has bothered me a little, but copy and paste with a multiple-cursor editor really makes short work of it."
Yes, its XXI century, and the earth is doomed.
no subject
Date: 2014-09-15 02:13 pm (UTC)I just don't see what's wrong with passing around the AST.
no subject
Date: 2014-09-15 04:11 pm (UTC)no subject
Date: 2014-09-15 04:48 pm (UTC)no subject
Date: 2014-09-15 05:21 pm (UTC)no subject
Date: 2014-09-15 09:11 pm (UTC)no subject
Date: 2014-09-16 06:01 pm (UTC)Separate compilation, anyone?
no subject
Date: 2014-09-16 06:46 pm (UTC)no subject
Date: 2014-09-15 04:06 pm (UTC)no subject
Date: 2014-09-15 04:15 pm (UTC)But I thing the best way would be to borrow Haskell's approach, when a record of functions is passed to the function as an implicit argument.
no subject
Date: 2014-09-15 04:34 pm (UTC)no subject
Date: 2014-09-15 04:50 pm (UTC)no subject
Date: 2014-09-15 05:00 pm (UTC)no subject
Date: 2014-09-15 05:03 pm (UTC)no subject
Date: 2014-09-15 05:16 pm (UTC)"A consequence is that GHC must be able to do cross-module, and indeed cross-package, inlining. The idea is simple:
* When compiling a Haskell module Lib.hs, GHC produces object code in Lib.o and an "interface file" in Lib.hi. This interface file contains information about all the functions that Lib exports, including both their types and, for sufficiently small functions, their definitions.
* When compiling a module Client.hs that imports Lib, GHC reads the interface Lib.hi. So if Client calls a function Lib.f defined in Lib, GHC can use the information in Lib.hi to inline Lib.f."
- Simon Marlow and Simon Peyton-Jones, http://www.aosabook.org/en/ghc.html
no subject
Date: 2014-09-15 05:44 pm (UTC)browsers, kernels - немного другая история. ЧСХ, они не столь низкоуровневые.
no subject
Date: 2014-09-15 05:54 pm (UTC)Но в типичном коде на Расте и подобных ему генериков будет куча, ибо тайпклассы на каждом шагу. Что до низкоуровневости, то тут речь больше о требованиях к эффективности. Если простые операции вдруг будут требовать кучу непроинлайненных вызовов мелких генерик функций (вроде монадных операций), то ничего не взлетит, проект можно закрывать.
no subject
Date: 2014-09-15 07:33 pm (UTC)А попилить язык на подмножества: тут инлайним, тут не инлайним, тут рыбу заворачивали?
генериков будет куча, ибо тайпклассы на каждом шагу
Тады ой.
no subject
Date: 2014-09-16 03:31 am (UTC)Страуструп улыбается и целует в макушку.
no subject
Date: 2014-09-15 07:15 pm (UTC)no subject
Date: 2014-09-15 07:34 pm (UTC)no subject
Date: 2014-09-16 06:01 pm (UTC)no subject
Date: 2014-09-16 02:28 am (UTC)And C++ inlines "generics" on source code level, as you mentioned.
no subject
Date: 2014-09-16 05:03 am (UTC)Anyway, "This is why both Rust and GHC store definitions for inlinable functions" is still wrong. For GHC it might be an optimization; for Rust it's semantics. It's generics just won't work otherwise.
no subject
Date: 2014-09-16 06:03 am (UTC)no subject
Date: 2014-09-16 08:27 am (UTC)no subject
Date: 2014-09-16 10:40 am (UTC)1. A lot of things being written in C++ where inlining is performed earlier, so LTO is not so important there.
2. Typical C code doesn't do so many calls to little functions as would a language full of type classes do, so again, not so crucial for C as for Rust-like.
3. Inertia.
4. Probably low gain from LTO for C. Which means C++ and other aggressively inlining and optimizing languages are bound to be faster than C. Canonical example is sorting: C++ blows C out of the water, being able to inline the comparison instead of calling a function each time.
no subject
Date: 2014-09-16 03:29 pm (UTC)no subject
Date: 2014-09-16 06:03 pm (UTC)no subject
Date: 2014-09-16 07:22 pm (UTC)