-
Notifications
You must be signed in to change notification settings - Fork 53
Qubit allocation without new block scope #14
Description
Suggestion
We propose creating an analogue of let for qubits: a statement that allocates qubits and binds them to a name for the remainder of the current scope, after which the name is no longer accessible and the qubits are released. The statement does not require a new block scope, unlike the current using and borrowing statements.
Considerations
Allocating qubits in Q# with using and borrowing statements requires creating a new block scope. The block makes the lifetime of the qubits explicit, and discourages holding on to qubits for longer than needed, but at the cost of increased block nesting and indentation. Additionally, it is very common for a using statement block to be the last statement in the enclosing scope, in which case the explicit scope did not actually help to shorten the lifetime of the allocated qubits.
The explicit block also makes it cumbersome to create more than one qubit variable at a time. If one using statement per variable is used, a new indentation level is required for each variable. More commonly, tuple destructuring is used to create more than one variable in a single assignment, but this becomes difficult to read as the number of variables increases or as the complexity of the qubit initializer expression increases.
A let-like qubit allocation statement is needed to simplify these use cases. Because using and borrowing statements are the only way to allocate qubits, there is no workaround currently in Q#. An alternative proposal that would only address the many variable case could be to allow multiple using statements in a row followed by only one scope:
using (q1 = Qubit())
using (q2 = Qubit()) {
// ... use both q1 and q2 ...
}But this still requires at least one new block scope in all cases, unlike the original suggestion.
Context
We can consider two possible naming conventions for the new statements:
- Reuse the same keywords as the block statements:
usingandborrowing. - By analogy to
let, create the new keywordsuseandborrow.
Reusing the keywords avoids a breaking change, but creates a slight inconsistency:
using q1 = Qubit();
borrowing q2 = Qubit();
letting q3 = q1; // wrong
let q3 = q1; // rightIf we use new keywords, we need to decide if we keep the original keywords for the block statements (supporting two parallel sets of keywords indefinitely), or if we rename those too:
use (q = Qubit()) {
// ...
}
borrow (q = Qubit()) {
// ...
}Examples
Example 1: Current syntax.
// One variable.
using (q = Qubit()) {
// ...
}
// Two variables with separate statements.
using (q1 = Qubit()) {
using (q2 = Qubit()) {
// ...
}
}
// Two variables with tuple destructuring.
using ((q1, q2) = (Qubit(), Qubit())) {
// ...
}Example 2: Proposed syntax with new keywords.
// One variable.
use q = Qubit();
// ...
// Two variables with separate statements.
use q1 = Qubit();
use q2 = Qubit();
// ...
// Two variables with tuple destructuring.
use (q1, q2) = (Qubit(), Qubit());
// ...Affidavit (please fill out)
Please add ticks by placing a cross in the box:
- I have searched both open and closed suggestions and proposals on this site and believe this is not a duplicate.
- I believe that the spirit of this suggestion is aligned with the design principles and general vision for Q#.
Please tick all that apply:
- This is not a breaking change to the Q# language design
- I or my organization would be willing to help implement and/or test this