Turbofish can be tamed by having syntax sugar for Types referring to one T only. If we imagine them to be a hierarchical structure (like directory tree) we can use a backslash \
to chain the elements.
To understand how common a long turbofish is, I have done overview of Bevy and Tokio codebases, and they have a lot of sequences of >>>
and >>
, and a limited number of >>>>
turbofish "heads".
Here's some examples (including where the sugar is not effective) and with and without sugar applied
From Bevy:
pub type RemovedIter<'a> = iter::Map<
iter::Flatten\option::IntoIter\iter::Cloned\EventIterator<'a, RemovedComponentEntity>,
fn(RemovedComponentEntity) -> Entity,
>;
// de-sugared
pub type RemovedIter<'a> = iter::Map<
iter::Flatten<option::IntoIter<iter::Cloned<EventIterator<'a, RemovedComponentEntity>>>>,
fn(RemovedComponentEntity) -> Entity,
>;
mut sysinfo: Local\Option\Arc\Mutex\System,
mut sysinfo: Local<Option<Arc<Mutex<System>>>>,
changed_by: MaybeLocation\ThinArrayPtr\UnsafeCell<&'static Location\'static>,
changed_by: MaybeLocation<ThinArrayPtr<UnsafeCell<&'static Location<'static>>>>,
let spawned: ConcurrentQueue\FallibleTask\Result<T, Box\(dyn core::any::Any + Send)>
let spawned: ConcurrentQueue<FallibleTask<Result<T, Box<(dyn core::any::Any + Send)>>>>
From Tokio:
#[derive(Clone)]
struct DropWaker(
Arc\AtomicBool,
Arc\Mutex\Vec\Pin\Box\tokio::time::Sleep,
);
// de-sugared
#[derive(Clone)]
struct DropWaker(
Arc<AtomicBool>,
Arc<Mutex<Vec<Pin<Box<tokio::time::Sleep>>>>>,
);
pub(crate) struct RcCell\T {
inner: UnsafeCell\Option\Rc\T,
}
// de-sugared
pub(crate) struct RcCell<T> {
inner: UnsafeCell<Option<Rc<T>>>,
}
Mutex\Option\VecDeque\task::Notified\Arc\Shared
Mutex<Option<VecDeque<task::Notified<Arc<Shared>>>>>
Poll\Result<OwnedPermit\T, PollSendError\T>
Poll<Result<OwnedPermit<T>, PollSendError<T>>>
type InnerFuture<'a, T> = ReusableBoxFuture<'a, Result<OwnedPermit\T, PollSendError\T>>;
type InnerFuture<'a, T> = ReusableBoxFuture<'a, Result<OwnedPermit<T>, PollSendError<T>>>;
assert_send_sync::<JoinHandle\std::cell::Cell\()>()
assert_send_sync::<JoinHandle<std::cell::Cell<()>>>()
async_assert_fn!(tokio::sync::OnceCell<NN>::get_or_try_init( _, fn() -> Pin\Box<dyn Future<Output = std::io::Result\NN>>): !Send & !Sync & !Unpin);
async_assert_fn!(tokio::sync::OnceCell<NN>::get_or_try_init( _, fn() -> Pin<Box<dyn Future<Output = std::io::Result<NN>>>>): !Send & !Sync & !Unpin);
Previous works
From: Uther
If you want that kind of syntax you will need another character for generics or you will need to change the macro invocation. For instance `Option`Rc`RefCell`Node` would seem pretty clean to me
Ref: Cleaner syntax for generics - #23 by Uther
Pros (subjective ofc):
- Improves readability (everyone knows how directories work)
- Removes the turbofish head
Cons (subjective):
- Introduces another way to do the same thing,
- No one cares about the turbofish head, we have modern editors to help us with the nesting of T's,
- Doesn't make it significantly more concise,
- Doesn't work with entities which accept two type-parameters.
Opinions?