QuantumLibraries
QuantumLibraries copied to clipboard
Consolidate Intrinsic and Canon under Microsoft.Quantum.Core
Consolidate Intrinsic and Canon under Microsoft.Quantum.Core
Conceptual overview
The Q# compiler auto-opens namespace Microsoft.Quantum.Core
, whereas iQ# (the Jupyter kernel for Q#) also auto-opens Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
. I believe the choice to open these automatically in iQ# was made before open namespaces were shared between notebook cells in iQ#, but this raises a good point:
open
ing Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
amounts to boilerplate required for almost any Q# program. Examples:
- All 32/32 of the solutions to the QuantumKatas
open Microsoft.Quantum.Intrinsic
, and 22/32 solutionsopen Microsoft.Quantum.Canon
- All of the project templates included in the VSCode extension open both these two namespaces
- Of the 115 Q# files in
samples/
in the Microsoft/Quantum repository, 109 filesopen Microsoft.Quantum.Intrinsic
, and 91open Microsoft.Quantum.Canon
Proposal
Move everything from Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
into Microsoft.Quantum.Core
.
Impact of breaking changes
Assuming the two namespaces still exist (albeit empty), programmers will not affected except for:
- Programmers who did not
open
either namespace, but defined their own e.g.H()
operation in their own namespace. If theyopen
their namespace and call theirH()
, they will get an AmbiguousCallable error- Can't find examples of this outside of qsharp-runtime
- Programmers using the fully qualified name to access something in
Microsoft.Quantum.Intrinsic
orMicrosoft.Quantum.Canon
- Can't find examples of this outside of qsharp-runtime
- Programmers opening
Microsoft.Quantum.Intrinsic
orMicrosoft.Quantum.Canon
with an alias- Can't find examples of this outside of qsharp-runtime
If my searching is failing and programmers are doing any of these 3 things, it's tough to think of a migration path. Leaving @Deprecated
stubs in Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
that call into Microsoft.Quantum.Core
may not work, since if someone open
s Microsoft.Quantum.Intrinsic
or Microsoft.Quantum.Canon
, if they call anything from either of those namespaces, then they'll get a AmbiguousCallable error between the new callable and the stub.
One idea could be allowing attributes on namespaces so we can @Deprecate
both Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
. Hopefully that could provide a more useful error message than the confusion programmers would see for (1)-(3) above, and it opens a path to eventually removing both namespaces.
Alternatives considered
An alternative is to have the compiler open Microsoft.Quantum.Intrinsic
and Microsoft.Quantum.Canon
by default. However, this is not as clean as always opening a single namespace: it seems like a slippery slope to continue adding more auto-opened namespaces to the compiler.
Thanks for opening this! To explain a bit of the thinking behind the split between Core, Intrinsic, and Canon, Core is the set of functions and operations needed to support Q# as a language at all — e.g.: Length
is required in order for the language to make sense and to be coherent.
By contrast, one can imagine writing Q# programs that use a different QIS than that represented by Microsoft.Quantum.Intrinsic. Similarly, not all devices will support the combinator logic and similar utilities collected in Microsoft.Quantum.Canon. Thus, there's a real and material sense in which Microsoft.Quantum.Core is more "fundamental" than the other two, reflected in the auto-open behavior. Collapsing all of them into one namespace may be confusing as a result.
Definitely all for reducing boilerplate, though; we maybe could look to C#'s recent efforts (Q# is not C#, obviously, but we do learn from development in a variety of languages, including Python, Rust, and C#). In particular, when using .NET 6-style projects, a reasonable set of using
statements is added by default, but that behavior can be turned off with a csproj property.
As another potential option, Rust's compact notation for opening namespaces may be helpful; e.g.: something like open Microsoft.Quantum.{Canon, Intrinsic};
.
One other option may be to use F#-style @AutoOpen
attributes. In F#, those can only be used from projects compiled as part of building the standard libraries, but it allows for decoupling auto-open decisions from the compiler implementation itself.
All by way of agreement, it would be good to reduce boilerplate — we may want to explore some other alternatives as to how to do so, though.
Rust, Haskell and other languages have a prelude, which is a module that is automatically imported in every file.
To explain a bit of the thinking behind the split between Core, Intrinsic, and Canon, Core is the set of functions and operations needed to support Q# as a language at all — e.g.: Length is required in order for the language to make sense and to be coherent.
Preludes usually re-export things defined in other modules (for example, see all the random things that std::prelude has). That's analogous to leaving things in Core, Intrinsic and Canon, but re-exporting them under either Core or a new prelude namespace.
By contrast, one can imagine writing Q# programs that use a different QIS than that represented by Microsoft.Quantum.Intrinsic. Similarly, not all devices will support the combinator logic and similar utilities collected in Microsoft.Quantum.Canon.
Preludes can be replaced. In Haskell, it's possible to turn off the default prelude and use another one that you like or more or that's more suited to a particular project. In Rust, it's common to see use foo::prelude::*;
to get access to domain-specific utilities from a library. But I think it's important that there's one prelude module, rather than three, to make it easier on users.
I'm closing this in favor of preludes since (in my opinion) Cassandra is correct above