Open Strilanc opened 3 years ago
Hi, thanks for the suggestion! Could you clarify the relationship between this suggestion and #40 or #14? Specifically, would syntax like this work for you, or is the within
block needed for another purpose?
use a = LittleEndian(Qubit[10]);
use b = LittleEndian(Qubit[10]);
use c = LittleEndian(Qubit[10]);
// ... code using a, b, c ...
The inline use
statements are from #14, and some form of UDT-wrapping-at-allocation will be possible with #40, although the syntax isn't final yet.
Yes that would work. I'm saying that in the context of a within
block the use
is technically not necessary, because the scoping is automatic.
Will I also be able to write expressions like use padded_array = existing_array + Qubit[10]
?
I haven't heard of plans to support that. It looks like it could be useful, but it may be confusing that some qubits in padded_array
are released when padded_array
goes out of scope, while other qubits (the ones in existing_array
) are not. @bettinaheim, since you're working on qubit initializers, what do you think?
I was hoping to give a more concrete reply with a suggested syntax, but since progress is a bit slower than I was hoping, let me reply regardless. @Strilanc I am assuming the +
in your expression above is a concatenation, such that the entire statement is an array allocation followed by an array concatenation and assignment to padded_array.
In that case, we are really only talking about one line of code that is saved here, so out of pure curiosity: Is that a big pain point e.g. because it is a very common pattern for you?
Supporting something like this could naturally be covered as part of the initializer generalization I am working on. It hadn't occurred to me that there is a use case for supporting elevating functions to be initializers, but this example here is one. I need a bit more time to come up with a concrete suggestion for how exactly I think the concrete syntax could look like, and I appreciate any input on it.
Supporting something like this could naturally be covered as part of the initializer generalization I am working on
I'm unclear why it would interact with initializers. My intention is that this line of code:
let a = existing_array + [Qubit()]
Should be exactly identical to these two lines:
use __compiler_temporary_1 = Qubit()
let a = existing_array + [__compiler_temporary_1]
There's a convention built into the language that initializers like Qubit()
can only be called from within a using
or borrowing
statement. This is to make it clear that when the variable declared by using
or borrowing
goes out of scope, the qubits allocated in the variable are released.
It would be possible to lift this restriction, but I'm not sure if we should. For example, in
let a = existing_array + [Qubit()];
the qubit allocated by Qubit()
is still released when a
goes out of scope, but this is easier to miss than if it was declared with
use a = existing + [Qubit()];
since now it's explicit that code for releasing qubits is automatically triggered when a
goes out of scope. That leads to wanting to allow +
to be used with a use
statement, which would mean qubit initializers would need to support classical functions and operators.
I don't think it should be associated with a, since some of the other qubits should last longer. Maybe what I'm asking for is a "use expression":
let a = other + [use Qubit()]
I don't think it should be associated with a, since some of the other qubits should last longer.
I agree, I think this is a good reason not to allow that construct. use
expressions were also considered recently in #33. Here's a (rather long) discussion about them: https://github.com/microsoft/qsharp-language/pull/33#discussion_r496271018
I think the main point from that discussion is that attaching use
to the Qubit()
instead of the variable name sort of obscures the lifetime of the qubit. Which scope is it bound to? In let a = other + [use Qubit()]
, it's bound to a
(or to a temporary variable that has the same scope as a
), but what about a call expression like MyOperation(use Qubit())
. Is the lifetime bound to the scope where MyOperation
is called from, or is it bound to the parameter of MyOperation
? It seems like it is less intuitive to me than an explicit use q = Qubit();
statement.
Currently, when you want to allocate several registers, it is quite cumbersome. You get a lot of indentation, you have to assign temporary names to the raw register before wrapping it into the type you actually want, etc.
One way to work around this issue would be if
within
blocks allowed arbitrary allocation expressions. That way there's no need for the temporary unwrapped names, and much less increase in indentation.This feels like a natural thing to just allow inside the
within
block.Examples
Affidavit (please fill out)
Please add ticks by placing a cross in the box:
Please tick all that apply: