I’ve seen a few threads lately trying to come up with syntaxes for unnameable entities. I figured I’d make a complete list of everything that is currently unnameable, so that we can try to deal with it all at once. This is all in absence of typeof
, of course.
This is an incomplete list based off my excellent^W iffy memory. Let me know if I missed anything!
Types
- The type of a function.
fn foo(_: T) -> U { .. }
// problem: I can't name the ZST that the following types as:
let bar = foo;
// workaround:
type foo_t = impl Fn(T) -> U;
let bar: foo_t = foo;
- The type of a fn-local item (struct, enum, type, etc)
// problem: I can't name `???` outside the fn scope
fn foo() -> ??? {
struct Foo;
Foo
}
// workaround:
struct Foo;
fn foo() -> Foo {
Foo
}
- The type of a closure.
fn foo() -> impl Fn() -> i32 {
|| 0
}
// same problem as the type of a function, really
- Output of a function.
fn foo() -> i32 { 0 };
// problem: how can I name this type without naming it again?
let bar = foo();
// workaround via assoc. type
type foo_t = impl Fn<()>;
let _: foo_t = foo;
let bar: foo_t::Output = foo();
Values
- Fn-local item (fn, const, static).
fn foo() {
fn bar() {}
}
// problem: how do I name bar outside of foo?
let baz = foo::bar;
- The captures of a closure. One can argue that those can’t be made
pub
though.
let a = 0;
let b = 1;
let bar = move |x| x + a - b;
let mut baz = bar.clone();
// problem: how do I do this? (assuming the field's
// name is the same as the capture's)
baz.b = 1;
// workaround: transmute! (or ptr casts) this is unstable though
// and maybe even UB!
unsafe { *transmute::<_, *mut i32>(&mut baz).offset(1) = 1; }
Lifetimes
- The lifetime of a function’s body.
fn foo(x: T) {
// problem: what lifetime goes here? sure, we can let the compiler
// infer it but relying on inference to name a lifetime
// can lead to problems if inference isn't allowed in some palce
let foo: &'? T = &x;
}
- The lifetime of a struct.
struct MyBox<T: ?Sized> {
// problem: what lifetime goes here? I need to use `*mut T` instead,
// since I can't just say "this pointer lives for as long as this
// this struct does" (we don't have &move yet but my point stands)
ptr_to_heap: &'? move T,
}
Solutions
The following are some ideas I’ve had/seen for solving each of these.
- Type of fn:
fn foo
orfoo::type
. - Type of fn-local item:
(fn foo)::Foo
,foo::type::Foo
,foo::Foo
. - Type of closure:
// introduce a new type inside the closure by ascribing the closure.
// there's a lot of unresolved problems with this, so it should probably
// be discussed in its own thread
fn foo() -> fn::Closure {
(|| 0): Closure
// or
let closure: Closure = || 0;
closure
// or maybe denote that it's a new type with special syntax?
let closure = struct Closure || 0;
}
- Fn output:
foo::return
?(fn foo)::return
? Could also imaginefoo::yield
for generators. - Inner fn: same as inner type.
- Closure captures: probably should be described in its own thread.
- Fn body lifetime:
'fn
. - Struct lifetime:
'self
.
PS: There’s one slightly insane corner case, where it’s impossible to name a lang item (like one of the panic fns) if you don’t know what it’s actually called. Imagine the following:
#![no_std]
fn my_panic() -> ! {
__lang__::panic_fmt()
}
I don’t think this is actually useful in any way, but I figured I’d mention it.