Generalized Closure Capture #747
Replies: 0 comments 3 replies
-
Hi Matt, TL;DR;
To understand in more details, let's look at the design of Val's lambdas. The type of a lambda is expressed as
For usability, the exact description of
So as you can see, the type of the captures is exposed to the type system. Hence, you can define higher-order functions that reason about it. The original purpose of that feature was to avoid dynamic allocation. The environment of a lambda is nothing fancy, it's just a tuple. That means you can emulate
You can also use remote parts in any user-defined type, such as a slice. I already showed an example here.
I think we can write this use case as below:
You could create a different version of
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Val supports closures with the ability to capture data with
let
,inout
, andsink
captures. If I understand correctly, this in effect allows users to safely create an object that can hold a mutable reference to data from the enclosing scope. This is great, however, in practice lots of types need to capture data beyond just closures. Is this considered something that Val also aims to solve? It seems like the same exact technique can be applied to other types in the language just as easily, there just is no syntax for it at the moment.For instance, coming from a C++ background, something commonly done with tuples is to
std::tie
together existing objects, which effectively captures elements by reference (withstd::tie
it happens to be all of them captured by reference, but it is not always the case that all elements are captured in the same way). This operation is used for a variety of reasons, such as to apply existing tuple algorithms to objects that weren't initially declared to be in the same tuple. The most common situation where this occurs is when wanting to perform a lexicographical compare with another tuple (often also one with "tied" elements). An example where mutable captures are useful is with assignment operations, where a user callsstd::tie
to bring together a series of otherwise unrelated objects and set their values all at once based on the value of some other tuple with similar element types (such as if copying an element of a zipped range). IIUC, all of these cases and others could be elegantly solved in Val if it were to support capture specifiers for tuple elements in a way similar to how they are supported for closures.Perhaps more complicated to figure out syntax for, but also important for uses in library code, is the ability to have captures within user-defined types. Again, the technique used to track lifetime from the outside would still be the same as for closures, but there would need to be a way to notate the relationship between members and constructor parameters.
Finally, for all of the above situations (including just for closures), it would be useful to denote capture of a function's parameter into that function's returned object. A simple example of this would be for the implementation of a higher-order function
foo
that takes an existing closureA
as a parameter, and returns a new closure of a lesser arity by itself capturingA
and passing along a constant as one ofA
's arguments. This would require some kind of explicit notation on the declaration offoo
that describes howA
is captured into the returned object.More use-cases can be provided if necessary.
Beta Was this translation helpful? Give feedback.
All reactions