So I've been thinking about this naming issue since at the moment I am
somewhat blocked for names. It seems to me that there are two
orthogonal features which are somewhat tied together in our current
closure system:
- how the environment is referenced;
- what data the environment contains.
A unique closure references its environment by a unique pointer (~) and
only permits the environment to contain sendable data. A boxed closure
(lambda) references the environment via a box pointer (@) and only
permits the environment to contain copyable data.
I am not proposing we separate these things: I don't think there is a
need to have a unique pointer to an environment that closes over
copyable data nor boxed closures that close over only sendable data.
However, the choice of names for unique/boxed closures will probably
depend on which of these two features we wish to emphasize.
I like the idea that "fn" is just the type of a general closure (i.e.,
"block"). I agree it's what you want most of the time. I think that
there are then three logical choices for boxed/unique closures:
1. `fn@` and `fn~`: this is intended to emphasize the fact that the
environment is referenced by a boxed/unique pointer. I don't know how
intuitive it is and it makes heavy use of sigils.
2. `copyfn` or `sendfn`: this emphasizes the kind restrictions. This is
also nice because a `copyfn` is copyable and a `sendfn` is sendable,
whereas a plain `fn` is neither.
3. `fn[copy]` and `fn[send]`: an alternate version of #2 that I find
more visually appealing.
Of these, I prefer `fn[copy]` and `fn[send]`. My only reservation is
that the syntax meshes reasonably somewhat awkwardly with capture
clauses in the copy case. A capture clause is used to specify variables
you wish to copy/move out of the environment; if we moved to `fn[copy]`
and `fn[send]`, it will also specify the kind restriction. So, you
would write:
let block_1 = fn(x: T, y: U) -> V { ... }; // currently not legal
but should be, I think
let boxed_closure_1 = fn[copy](x: T, y: U) -> V { ... };
let unique_closure_1 = fn[send](x: T, y: U) -> V { ... };
and if you wanted to copy the variable `a` out of the environment
explicitly and move the variable `b`, you would write:
let boxed_closure_2 = fn[copy a; move b](x: T, y: U) -> V { ... };
let unique_closure_2 = fn[send; copy a; move b](x: T, y: U) -> V {
... };
Here you can see that the kind restriction melded with the request to
`copy a`. At the moment, explicit copies are unnecessary anyhow, but I
personally would like to make them required for mutable local variables
or for variables whose types are not implicitly copyable (per the no
copies proposal I sent out a while back).
Thoughts?
Niko
On 12/20/11 2:50 PM, Brian Anderson wrote:
----- Original Message -----
From: "Niko Matsakis"<[email protected]>
To: [email protected]
Sent: Tuesday, December 20, 2011 2:13:49 PM
Subject: [rust-dev] names needed for function types
Per recent conversations, my current plan with regard to function
types
is to pare us back to three:
- Unique closures (currently written "sendfn"), which can only close
over sendable state, which is either copied or moved into the closure;
- Shared closures (currently written "lambda" or "fn@"), which can
copy
or move arbitrary state off the stack frame and access it;
- Blocks (currently written "block"), which access state from their
creator's stack frame by reference and therefore cannot be used once
their creator returns.
This will mean 'fn' can't be used as a type, unless it means two different
things - I don't think it should both mean 'shared closure' and this non-type
thing that can be instantiated as any type of closure. It's a shame that we
have to think of a different name for the most common function type, but maybe
not a big problem since you often want to use it as a block.
The question is: what should we call the various closure types? I
think
we need both good prose names and good keywords, ideally those are the
same.
Rename 'block' to 'fn'. Reason: this is the type that most higher order
functions take; it has symmetry with your proposal for fn declarations, in that
fn declarations can be instantiated as either shared closures or unique
closures. In common practice you would write 'fn' most everywhere. Only when
you need to put a closure into a data structure or send it would you have to be
more specific about the type.
Still thinking about the other two.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev