From 45aaa73aa8f2ac7cf559004fe552914503d1a12a Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 28 Oct 2020 11:04:18 -0700 Subject: [PATCH 01/22] Remove default-initialized new array expressions --- Approved/remove-new-array.md | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 Approved/remove-new-array.md diff --git a/Approved/remove-new-array.md b/Approved/remove-new-array.md new file mode 100644 index 0000000..fb6179f --- /dev/null +++ b/Approved/remove-new-array.md @@ -0,0 +1,84 @@ +--- +title: Remove default-initialized new array expressions +description: The `new Type[N]` array expression is deprecated and removed from Q#. +author: Sarah Marshall +date: October 28, 2020 +--- + +# Proposal + +The `new Type[N]` expression, which creates an array of `N` values using the default value of `Type`, is deprecated and removed from Q#. + +# Justification + +The existence of `new Type[N]` has negative effects on the language. + +The most important negative effect is the assumption that every type has a default value. +This is not a reasonable assumption, because it is not possible to define useful default values of types like `Qubit` and `a -> b`. +Their current default values are invalid and will trigger an error if they are used. +But the syntax is the same both for types with valid default values, and those without, which is misleading: while `new Int[3]` is a perfectly well-defined value whose elements can be used immediately, `new Qubit[3]` creates a potential trap that will crash the program if any value in the array is used. + +This assumption is also invalid in the presence of uninhabited types such as `Void`. +If Q# requires that every type has a default value, then uninhabited types are not possible to express properly. +This can even cause subtle bugs in the soundness of a type system, as demonstrated by [this bug in Java's generics](https://hackernoon.com/java-is-unsound-28c84cb2b3f) that happened because of the existence of a value (specifically `null`) for a type that should have been uninhabited. + +Finally, the use of the `new` keyword is inconsistent with other ways to create values in Q#. +`new` is required only when creating a default-initialized array, not when using a square bracket array literal or when creating values of other types. + +# Description + +## Current Status + +Q# currently supports this syntax: + +```qsharp +// Create an empty array of type Int[]. +let empty = new Int[0]; + +// Create an array of length 10 of type Bool[] where every value is false. +let bools = new Bool[10]; +``` + +## Proposed Modification + +The syntax above will be removed. +The same functionality can be accomplished with functions in the standard library: + +```qsharp +// Create an empty arra of type Int[]. +let empty = EmptyArray(); + +// Create an array of length 10 of type Bool[] where every value is false. +let bools = ConstantArray(10, false); +``` + +# Implementation + +The library functions `EmptyArray` and `ConstantArray` are already implemented. +The `new Type[N]` syntax can be deprecated and removed with the next major version of Q#. + +## Timeline + +N/A + +# Further Considerations + +## Related Mechanisms + +N/A + +## Impact on Existing Mechanisms + +N/A + +## Anticipated Interactions with Future Modifications + +Improved type inference will allow the empty array to be expressed as `[]` instead of `EmptyArray()`. + +## Alternatives + +N/A + +# Raised Concerns + +N/A From 619f72243aa569f0ef3ef8a7173dc12ed443d51a Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 28 Oct 2020 11:25:18 -0700 Subject: [PATCH 02/22] Change wording --- Approved/remove-new-array.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Approved/remove-new-array.md b/Approved/remove-new-array.md index fb6179f..344697c 100644 --- a/Approved/remove-new-array.md +++ b/Approved/remove-new-array.md @@ -16,7 +16,7 @@ The existence of `new Type[N]` has negative effects on the language. The most important negative effect is the assumption that every type has a default value. This is not a reasonable assumption, because it is not possible to define useful default values of types like `Qubit` and `a -> b`. Their current default values are invalid and will trigger an error if they are used. -But the syntax is the same both for types with valid default values, and those without, which is misleading: while `new Int[3]` is a perfectly well-defined value whose elements can be used immediately, `new Qubit[3]` creates a potential trap that will crash the program if any value in the array is used. +But the syntax is the same both for types with valid default values, and those without, which is misleading: while `new Int[3]` is a well-defined value whose items can be used safely, `new Qubit[3]` creates a potential trap that will crash the program if any item in the array is used before being set to a valid value first. This assumption is also invalid in the presence of uninhabited types such as `Void`. If Q# requires that every type has a default value, then uninhabited types are not possible to express properly. From aa3c1a13898808926df501e13118d3188f23fbd1 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 3 Nov 2020 09:19:16 -0800 Subject: [PATCH 03/22] More specific intro section --- Approved/remove-new-array.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Approved/remove-new-array.md b/Approved/remove-new-array.md index 344697c..c6c74a9 100644 --- a/Approved/remove-new-array.md +++ b/Approved/remove-new-array.md @@ -2,12 +2,14 @@ title: Remove default-initialized new array expressions description: The `new Type[N]` array expression is deprecated and removed from Q#. author: Sarah Marshall -date: October 28, 2020 +date: November 3, 2020 --- # Proposal -The `new Type[N]` expression, which creates an array of `N` values using the default value of `Type`, is deprecated and removed from Q#. +The `new Type[N]` expression, which creates an array of `N` values using the default value of `Type`, will be deprecated and removed from Q#. +With the exception of the empty array, creating an array requires that the value of each item is given explicitly by the user; arrays are no longer initialized implicitly using default values. +With the removal of `new Type[N]`, the concept of each type having a default value will also be removed from Q#. # Justification From ea41dc754146950bcf0d8d315d7b6490b592f567 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 3 Nov 2020 09:31:54 -0800 Subject: [PATCH 04/22] More implementation details --- Approved/remove-new-array.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Approved/remove-new-array.md b/Approved/remove-new-array.md index c6c74a9..997bfe9 100644 --- a/Approved/remove-new-array.md +++ b/Approved/remove-new-array.md @@ -56,9 +56,14 @@ let bools = ConstantArray(10, false); # Implementation -The library functions `EmptyArray` and `ConstantArray` are already implemented. The `new Type[N]` syntax can be deprecated and removed with the next major version of Q#. +The library functions `EmptyArray` and `ConstantArray` are already present in the `Microsoft.Quantum.Arrays` namespace of the standard library. +Since the only built-in way to create an empty array was `new Type[0]`, `EmptyArray` must be intrinsic; however, this is already the case, so no additional work is needed. + +While `ConstantArray` can be written in pure Q# using array concatenation, this is not the most efficient implementation. +`ConstantArray` should be converted into an intrinsic function that allocates the whole array before initializing the items with the given value. + ## Timeline N/A From 2d147fd082d245124a93f74cf48437aca6dded06 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 3 Nov 2020 10:57:59 -0800 Subject: [PATCH 05/22] ConstantArray should have pure Q# fallback --- Approved/remove-new-array.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Approved/remove-new-array.md b/Approved/remove-new-array.md index 997bfe9..59af7c9 100644 --- a/Approved/remove-new-array.md +++ b/Approved/remove-new-array.md @@ -62,7 +62,8 @@ The library functions `EmptyArray` and `ConstantArray` are already present in th Since the only built-in way to create an empty array was `new Type[0]`, `EmptyArray` must be intrinsic; however, this is already the case, so no additional work is needed. While `ConstantArray` can be written in pure Q# using array concatenation, this is not the most efficient implementation. -`ConstantArray` should be converted into an intrinsic function that allocates the whole array before initializing the items with the given value. +A native implementation of `ConstantArray` should be added that allocates the whole array before initializing the items with the given value. +The pure Q# implementation should remain as a fallback in case the native implementation is not available. ## Timeline From 8de9ea754f03e5742aa9f8bad5c4a919f569634a Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 14 Dec 2020 17:37:58 -0800 Subject: [PATCH 06/22] Update with new syntax --- Approved/enhanced-array-literals.md | 149 ++++++++++++++++++++++++++++ Approved/remove-new-array.md | 92 ----------------- 2 files changed, 149 insertions(+), 92 deletions(-) create mode 100644 Approved/enhanced-array-literals.md delete mode 100644 Approved/remove-new-array.md diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md new file mode 100644 index 0000000..4d66596 --- /dev/null +++ b/Approved/enhanced-array-literals.md @@ -0,0 +1,149 @@ +--- +title: Enhanced array literals and removal of default-initialized array constructors +description: Array literals are enhanced to support empty and repeated constant arrays, and the default-initialized array constructor `new Type[n]` is removed. +author: Sarah Marshall +date: December 14, 2020 +--- + +# Proposal + +* The empty array literal, `[]`, is supported. +* The repeated constant array literal, `[x, size = n]`, is added. +* The default-initialized `new Type[n]` array constructor is deprecated and will be removed in the next major version of Q#. + With it, the concept that every type has a default value is also deprecated and removed. + +# Justification + +## Removing default-initialized array constructors + +The `new Type[n]` array constructor has two issues: + +1. The `new` keyword is not used anywhere else in Q#. + Its use with default-initialized arrays is inconsistent with other type constructors. +2. It requires every type to have a default value with which to initialize each item in the array. + +### Default values + +It is not possible to define reasonable default values of types like `Qubit` and `a -> b`. +Their current default values are invalid and will trigger an error if they are used. +But the syntax is the same both for types with valid default values, and those without: while `new Int[3]` is a well-defined value whose items can be used safely, `new Qubit[3]` creates a trap that will crash the program if any item in the array is used before being set to a valid value first. + +This assumption is also invalid for uninhabited types such as `Void`. +If Q# requires that every type has a default value, then uninhabited types are not possible to express properly. +This can even cause subtle bugs in the soundness of a type system, as demonstrated by [this bug in Java's generics](https://hackernoon.com/java-is-unsound-28c84cb2b3f) that happened because of the existence of a value (specifically `null`) for a type that should have been uninhabited. + +## Enhancing array literals + +With the removal of default-initialized array constructors, alternatives are needed to create empty arrays and arrays with a repeated initial value. +The alternative for `new T[0]` is `[]`. +The alternative for `new T[n]` where `n > 0` is `[x, size = n]`, where `x` is the initial value of each item. + +# Description + +## Current Status + +Q# currently supports this syntax: + +```qsharp +// Create an empty array of type Int[]. +let empty = new Int[0]; + +// Create an array of length 10 of type Bool[] where every value is false. +let bools = new Bool[10]; +``` + +## Proposed Modification + +The syntax above will be deprecated and removed. +The replacement for each case is different. + +### Empty arrays + +The empty array literal, `[]`, will be supported. +Unlike `new T[0]`, this literal does not specify the type of the array to be created. +Its type will be inferred based on its first usage. + +```qsharp +function SumI(xs : Int[]) : Int { + return Fold(PlusI, 0, xs); +} + +function SumD(xs : Double[]) : Int { + return Fold(PlusD, 0.0, xs); +} + +function Example() : Unit { + // The type of [] is inferred to be Int[] based on its position as the argument to SumI. + let x = SumI([]); + + // The type of empty1 is inferred to be Int[] based on its position as the argument to SumI. + let empty1 = []; + let y = SumI(empty1); + + // The following line contains a compilation error, because empty1 is of type Int[], not Double[]. + let z = SumD(empty1); + + // Since empty2 is not used, its type cannot be inferred. + // This is a compilation error. + let empty2 = []; + + // While empty3 is used, its usage does not provide any information about its concrete type. + // This is a compilation error. + let empty3 = []; + Message($"Empty array: {empty3}"); + + // In cases where the type of [] cannot be inferred, Microsoft.Quantum.Arrays.EmptyArray can be used instead. + // The following code is valid. + let empty4 = EmptyArray(); + Message($"Empty array: {empty4}"); +} +``` + +### Repeated constant arrays + +The semantics of `[x, size = n]` are identical to `new T[n]`, except that the initial value is now given by `x`: + +1. `n` may be an integer literal or a variable of integer type. +2. If `n` is negative, a runtime error occurs. + +```qsharp +// Create an array of length 10 of type Bool[] where every value is false. +let bools = [false, size = 10]; +``` + +# Implementation + +The implementation of `[x, size = n]` should be a relatively straightforward extension of the current implementation for `new T[n]`. +It will require parser and syntax tree changes, as well as changes to code generation and potentially a small amount of runtime support. + +The implementation for `[]` will require enhancements to type inference. +One possible approach is to create a placeholder type variable for each usage of `[]`. +When an expression with a placeholder type variable is used in a context that requires a specific type, this context can refine the placeholder type. +Once all placeholders are refined, they can be replaced with their concrete types if one was determined. +Since all specialization signatures must have explicit parameter and return types, the type inference for a placeholder variable cannot extend beyond its containing specialization. + +## Timeline + +N/A + +# Further Considerations + +## Related Mechanisms + +N/A + +## Impact on Existing Mechanisms + +N/A + +## Anticipated Interactions with Future Modifications + +N/A + +## Alternatives + +N/A + +# Raised Concerns + +N/A diff --git a/Approved/remove-new-array.md b/Approved/remove-new-array.md deleted file mode 100644 index 59af7c9..0000000 --- a/Approved/remove-new-array.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Remove default-initialized new array expressions -description: The `new Type[N]` array expression is deprecated and removed from Q#. -author: Sarah Marshall -date: November 3, 2020 ---- - -# Proposal - -The `new Type[N]` expression, which creates an array of `N` values using the default value of `Type`, will be deprecated and removed from Q#. -With the exception of the empty array, creating an array requires that the value of each item is given explicitly by the user; arrays are no longer initialized implicitly using default values. -With the removal of `new Type[N]`, the concept of each type having a default value will also be removed from Q#. - -# Justification - -The existence of `new Type[N]` has negative effects on the language. - -The most important negative effect is the assumption that every type has a default value. -This is not a reasonable assumption, because it is not possible to define useful default values of types like `Qubit` and `a -> b`. -Their current default values are invalid and will trigger an error if they are used. -But the syntax is the same both for types with valid default values, and those without, which is misleading: while `new Int[3]` is a well-defined value whose items can be used safely, `new Qubit[3]` creates a potential trap that will crash the program if any item in the array is used before being set to a valid value first. - -This assumption is also invalid in the presence of uninhabited types such as `Void`. -If Q# requires that every type has a default value, then uninhabited types are not possible to express properly. -This can even cause subtle bugs in the soundness of a type system, as demonstrated by [this bug in Java's generics](https://hackernoon.com/java-is-unsound-28c84cb2b3f) that happened because of the existence of a value (specifically `null`) for a type that should have been uninhabited. - -Finally, the use of the `new` keyword is inconsistent with other ways to create values in Q#. -`new` is required only when creating a default-initialized array, not when using a square bracket array literal or when creating values of other types. - -# Description - -## Current Status - -Q# currently supports this syntax: - -```qsharp -// Create an empty array of type Int[]. -let empty = new Int[0]; - -// Create an array of length 10 of type Bool[] where every value is false. -let bools = new Bool[10]; -``` - -## Proposed Modification - -The syntax above will be removed. -The same functionality can be accomplished with functions in the standard library: - -```qsharp -// Create an empty arra of type Int[]. -let empty = EmptyArray(); - -// Create an array of length 10 of type Bool[] where every value is false. -let bools = ConstantArray(10, false); -``` - -# Implementation - -The `new Type[N]` syntax can be deprecated and removed with the next major version of Q#. - -The library functions `EmptyArray` and `ConstantArray` are already present in the `Microsoft.Quantum.Arrays` namespace of the standard library. -Since the only built-in way to create an empty array was `new Type[0]`, `EmptyArray` must be intrinsic; however, this is already the case, so no additional work is needed. - -While `ConstantArray` can be written in pure Q# using array concatenation, this is not the most efficient implementation. -A native implementation of `ConstantArray` should be added that allocates the whole array before initializing the items with the given value. -The pure Q# implementation should remain as a fallback in case the native implementation is not available. - -## Timeline - -N/A - -# Further Considerations - -## Related Mechanisms - -N/A - -## Impact on Existing Mechanisms - -N/A - -## Anticipated Interactions with Future Modifications - -Improved type inference will allow the empty array to be expressed as `[]` instead of `EmptyArray()`. - -## Alternatives - -N/A - -# Raised Concerns - -N/A From fd9cc66b422f213d69eb09f301b5b94f7c70a03c Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 14 Dec 2020 17:49:27 -0800 Subject: [PATCH 07/22] Add examples of syntax errors for repeat arrays --- Approved/enhanced-array-literals.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 4d66596..fd46b7b 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -109,6 +109,11 @@ The semantics of `[x, size = n]` are identical to `new T[n]`, except that the in ```qsharp // Create an array of length 10 of type Bool[] where every value is false. let bools = [false, size = 10]; + +// The following examples are syntax errors: +let wrong1 = [size = 10, false]; +let wrong2 = [false, true, size = 10]; +let wrong3 = [false, size = 10, true]; ``` # Implementation From 781f4f6c012b86fbfde5e86fd6b71173f6fc569e Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 14 Dec 2020 18:04:00 -0800 Subject: [PATCH 08/22] Remaining sections are TODO --- Approved/enhanced-array-literals.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index fd46b7b..3358e3a 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -129,26 +129,26 @@ Since all specialization signatures must have explicit parameter and return type ## Timeline -N/A +TODO # Further Considerations ## Related Mechanisms -N/A +TODO ## Impact on Existing Mechanisms -N/A +TODO ## Anticipated Interactions with Future Modifications -N/A +TODO ## Alternatives -N/A +TODO # Raised Concerns -N/A +TODO From 33f32c29da09eb7d39d12ab8e03bc16c6d1fe6dd Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 15 Dec 2020 15:09:19 -0800 Subject: [PATCH 09/22] Fill in more sections --- Approved/enhanced-array-literals.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 3358e3a..b338ae1 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -10,7 +10,7 @@ date: December 14, 2020 * The empty array literal, `[]`, is supported. * The repeated constant array literal, `[x, size = n]`, is added. * The default-initialized `new Type[n]` array constructor is deprecated and will be removed in the next major version of Q#. - With it, the concept that every type has a default value is also deprecated and removed. + With it, the concept that every type has a default value is also deprecated and will be removed. # Justification @@ -129,17 +129,26 @@ Since all specialization signatures must have explicit parameter and return type ## Timeline -TODO +The bulk of the work is expected to be in implementing type inference for the empty array literal. +However, since it is limited to only the empty array literal, and bounded by the scope of a specialization, the complexity should be managable within a month or two of work. +The remaining work of adding repeated constant array literals and deprecating the old array literals should not take much time. # Further Considerations ## Related Mechanisms -TODO +The syntax for allocating arrays of qubits is similar to the existing default-initialized array constructor syntax: + +```qsharp +use qs = Qubit[n]; +``` + +For consistency, it may make sense to change this syntax as well. +The [proposal for allocatable types and generalization of initializers](https://github.com/microsoft/qsharp-language/pull/41) is addressing this. ## Impact on Existing Mechanisms -TODO +The [`Default`](https://docs.microsoft.com/en-us/qsharp/api/qsharp/microsoft.quantum.core.default) function depends on default-initialized array constructors, and it will also be deprecated. ## Anticipated Interactions with Future Modifications From d6c1d99a3fa62e1760f6c27e93812e0d92718eb2 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 15 Dec 2020 15:36:07 -0800 Subject: [PATCH 10/22] Fill in future modifications section --- Approved/enhanced-array-literals.md | 35 ++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index b338ae1..1226cb0 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -2,7 +2,7 @@ title: Enhanced array literals and removal of default-initialized array constructors description: Array literals are enhanced to support empty and repeated constant arrays, and the default-initialized array constructor `new Type[n]` is removed. author: Sarah Marshall -date: December 14, 2020 +date: December 15, 2020 --- # Proposal @@ -152,7 +152,36 @@ The [`Default`](https://docs.microsoft.com/en-us/qsharp/api/qsharp/microsoft.qua ## Anticipated Interactions with Future Modifications -TODO +### Named arguments + +The syntax for repeated constant arrays is designed to be similar to the syntax for named arguments, a feature that Q# does not currently support (and for which there is currently no suggestion or proposal). +This proposal makes the assumption that the syntax for named arguments, if Q# supports them, will be: + +```qsharp +Foo(firstArgument, secondArgument, namedArgument = "foo"); +``` + +### Type inference + +In the future, the type inference used for empty array literals may be extended to all expressions, allowing calls to polymorphic functions where not all type variables are determined by their arguments. + +### Partial application + +We may want to consider supporting partial application for array literals in the future: + +```qsharp +let f = ["foo", size = _]; +// f : Int -> String[] +// f(3) == ["foo", "foo", "foo"] + +let g = [_, size = 3]; +// g : 'a -> 'a[] +// g("foo") == ["foo", "foo", "foo"] + +let h = [_, "middle", _]; +// h : (String, String) -> String[] +// h("first", "last") == ["first", "middle", "last"] +``` ## Alternatives @@ -160,4 +189,4 @@ TODO # Raised Concerns -TODO +N/A From 1c694a135998602635c1c0ca07055dc2103e2e47 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 15 Dec 2020 15:52:37 -0800 Subject: [PATCH 11/22] Fill in alternatives section --- Approved/enhanced-array-literals.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 1226cb0..03e17fb 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -185,7 +185,22 @@ let h = [_, "middle", _]; ## Alternatives -TODO +Both empty arrays and repeated constant arrays can be created using functions in the Q# standard library, using the `EmptyArray` and `ConstantArray` functions. +After deprecating the existing default-initialized array constructor syntax, this proposal could have made these functions the primary way to create these kinds of arrays instead of introducing new syntax. + +For empty arrays, the syntax `[]` comes naturally as the zero-length case of general array literals, and is very common in other languages. +It is much more convenient to use than `EmptyArray()`. + +For repeated constant arrays, the syntax `[x, size = n]` is not as obvious. +Many languages use a function to provide this functionality instead of built-in syntax. +However, we were not able to come to a consensus on how the `ConstantArray` function should be made available. +There are unresolved questions, such as: + +1. Should `ConstantArray` be added to `Microsoft.Quantum.Core` so that it can be used without an open directive? +2. Should `ConstantArray` be part of a more general `Array` module that is in `Microsoft.Quantum.Core`, so that it can be used like `Array.Constant`? +3. Should modules be a language feature in Q# or are open-as directives enough to emulate them? + +We defer answering these questions for now, instead adding new syntax for this case. # Raised Concerns From a466ce68e2195386a983fc022b1dd00fdd51b521 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 15 Dec 2020 15:59:15 -0800 Subject: [PATCH 12/22] Minor edits --- Approved/enhanced-array-literals.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 03e17fb..b9d6037 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -32,6 +32,8 @@ This assumption is also invalid for uninhabited types such as `Void`. If Q# requires that every type has a default value, then uninhabited types are not possible to express properly. This can even cause subtle bugs in the soundness of a type system, as demonstrated by [this bug in Java's generics](https://hackernoon.com/java-is-unsound-28c84cb2b3f) that happened because of the existence of a value (specifically `null`) for a type that should have been uninhabited. +Removing default-initialized array constructors, and the requirement that every type has a default value, resolves these problems. + ## Enhancing array literals With the removal of default-initialized array constructors, alternatives are needed to create empty arrays and arrays with a repeated initial value. @@ -189,7 +191,7 @@ Both empty arrays and repeated constant arrays can be created using functions in After deprecating the existing default-initialized array constructor syntax, this proposal could have made these functions the primary way to create these kinds of arrays instead of introducing new syntax. For empty arrays, the syntax `[]` comes naturally as the zero-length case of general array literals, and is very common in other languages. -It is much more convenient to use than `EmptyArray()`. +It is much more convenient to use than `EmptyArray()`. For repeated constant arrays, the syntax `[x, size = n]` is not as obvious. Many languages use a function to provide this functionality instead of built-in syntax. From d998e2744f7d68b6702272361dbc51030dec2cd5 Mon Sep 17 00:00:00 2001 From: Sarah Marshall <33814365+samarsha@users.noreply.github.com> Date: Tue, 15 Dec 2020 18:11:36 -0800 Subject: [PATCH 13/22] n is an integer expression Co-authored-by: bettinaheim <34236215+bettinaheim@users.noreply.github.com> --- Approved/enhanced-array-literals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index b9d6037..94e4111 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -105,7 +105,7 @@ function Example() : Unit { The semantics of `[x, size = n]` are identical to `new T[n]`, except that the initial value is now given by `x`: -1. `n` may be an integer literal or a variable of integer type. +1. `n` is an expression of type `Int`. 2. If `n` is negative, a runtime error occurs. ```qsharp From 858616be1773414618376c4f564b7fadc5e4aa40 Mon Sep 17 00:00:00 2001 From: Sarah Marshall <33814365+samarsha@users.noreply.github.com> Date: Wed, 16 Dec 2020 14:30:17 -0800 Subject: [PATCH 14/22] Apply suggestions from code review Co-authored-by: bettinaheim <34236215+bettinaheim@users.noreply.github.com> --- Approved/enhanced-array-literals.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 94e4111..0326319 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -28,7 +28,7 @@ It is not possible to define reasonable default values of types like `Qubit` and Their current default values are invalid and will trigger an error if they are used. But the syntax is the same both for types with valid default values, and those without: while `new Int[3]` is a well-defined value whose items can be used safely, `new Qubit[3]` creates a trap that will crash the program if any item in the array is used before being set to a valid value first. -This assumption is also invalid for uninhabited types such as `Void`. +This assumption is also invalid for uninhabited types such as `Void` in other languages. If Q# requires that every type has a default value, then uninhabited types are not possible to express properly. This can even cause subtle bugs in the soundness of a type system, as demonstrated by [this bug in Java's generics](https://hackernoon.com/java-is-unsound-28c84cb2b3f) that happened because of the existence of a value (specifically `null`) for a type that should have been uninhabited. @@ -57,7 +57,7 @@ let bools = new Bool[10]; ## Proposed Modification The syntax above will be deprecated and removed. -The replacement for each case is different. +It is replaced by the constructs described below. ### Empty arrays From c1fad344d0ef048102aca2c35ad51ceafa20acdb Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 16 Dec 2020 14:44:49 -0800 Subject: [PATCH 15/22] More edits based on suggestions --- Approved/enhanced-array-literals.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 0326319..d3968dc 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -2,7 +2,7 @@ title: Enhanced array literals and removal of default-initialized array constructors description: Array literals are enhanced to support empty and repeated constant arrays, and the default-initialized array constructor `new Type[n]` is removed. author: Sarah Marshall -date: December 15, 2020 +date: December 16, 2020 --- # Proposal @@ -37,8 +37,8 @@ Removing default-initialized array constructors, and the requirement that every ## Enhancing array literals With the removal of default-initialized array constructors, alternatives are needed to create empty arrays and arrays with a repeated initial value. -The alternative for `new T[0]` is `[]`. -The alternative for `new T[n]` where `n > 0` is `[x, size = n]`, where `x` is the initial value of each item. +The alternative for `new T[n]` is `[x, size = n]`, where `x` is the initial value of each item. +In the case where `n` = 0, the alternative for `new T[0]` is `[]`. # Description @@ -82,7 +82,8 @@ function Example() : Unit { let empty1 = []; let y = SumI(empty1); - // The following line contains a compilation error, because empty1 is of type Int[], not Double[]. + // The following line contains a compilation error, because empty1 is of type Int[], not + // Double[]. let z = SumD(empty1); // Since empty2 is not used, its type cannot be inferred. @@ -94,10 +95,12 @@ function Example() : Unit { let empty3 = []; Message($"Empty array: {empty3}"); - // In cases where the type of [] cannot be inferred, Microsoft.Quantum.Arrays.EmptyArray can be used instead. + // In cases where the type of [] cannot be inferred, either [x, size = 0] or + // Microsoft.Quantum.Arrays.EmptyArray can be used instead. // The following code is valid. - let empty4 = EmptyArray(); - Message($"Empty array: {empty4}"); + let empty4 = [0, size = 0]; + let empty5 = EmptyArray(); + Message($"Empty Int arrays: {empty4}, {empty5}"); } ``` From 0786c156e763329b802bf9ace8a84124e1de924c Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 16 Dec 2020 16:50:11 -0800 Subject: [PATCH 16/22] Add sections for n-d arrays and array comprehensions --- Approved/enhanced-array-literals.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index d3968dc..af5cd03 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -188,6 +188,35 @@ let h = [_, "middle", _]; // h("first", "last") == ["first", "middle", "last"] ``` +### Multidimensional arrays + +The array literals in this proposal can be extended to support multidimensional arrays. +See the [𝑛-d array proposal](https://github.com/microsoft/qsharp-language/pull/49). + +Empty multidimensional arrays can be created with `#[]` for 2D, `##[]` for 3D, etc. +(Note: this syntax is still subject to change.) + +Both multidimensional and nested (jagged) arrays could be created with the repeated constant array literal syntax. +For example, `#[0, size = (2, 2)]` could create a 2x2 multidensional array, while `[0, size = (2, 2)]` could create a 2x2 nested array. +This is why the more general term `size` is used here instead of `length`. + +### Array comprehensions + +Another possible enhancement to array literals is support for array comprehensions. +This would complement repeated constant array literals, and could be used in conjunction with them. +For example: + +```qsharp +// An array containing the first 10 squares. +[x * x for x in 1 .. 10] + +// An array containing arrays of the first 10 squares. +[[x * x for x in 1 .. 10], size = 3] + +// A 3x10 multidensional array with the first 10 squares along one dimension. +#[[x * x for x in 1 .. 10], size = 3] +``` + ## Alternatives Both empty arrays and repeated constant arrays can be created using functions in the Q# standard library, using the `EmptyArray` and `ConstantArray` functions. From 6d919d41512229f7719c7ca7cfb386bb842e4ca0 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 16 Dec 2020 17:01:12 -0800 Subject: [PATCH 17/22] Update alternatives section --- Approved/enhanced-array-literals.md | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index af5cd03..c2a01a0 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -219,22 +219,9 @@ For example: ## Alternatives -Both empty arrays and repeated constant arrays can be created using functions in the Q# standard library, using the `EmptyArray` and `ConstantArray` functions. -After deprecating the existing default-initialized array constructor syntax, this proposal could have made these functions the primary way to create these kinds of arrays instead of introducing new syntax. - -For empty arrays, the syntax `[]` comes naturally as the zero-length case of general array literals, and is very common in other languages. -It is much more convenient to use than `EmptyArray()`. - -For repeated constant arrays, the syntax `[x, size = n]` is not as obvious. -Many languages use a function to provide this functionality instead of built-in syntax. -However, we were not able to come to a consensus on how the `ConstantArray` function should be made available. -There are unresolved questions, such as: - -1. Should `ConstantArray` be added to `Microsoft.Quantum.Core` so that it can be used without an open directive? -2. Should `ConstantArray` be part of a more general `Array` module that is in `Microsoft.Quantum.Core`, so that it can be used like `Array.Constant`? -3. Should modules be a language feature in Q# or are open-as directives enough to emulate them? - -We defer answering these questions for now, instead adding new syntax for this case. +The new syntax for empty arrays and repeated constant arrays is not strictly necessary. +The standard library functions `EmptyArray` and `ConstantArray` provide this functionality already. +However, the new syntax is more concise. # Raised Concerns From b4e8ee0f5f995ca41e4dfaac7e3a30e53874ce57 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Wed, 16 Dec 2020 17:36:38 -0800 Subject: [PATCH 18/22] Add raised concerns --- Approved/enhanced-array-literals.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index c2a01a0..4aee405 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -225,4 +225,27 @@ However, the new syntax is more concise. # Raised Concerns -N/A +The new syntax for repeated constant arrays adds additional complexity to the language, but with only a relatively small benefit to conciseness compared to the standard function syntax `ConstantArray(n, x)`. + +The anticipated extensions to this syntax to support multidimensional arrays and partial application will likely pose additional challenges for Q#'s type system that could be avoided if a traditional function was used instead. +For example, the planned re-use of `size = n` for arrays of any dimensionality is a kind of quasi-overloading that can't be expresed in the type system. +`[0, size = 2]` is an expression of type `Int[]`, but `[0, size = (2, 2)]` is an expression of type `Int[][]`. +With this overloading, partial application of the `size` parameter is problematic: + +```qsharp +let f = [0, size = _]; +``` + +`f` cannot be typed without additional information, such as: + +```qsharp +let g = [0, size = _]; +let xs = g(2, 3); +``` + +`g` can be inferred to be of type `(Int, Int) -> Int[][]`. +But the implementation of this kind of type inference will likely be complicated. +The compiler needs to encode the fact that `g` is of any type that fits `Int n-tuple -> n-nested Int array`, where the arity of the argument tuple equals the nesting of the returned array. +Since this type is impossible to express in Q#'s type system, special handling will need to be added to the type inference algorithm. + +These problems would be avoided, however, if traditional function calls were used instead, such as nested calls to `ConstantArray` for nested arrays, or defining separate `ConstantArray2`, `ConstantArray3`, etc. functions for multidimensional arrays. From 25c2fd349d482be8ded7d12128f5a6e0e4a6f2fe Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 21 Dec 2020 16:04:59 -0800 Subject: [PATCH 19/22] Update raised concerns --- Approved/enhanced-array-literals.md | 31 +++++++---------------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 4aee405..5a169b2 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -197,7 +197,7 @@ Empty multidimensional arrays can be created with `#[]` for 2D, `##[]` for 3D, e (Note: this syntax is still subject to change.) Both multidimensional and nested (jagged) arrays could be created with the repeated constant array literal syntax. -For example, `#[0, size = (2, 2)]` could create a 2x2 multidensional array, while `[0, size = (2, 2)]` could create a 2x2 nested array. +For example, `#[0, size = (2, 2)]` could create a 2x2 multidensional array, while `[[0, size = 2], size = 2]` could create a 2x2 nested array. This is why the more general term `size` is used here instead of `length`. ### Array comprehensions @@ -225,27 +225,10 @@ However, the new syntax is more concise. # Raised Concerns -The new syntax for repeated constant arrays adds additional complexity to the language, but with only a relatively small benefit to conciseness compared to the standard function syntax `ConstantArray(n, x)`. +While the new syntax for repeated constant arrays is designed to be similar to a more general syntax for named arguments, its use in array literals is a special case that needs to specifically be added to the Q# grammar. +This special case adds additional complexity to array literals, especially when potentially combined with array comprehensions in the future. +However, it only provides a small benefit to conciseness compared to traditional syntax like `ConstantArray(n, x)`. -The anticipated extensions to this syntax to support multidimensional arrays and partial application will likely pose additional challenges for Q#'s type system that could be avoided if a traditional function was used instead. -For example, the planned re-use of `size = n` for arrays of any dimensionality is a kind of quasi-overloading that can't be expresed in the type system. -`[0, size = 2]` is an expression of type `Int[]`, but `[0, size = (2, 2)]` is an expression of type `Int[][]`. -With this overloading, partial application of the `size` parameter is problematic: - -```qsharp -let f = [0, size = _]; -``` - -`f` cannot be typed without additional information, such as: - -```qsharp -let g = [0, size = _]; -let xs = g(2, 3); -``` - -`g` can be inferred to be of type `(Int, Int) -> Int[][]`. -But the implementation of this kind of type inference will likely be complicated. -The compiler needs to encode the fact that `g` is of any type that fits `Int n-tuple -> n-nested Int array`, where the arity of the argument tuple equals the nesting of the returned array. -Since this type is impossible to express in Q#'s type system, special handling will need to be added to the type inference algorithm. - -These problems would be avoided, however, if traditional function calls were used instead, such as nested calls to `ConstantArray` for nested arrays, or defining separate `ConstantArray2`, `ConstantArray3`, etc. functions for multidimensional arrays. +By adding special support for constant array syntax to the compiler, it makes it possible to add non-standard handling of types that can't be expressed in Q#'s type system, like what is currently done for arithmetic operators. +For simplicity and to avoid problems with type inference and partial application in the future, we should be careful to avoid behavior that can't be expressed by the current type system or by future extensions to the type system. +In particular, we should be careful about supporting expressions like `[0, size = 3] : Int[]` and `[0, size = (2, 3)] : Int[][]`, where the type of the resulting array is determined by the arity of the `size` tuple, since overloading on tuple arity is difficult to support in the type system. From e4f4f730cc51695850925b528a3fb12daad563cd Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 21 Dec 2020 16:11:07 -0800 Subject: [PATCH 20/22] Update date --- Approved/enhanced-array-literals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 5a169b2..97a964f 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -2,7 +2,7 @@ title: Enhanced array literals and removal of default-initialized array constructors description: Array literals are enhanced to support empty and repeated constant arrays, and the default-initialized array constructor `new Type[n]` is removed. author: Sarah Marshall -date: December 16, 2020 +date: December 21, 2020 --- # Proposal From 4773adfa0f4efdeb67f5796df0020762f361589c Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Mon, 21 Dec 2020 16:12:26 -0800 Subject: [PATCH 21/22] Remove 2D array comprehension example --- Approved/enhanced-array-literals.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index 97a964f..a9e7a4e 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -212,9 +212,6 @@ For example: // An array containing arrays of the first 10 squares. [[x * x for x in 1 .. 10], size = 3] - -// A 3x10 multidensional array with the first 10 squares along one dimension. -#[[x * x for x in 1 .. 10], size = 3] ``` ## Alternatives From 35b764a8d265ad53ff4803f710ab5554d77bb1f8 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 22 Dec 2020 15:24:16 -0800 Subject: [PATCH 22/22] Recommend Size function for arrays --- Approved/enhanced-array-literals.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Approved/enhanced-array-literals.md b/Approved/enhanced-array-literals.md index a9e7a4e..af1d7dd 100644 --- a/Approved/enhanced-array-literals.md +++ b/Approved/enhanced-array-literals.md @@ -2,7 +2,7 @@ title: Enhanced array literals and removal of default-initialized array constructors description: Array literals are enhanced to support empty and repeated constant arrays, and the default-initialized array constructor `new Type[n]` is removed. author: Sarah Marshall -date: December 21, 2020 +date: December 22, 2020 --- # Proposal @@ -142,6 +142,19 @@ The remaining work of adding repeated constant array literals and deprecating th ## Related Mechanisms +### Array size + +The repeated constant array literal uses `size` instead of `length` in anticipation of multidimensional arrays (see the [𝑛-d array proposal](https://github.com/microsoft/qsharp-language/pull/49)). +For consistency, the standard library should consider adding a `Size` function for 1D arrays that is equivalent to `Length`. +This would allow both cases: + +```qsharp +EqualityFactI(Size([0, size = 5]), 5, "Array should have size 5"); +EqualityFactI(Length([0, size = 5]), 5, "Array should have length 5"); +``` + +### Qubit initializers + The syntax for allocating arrays of qubits is similar to the existing default-initialized array constructor syntax: ```qsharp @@ -198,7 +211,6 @@ Empty multidimensional arrays can be created with `#[]` for 2D, `##[]` for 3D, e Both multidimensional and nested (jagged) arrays could be created with the repeated constant array literal syntax. For example, `#[0, size = (2, 2)]` could create a 2x2 multidensional array, while `[[0, size = 2], size = 2]` could create a 2x2 nested array. -This is why the more general term `size` is used here instead of `length`. ### Array comprehensions