-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Problem with generics and bare functions #1038
Comments
(I'm assuming safe spawning is the primary motivation for bare functions. If it is actually 'saving a word of storage', ignore what comes after---) What if we support 'unique functions' (terrible term) instead of bare functions? They'd be closures that own all the values in their environment (the environment being a unique pointer as well). They'd be more compatible with regular blocks (you could pass a fn~ to a function expecting a block), and for real bare functions the environment field can simply be a null pointer, so no extra malloc is required. |
Spawning is the primary motivation for having some sort of typesafe function that can cross tasks. The reasons for preferring bare functions to unique functions are somewhat murky to me, but pcwalton and dherman have both expressed doubts. One tangible issue is that type descriptors are not unique-kinded so putting them into unique closures and passing them between tasks presents obstacles. I'm going to make it so you can't take the value of generic bare functions. It doesn't bring me joy. For reference, graydon's notes on function types are here: https://github.com/graydon/rust/wiki/Function-types |
Also, the plan is to turn function items into bare functions, which means that anywhere we are taking the value of a generic function currently will have to become a bind. |
I'm going to add further checks unrelated to unsafe. Issue #1038
We've discussed this before and I agree that it's a severe problem. As far as I can tell we have to do one of these things:
All of these are painful. #2 is especially bad for performance, but it's probably the easiest to implement. In any case, I think that sending is the nail in the coffin for type-passing. The only option that's acceptable for production is #1. |
Fwiw, we have experimented #1 and something that looks like #2 in Opa, with the added difficulties that we had to pass types between (untrusted) computers and that our type system allowed (possibly recursive) open sums and open products. The results were unfortunately unimpressive with either solution. Both solutions caused our binaries to grow enormously. #1 because of the sheer number of polymorphic calls in our code, #2 because of the size of the type descriptor store, despite our optimizations. Solution #2 considerably slowed down communication. Solution #1 was largely incompatible with separate compilation and caused surprising bugs (e.g. with mutable cells that were somehow monomorphized as a side-effect of the monomorphization of something else). I personally believe that #2 is the least fragile. I am really not sure how you would go about #1 without a quite complex linking phase. |
I don't accept the assertion that #2 is unacceptable for performance. This is hypothetical. Many tydescs are static and if the dynamic cases are really so bad in practice, there are options:
|
For #1 we basically have to do something like serializing ASTs. Interprocedural tydesc escape analysis seems complex, but we might be able to get away with something simpler: just dynamically (shallowly) copy a type descriptor into the new type descriptor whenever we're creating a derived type descriptor. The latter option is #3 above. It'd be tricky to get working but should be possible. I'd be worried about slowing down communication though. |
Is seems #3 requires yet another function type. That's unfortunate, of course. |
If you mean "unique closure", this is necessarily the case (always was) to get the kind-based control of closures working, to prevent accidentally racing on captured environments between tasks. |
Unique closures have been implemented. The current semantics are that closed over type descriptors are cloned into the shared heap as needed. |
…t-lang#1038) * Remove some assets * Remove `rust-doc` files and submodules * Remove static files and references to them * Remove `highlight` tests and fixtures * Remove templates and code that used them with warnings (now hidden) * Add copyright modifications for TOML files * Add copyright modifications to Rust files * Remove asset formats not present anymore from exclude list * Keep original scope for non-used attributes * Remove html tests from `mod.rs` * Fix format issues
As a result we can't do bare-fn spawn for generic functions, which is pretty important:
The text was updated successfully, but these errors were encountered: