# Solving function ecosystem division

**URL:** <https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538>\
**Category:** language design\
**Created:** [October 11, 2022, 2:17pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538 "2022-10-11T14:17:18Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)\
**Post date:** [October 11, 2022, 2:17pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/1 "2022-10-11T14:17:18Z")

</div>

As Rust is becoming more widely used, many different developers need to use it. There is huge variety in their requirements. System developers want to be able to fully control where allocations occur \[1\]. And the casual user wants to have as little friction as possible, not having to worry about the unlikely scenario that the operating system is unable to supply them with memory.

These goals are at odds with each other. For the time being I think that language development has danced between these two worlds and tried to satisfy both equally. I feel like that this is going to become increasingly difficult in the future. While adding fallible functions to `Vec` has worked out better than providing `FallibleVec` \[2\], I still think having to use `try_push` instead of `push` in an environment where one is _only_ allowed to use fallible allocation (the Linux kernel) is a detriment to ergonomics. Especially when we look at worse examples like `Box::try_new_uninit`. We do not need `Box::new_uninit`, as it panics, but we would like to reuse the name...

I have not done enough thorough research to find if this has been proposed already. This is because I have no idea what to search for. I will name this feature "profile" temporarily (yes it clashes with compilation profile, so it should have a different name, but I could not come up with a better one). There are probably many things that we could do different syntactically, please leave bike-shedding for later.

## The solution

What if we solve this issue of having to cater to multiple diverging worlds at the same time? I think we could introduce so called "profiles". They can be used in an impl block like this:

```rust
impl<T> Vec<T> in @default {
    pub fn push(&mut self, item: T) {}
}

```

I have used `@` as a marker for profiles. The `@default` profile is the default profile! It would need to include the whole of `std` for backwards compatibility. But now we could add some more profiles:

```rust
pub profile no_std;

impl<T> Vec<T> in @no_std {
    pub fn push(&mut self, item: T) -> Result<(), T> {}
}

```

With the magic of profiles, we can have the same function name, but different signature and functionality. While this change is not backwards compatible, I think it could be done over an edition. Also you are not locked out from using the function from another profile:

```rust
#![profile(no_std)] // this sets the default profile

fn main() {
    let mut v = Vec::new();
    v.push(42).expect("ran out of memory");
    <Vec<i32> in @default>::push(v, 42);// this will panic if there is not enough memory
}

```

This feature would need extremely good documentation. I think every function that is only available in a specific profile should be annotated similar to how [std::os::unix](https://doc.rust-lang.org/std/os/unix/index.html) is. There should be some easily accessible drop down menu to select the current profile regardless of the current position.

## Future extensions

There are many ways to extend this feature. For example adding `#![deny_profile(default)]` which errors on `<Vec<i32> in @default>::push()`. Or allowing orthogonal profiles that can be enabled independently. Another more elaborate extension could be to add a profile `@implicit_alloc` and allow implicit allocations for `dyn Future`s returned by `dyn TraitWithAsyncFn`. This could be a bit extreme, but on the other and also be exactly what Rust needs to be more accessible.

## Disadvantages

#### More complexity for API designers:

- which profile should I choose?
- when should I create my own profile?

#### More possibility for bad APIs:

- why does this API use `@default` even though it is compatible with `#![no_core]`?!
- these two methods from the same profile are not even remotely related!

#### "Profile soup"

Users might have to enable too many profiles at the same time, so we would end up with:

```rust
#![profile(no_std, foo, bar, foo_and_bar, )]

```

Users can still enable profiles that conceptually do not fit together:

```rust
#![profile(no_std, implicit_alloc)]

```

We could of course first only allow stdlib to create profiles, preventing the profile soup and we could lint against them not fitting together. But the first two problems still exists...

* * *

Please let me know what you think. For the moment I think we should constrain this feature to implementing inherent methods only.

* * *

1. [https://github.com/rust-lang/rfcs/pull/3271](https://github.com/rust-lang/rfcs/pull/3271) 

2. [Feedback from adoption of fallible allocations](https://internals.rust-lang.org/t/feedback-from-adoption-of-fallible-allocations/14502)

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [October 11, 2022, 2:33pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/2 "2022-10-11T14:33:41Z")

</div>

This seems very similar to [Tyler's proposal for capabilities and contexts](https://tmandry.gitlab.io/blog/posts/2021-12-21-context-capabilities/).

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [October 11, 2022, 2:34pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/3 "2022-10-11T14:34:21Z")

</div>

Also, with the full benefit of hindsight, if we'd had `?` as an ergonomic way to propagate failure, I _wish_ that we had just made all these methods fallible.

---

<div class="post-metadata">

**Author:** ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)\
**Post date:** [October 11, 2022, 2:44pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/4 "2022-10-11T14:44:37Z")

</div>

> [@josh](#):
>
> This seems very similar to [Tyler's proposal for capabilities and contexts](https://tmandry.gitlab.io/blog/posts/2021-12-21-context-capabilities/).

What do you mean by similar? That this problem can be solved by capabilities? I am not so sure, as the signature would be entirely different... But I might be misunderstanding you.

---

<div class="post-metadata">

**Author:** ![tschuett](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tschuett/32/8380_2.png) [@tschuett](https://internals.rust-lang.org/u/tschuett)\
**Post date:** [October 11, 2022, 4:54pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/5 "2022-10-11T16:54:14Z")

</div>

But this hurts readability:

`environment where one is only allowed to use fallible allocation (the Linux kernel)`

```rust
data.push(5);

```

Is it safe in the kernel? Maybe, if there is some config at the top of `lib.rs`?.

---

<div class="post-metadata">

**Author:** ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)\
**Post date:** [October 11, 2022, 5:12pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/6 "2022-10-11T17:12:54Z")

</div>

I do not really understand your points. Could you elaborate on

> [@tschuett](#):
>
> But this hurts readability:

and

> [@tschuett](#):
>
> Is it safe in the kernel?

Because I think pushing an item into a vec is safe (why would it not be?) and I think in general this feature would improve readability.

---

<div class="post-metadata">

**Author:** ![nacaclanga](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nacaclanga/32/7461_2.png) [@nacaclanga](https://internals.rust-lang.org/u/nacaclanga)\
**Post date:** [October 11, 2022, 5:24pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/7 "2022-10-11T17:24:09Z")

</div>

What is the main benefit of having this over simply disallowing some functions in certain contexts? Rust doesn't have general function overloading, so I don't really get, why we should allow overloading here.

```rust
#![profile(no_std)] // this sets the default profile

fn main() {
    let mut v = Vec::new();
    v.try_push(42).expect("ran out of memory");
    <Vec<i32> in @default>::push(v, 42);// this will panic if there is not enough memory
}

```

if we adapt the `try_` convention consistently, it shouldn't increase the workload significantly. Also there might be usecases where end users want to opt in to having an allocation failure available even on other setups, e.g.

```rust
let mut uintbuffer: Vec<u32> = vec::new(); // Some potentially huge vec
let mut special_snowflake_ids: Vec<u32> = Vec::with_capacity(10); // Some normal vec
if buffer.try_reserve(2 << 40).is_err() {
     // Downscale memory usage to avoid using such a huge buffer at the expense of performance
     // ...
}
```

---

<div class="post-metadata">

**Author:** ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)\
**Post date:** [October 11, 2022, 5:34pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/8 "2022-10-11T17:34:38Z")

</div>

> [@nacaclanga](#):
>
> if we adapt the `try_` convention consistently, it shouldn't increase the workload significantly.

It is really annoying when we cannot use the normal names for the operations. In the kernel no allocation may panic. That is just a fact. Why do we have to give up ergonomics for a feature that we are forced to use by our constraints?

> [@nacaclanga](#):
>
> Also there might be usecases where end users want to opt in to having an allocation failure available even on other setups, e.g.
> 
> ```rust
> let mut uintbuffer: Vec<u32> = vec::new(); // Some potentially huge vec
> let mut special_snowflake_ids: Vec<u32> = Vec::with_capacity(10); // Some normal vec
> if buffer.try_reserve(2 << 40).is_err() {
> // Downscale memory usage to avoid using such a huge buffer at the expense of performance
> // ...
> }
> 
> ```

My proposal also allows that:

```rust
let mut uintbuffer: Vec<u32> = vec::new(); // Some potentially huge vec
let mut special_snowflake_ids: Vec<u32> = Vec::with_capacity(10); // Some normal vec
if <Vec<_> in @no_std>::reserve(buffer, 2 << 40).is_err() {
     // Downscale memory usage to avoid using such a huge buffer at the expense of performance
     // ...
}

```

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [October 11, 2022, 6:44pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/9 "2022-10-11T18:44:04Z")

</div>

> [@y86-dev](#):
>
> In the kernel no allocation may panic. That is just a fact.

Honestly, it's hard for me to imagine a situation where one would want to use both panicking and fallible methods on `Vec`. Either you don't care about OOM and the most you do is occasional `Vec::with_capacity` or `Vec::try_reserve`, or you care about OOM and all panicking methods are a footgun which shouldn't be used.

This proposal sounds a bit like feature-gating parts of `std`, except that features are additive while profiles are not. There is also the possibility to use several profiles, but again, I find it hard to imagine why would one do it.

---

<div class="post-metadata">

**Author:** ![tschuett](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tschuett/32/8380_2.png) [@tschuett](https://internals.rust-lang.org/u/tschuett)\
**Post date:** [October 11, 2022, 7:26pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/10 "2022-10-11T19:26:27Z")

</div>

I believe in the kernel that you must use the try\_ family of functions. And there should be lints/clippy that catches misuse.

---

<div class="post-metadata">

**Author:** ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)\
**Post date:** [October 11, 2022, 7:42pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/11 "2022-10-11T19:42:11Z")

</div>

> [@tschuett](#):
>
> I believe in the kernel that you must use the try\_ family of functions. And there should be lints/clippy that catches misuse.

The whole point of the proposal is to permit using the same named function but with _different_ semantic meaning. Why should we litter every call that might allocate with `try_` when we do not have calls without `try_`? I think dropping the prefix when it is obvious results in better readability.

> [@afetisov](#):
>
> or you care about OOM and all panicking methods are a footgun which shouldn't be used.

Which is why I think `#![deny_profile(default)]` is important.

> [@afetisov](#):
>
> This proposal sounds a bit like feature-gating parts of `std`, except that features are additive while profiles are not. There is also the possibility to use several profiles, but again, I find it hard to imagine why would one do it.

The entire point of this proposal is to provide better ergonomics. I do not see a way to achieve this with features.

---

<div class="post-metadata">

**Author:** ![tschuett](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tschuett/32/8380_2.png) [@tschuett](https://internals.rust-lang.org/u/tschuett)\
**Post date:** [October 11, 2022, 7:59pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/12 "2022-10-11T19:59:34Z")

</div>

This is the part that scares me:

` with different semantic meaning.`

Sometimes `push` is `push` and sometimes it is `try_push`. I believe this causes more problems than it helps you.

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [October 11, 2022, 8:24pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/13 "2022-10-11T20:24:59Z")

</div>

I still don't understand why would you want to use both `default` and `no_std` profiles in the same crate.

Nor do I see any other possible profiles, or uses of profiles beyond the `alloc` crate. If it's just to solve the OOM panic issues, we need a finer scoped tool and not a brand new feature with unclear semantics. If it has uses beyond that, it would be nice to include proper motivation.

> [@y86-dev](#):
>
> I do not see a way to achieve this with features.

Features are additive, but there were always suggestions for something non-additive. Let's call it "alternatives", to distinguish from usual features. Now, if features and alternatives could be used in sysroot libraries, we could introduce `no_oom` and `handle_oom` alternatives for `alloc`. The functions would be gated by the corresponding alternatives. Downstream crates could introduce similar aternatives, if they want to support both fallible and infallible allocations.

The core issue that all proposals for fallible allocation hit is that fallibility is infectious. Anything which resorts to `Vec::push` now becomes fallible. Standard traits, like `Extend`, `FromIterator` and `ToString` no longer work, because they don't support fallibility. Modifying traits will introduce even more downstream problems.

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [October 11, 2022, 9:01pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/14 "2022-10-11T21:01:05Z")

</div>

This is a list of traits from stdlib, which would be unapplicable to the standard allocating objects (`alloc::*`) if fallible allocations were required:

- All `FromIterator` and `Collect` impls. Can't collect if the allocation may fail.
- All `From<T>` impls, for various `T`. For example, `Vec` has 10 `From` impls, while `Box` has 28. A few of them may stay, because the impl requires no reallocation (e.g. `impl From<Box<[T]>> for Vec<T>`), but most must become `TryFrom` impls/
- `Extend`, `Clone`.
- For `Vec<u8>`, `Cow<T>` and `String`, the impls of `io::Write` and `fmt::Write` will need to go, or at least to change the implementation significantly.
- For `String`, `Add<&str>` and `AddAssign<&str>`.

That's just the traits directly implemented for the collections.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [October 11, 2022, 10:00pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/15 "2022-10-11T22:00:33Z")

</div>

> [@afetisov](#):
>
> `impl From<Vec<T>> for Box<[T]>`

This also actually requires reallocation to ensure `capacity == len`.

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [October 11, 2022, 10:02pm UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/16 "2022-10-11T22:02:05Z")

</div>

Sorry, I meant the reverse. Edited.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [October 12, 2022, 12:38am UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/17 "2022-10-12T00:38:17Z")

</div>

> [@josh](#):
>
> Also, with the full benefit of hindsight, if we'd had `?` as an ergonomic way to propagate failure, I _wish_ that we had just made all these methods fallible.

On the other hand... no, not really, I don't think `?` is sufficient here. It is the right behavior for desktop applications to by default abort (or at least unwind) on allocation failure, because allocation failure is either a programmer mistake (too large allocation to ever succeed) or going to be OOM killed by the OS.

Even without that caveat, now you're forcing every function to carry annotation for the allocation effect. Again, for a hosted program, allocation is just an ambient thing that you can do. Even Haskell and even [Koka](https://koka-lang.github.io/koka/doc/book.html#why-perceus) don't encode allocation as an effect.

Rust is first and foremost a practical language. I definitely think that encoding allocation in the default allocator as a capability is an interesting approach, but I also believe that Rust made the practical choice in making allocation infallible by default.

... This does give me an interesting idea, though. As a HUGE what if: `Global` had an associated allocation error type of `!`? Then you could gate the infallible allocation methods on `Err=!`. This doesn't solve the need for the `try_` prefix, but it does offer an answer to enforcing use of fallible allocation.

(This also makes me realize I haven't considered how fallible allocation and `Storage` interact properly...)

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [October 12, 2022, 1:23am UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/18 "2022-10-12T01:23:46Z")

</div>

> [@CAD97](#):
>
> Even Haskell and even [Koka](https://koka-lang.github.io/koka/doc/book.html#why-perceus) don't encode allocation as an effect.

Haskell and Koka are functional languages. Haskell is based on a garbage collector, while Koka uses reference counting with smart ownership analysis, but still supports arbitrary object graphs. This makes them unable to care about allocations by design, since the allocation process is a hard requirement for the semantics of the program and is hidden from the programmer.

While most application code wouldn't care about OOM, it would still be valuable to have explicit allocation effects. You may not care about OOM with a global allocator, but you may care about OOM with local arenas, you may care that the global allocations can be easily swapped with local ones, and you likely care which functions have the capability to allocate, for performance and correctness reasons (allocations are generally slow, and uncontrolled dynamic allocations can lead to resource exhaustion).

It would be super valuable to have reified allocation effects, just as it's great that we have reified exceptions (`Result`) and reified asynchrony (`Future`). It's just that it's really hard to fit in Rust's design, doubly so if you want backwards compatibility.

> [@CAD97](#):
>
> As a HUGE what if: `Global` had an associated allocation error type of `!`? Then you could gate the infallible allocation methods on `Err=!`.

I have [proposed](https://github.com/rust-lang/rfcs/pull/3271#issuecomment-1274887918) that in the recent RFC, although it was offtopic and likely went unnoticed. But I doubt that it can be made to work in current Rust. If we want a seamless transition, then we want `fn push(..) -> Result<(), !>` to be usable wherever `fn push(..) -> ()` is currently usable, but that is possible only if we introduce a type coercion `Result<(), !> -> ()`. Coercions are a huge load of complexity and hidden issues, so it's unlikely to fly. Also, I don't see how this approach would solve the infectious ecosystem split that I talked about above (i.e. what would you do to `Clone`, `Extend` and `FromIterator` traits?).

This would be an easier sell if we didn't have to care about backwards compatibility, but still, it requires at least some language features which currently don't exist in Rust.

---

<div class="post-metadata">

**Author:** ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)\
**Post date:** [October 12, 2022, 7:41am UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/19 "2022-10-12T07:41:40Z")

</div>

> [@tschuett](#):
>
> Sometimes `push` is `push` and sometimes it is `try_push`. I believe this causes more problems than it helps you.

But this would be enabled on a module/crate level, in the kernel the current `push` semantics will not occur.

> [@afetisov](#):
>
> I still don't understand why would you want to use both `default` and `no_std` profiles in the same crate.

You already mentioned the only real use case:

> [@afetisov](#):
>
> the most you do is occasional `Vec::with_capacity` or `Vec::try_reserve`

> [@afetisov](#):
>
> Nor do I see any other possible profiles, or uses of profiles beyond the `alloc` crate. If it's just to solve the OOM panic issues, we need a finer scoped tool and not a brand new feature with unclear semantics. If it has uses beyond that, it would be nice to include proper motivation.
> 
> > [@y86-dev](#):
> >
> > I do not see a way to achieve this with features.
> 
> Features are additive, but there were always suggestions for something non-additive. Let's call it "alternatives", to distinguish from usual features. Now, if features and alternatives could be used in sysroot libraries, we could introduce `no_oom` and `handle_oom` alternatives for `alloc`. The functions would be gated by the corresponding alternatives. Downstream crates could introduce similar aternatives, if they want to support both fallible and infallible allocations.

I just wanted to present this idea. I think we should solve the problem of splitting the ecosystem. Personally I do not think that plastering `try_` methods everywhere is going to be the solution. It is distracting for people who do not use them and annoying for people who do not use the normal versions.

> [@afetisov](#):
>
> This is a list of traits from stdlib, which would be unapplicable to the standard allocating objects (`alloc::*`) if fallible allocations were required:
> 
> - All `FromIterator` and `Collect` impls. Can't collect if the allocation may fail.
> - All `From<T>` impls, for various `T`. For example, `Vec` has 10 `From` impls, while `Box` has 28. A few of them may stay, because the impl requires no reallocation (e.g. `impl From<Box<[T]>> for Vec<T>`), but most must become `TryFrom` impls/
> - `Extend`, `Clone`.
> - For `Vec<u8>`, `Cow<T>` and `String`, the impls of `io::Write` and `fmt::Write` will need to go, or at least to change the implementation significantly.
> - For `String`, `Add<&str>` and `AddAssign<&str>`.
> 
> That's just the traits directly implemented for the collections.

I agree, these traits are not usable in a fallible allocation world. Can we improve this situation? I think we could at some point extend Profiles to trait definitions and implementations.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [October 12, 2022, 8:49am UTC](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538/20 "2022-10-12T08:49:30Z")

</div>

> While adding fallible functions to `Vec` has worked out better than providing `FallibleVec`

I don't understand why the linked post doesn't even discuss the mere possibility of having cheap conversion between those types. Some `Into`/`AsMut` impls should significantly reduce the friction (granted, not _zero_ friction)

> What if we solve this issue of having to cater to multiple diverging worlds at the same time? I think we could introduce so called "profiles". They can be used in an impl block like this

This only seems to solve the naming problem, for which types are sufficient imo. It doesn't solve the other problem of detecting panicking code paths in 3rd party crates.

I think to enforce this in a watertight way we'd need an effects system and mark functions with a `no_oom_panic` (or its negation?) effect. And crates/modules/impls could then blanket-apply that effect to all their functions to avoid repetitive annotations.

[Next page](https://internals.rust-lang.org/t/solving-function-ecosystem-division/17538.md?page=2)
