[RFC] Definitive Initialization and Incompatibilities with Fixed-size Arrays

As I understand it, Definitive Initialization means the Swift compiler will make sure an instance is fully initialized before the first attempt to read it. It does not require mandatory assignment at declaration; an instance can be declared with no initializer and receive an assignment at a later point.

* Class and structure types are considered OK by DI when an initializer is called.
* Enumerations can either use an initializer or have an enumeration-case assigned for DI.
* Compound types (function pointers and tuples) use assignment (possibly at declaration) for DI.
* Tuples can also have the individual members can be tracked for DI. A member has to be initialized by the time that member or the entire tuple is read (whichever comes first).

Tuples (and the other types) can statically determine when a sub-object is initialized. When adding a new member, via new text in the source code, a corresponding new line(s) of code has to be added during the initialization sequence. But built-in arrays, no matter how they’re defined, would be different. The whole point of arrays is to allow adjustment the number of sub-objects without per-sub-object alteration to the array type’s declaration code. That means you can’t write out all the member initializations in advance (in general). And that means you generally use a loop and subscripting instead. And since that moves the references to which elements get initialized to run-time, we have a fundamental incompatibility with definitive initialization. (The fixed-size array proposal I recently posted about does have a static indexing mode, but the point I’m making here is that it doesn’t scale from the perspective of the regular array interaction model.)

Besides banning fixed-size arrays forever and ever (which just hides the problem), we’re limited to:
* Mandatory assignment at declaration, and the initializing expression has to cover all elements
* If arrays keep a static indexing mode, apply DI to an array instance using that. This would mean changing the initialization sequence code every time the number of elements is adjusted. And the initialization would have to be from the static indexing mode for DI to recognize it (i.e. always “a.0 = 4”, no “a[0] = 4”) Note that if we gain an equivalent to C++’s constexpr, then static indexing mode could be spelled with the subscript operation.
* For each array instance not initialized on declaration, define a secret extra Boolean-array object that keeps the initialization state of each element of the first array. Of course, this means tracking each element read and raising a run-time error if not initialized first.
* Something I haven’t considered.

If anyone from the original Swift team is around: is this why you didn’t add fixed-size arrays at the start? (Or did you just forget?) I don’t think you missed a way to link FSAs to DI; the two are just incompatible (if you want to keep the way most people use arrays).

So I’m asking for either some way to make FSAs and DI work together that I missed. Or start a discussion on how undefined behavior on uninitialized-data reads should work on compiler, ABI, and run-time levels.

···


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Right now, my solution is run-time deterministic initialization, but only to fixed-size arrays that are either local objects or stored instance properties. Other instances require the array to be initialized in one shot. To segregate code initializing an array, a special attribute suspends the full initialization requirement in function arguments.

Deterministic Initialization at Run-time

For each local object of a fixed-size array type that is not fully initialized at declaration and has at least one call to its subscript method and/or used as a fragmentary argument, there shall be a secret map object indicating which elements of the array have been initialized. When an element is initialized, either statically or dynamically, the corresponding flag in the initialization map shall be set. When an element is read statically or dynamically, the flag is checked before access, and a run-time error shall be triggered if the element has not been yet initialized. (The check can be elided if the element’s initialization and access were both static.) The same triggering occurs if the array as a whole is read and at least one element is uninitialized, unless the array’s access is being passed as a function argument with the corresponding parameter having the “fragmentary” attribute.

(An array that does not need run-time deterministic initialization checks still has the compile-time ones for it and its sub-objects, just like tuples.)

For each stored instance property of a fixed-size array type declared without a full initialization, then an element initialization map is made for that property at the start of each designated initializer. The properties’ elements’ initializations are confirmed like for local arrays, with the addition of a run-time error gets triggered if the initializer finishes with at least one property element still uninitialized. (The map is elided for a property if all access to its elements is static. Compile-time deterministic initialization still applies.)

Global fixed-size arrays and stored type properties of fixed-size array type must have their initializations done in one shot (i.e. let compile-time deterministic initialization work).

The “fragmentary” type attribute can only be applied to a parameter’s type in a method or function declaration, where the parameter is of a fixed-size array type and also marked with “inout”. It makes the array argument be passed by reference instead of copy, and be secretly accompanied by an in-out (or by-reference) object representing which elements of the array are already initialized. If an element is accessed for reading when the initialization map indicates that it hasn’t been initialized, a run-time error occurs. When an element is written to, the corresponding element in the initialization map is set to TRUE; the updates are sent back out through the secret map argument. When a function with a parameter with this attribute is called, the corresponding array is passed as the explicit argument and the element initialization map is passed as the secret argument. If the array argument does not have a map, like if it was fully initialized statically already, then an equivalent with indicators that all elements are initialized shall be passed.

···

On Jul 13, 2017, at 1:41 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org> wrote:

As I understand it, Definitive Initialization means the Swift compiler will make sure an instance is fully initialized before the first attempt to read it. It does not require mandatory assignment at declaration; an instance can be declared with no initializer and receive an assignment at a later point.

* Class and structure types are considered OK by DI when an initializer is called.
* Enumerations can either use an initializer or have an enumeration-case assigned for DI.
* Compound types (function pointers and tuples) use assignment (possibly at declaration) for DI.
* Tuples can also have the individual members can be tracked for DI. A member has to be initialized by the time that member or the entire tuple is read (whichever comes first).

Tuples (and the other types) can statically determine when a sub-object is initialized. When adding a new member, via new text in the source code, a corresponding new line(s) of code has to be added during the initialization sequence. But built-in arrays, no matter how they’re defined, would be different. The whole point of arrays is to allow adjustment the number of sub-objects without per-sub-object alteration to the array type’s declaration code. That means you can’t write out all the member initializations in advance (in general). And that means you generally use a loop and subscripting instead. And since that moves the references to which elements get initialized to run-time, we have a fundamental incompatibility with definitive initialization. (The fixed-size array proposal I recently posted about does have a static indexing mode, but the point I’m making here is that it doesn’t scale from the perspective of the regular array interaction model.)

Besides banning fixed-size arrays forever and ever (which just hides the problem), we’re limited to:
* Mandatory assignment at declaration, and the initializing expression has to cover all elements
* If arrays keep a static indexing mode, apply DI to an array instance using that. This would mean changing the initialization sequence code every time the number of elements is adjusted. And the initialization would have to be from the static indexing mode for DI to recognize it (i.e. always “a.0 = 4”, no “a[0] = 4”) Note that if we gain an equivalent to C++’s constexpr, then static indexing mode could be spelled with the subscript operation.
* For each array instance not initialized on declaration, define a secret extra Boolean-array object that keeps the initialization state of each element of the first array. Of course, this means tracking each element read and raising a run-time error if not initialized first.
* Something I haven’t considered.

If anyone from the original Swift team is around: is this why you didn’t add fixed-size arrays at the start? (Or did you just forget?) I don’t think you missed a way to link FSAs to DI; the two are just incompatible (if you want to keep the way most people use arrays).

So I’m asking for either some way to make FSAs and DI work together that I missed. Or start a discussion on how undefined behavior on uninitialized-data reads should work on compiler, ABI, and run-time levels.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

I think that you're getting ahead of yourself. Fixed-size arrays are still useful even if they have to have been demonstrably initialized before you can use dynamic indices with them. A ton of people have already gotten into the habit of writing `int foo[40] = {}` in C.

I would like to encourage you to exercise your sense of priority and figure out the minimum changes that you need to make to the language to get something useful, without blocking avenues for expansion. I think that everyone, especially the people that you would be signing up for a tremendous amount of work with your current direction, will be happier this way.

···

Le 16 juil. 2017 à 15:18, Daryle Walker via swift-evolution <swift-evolution@swift.org> a écrit :

On Jul 13, 2017, at 1:41 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

As I understand it, Definitive Initialization means the Swift compiler will make sure an instance is fully initialized before the first attempt to read it. It does not require mandatory assignment at declaration; an instance can be declared with no initializer and receive an assignment at a later point.

* Class and structure types are considered OK by DI when an initializer is called.
* Enumerations can either use an initializer or have an enumeration-case assigned for DI.
* Compound types (function pointers and tuples) use assignment (possibly at declaration) for DI.
* Tuples can also have the individual members can be tracked for DI. A member has to be initialized by the time that member or the entire tuple is read (whichever comes first).

Tuples (and the other types) can statically determine when a sub-object is initialized. When adding a new member, via new text in the source code, a corresponding new line(s) of code has to be added during the initialization sequence. But built-in arrays, no matter how they’re defined, would be different. The whole point of arrays is to allow adjustment the number of sub-objects without per-sub-object alteration to the array type’s declaration code. That means you can’t write out all the member initializations in advance (in general). And that means you generally use a loop and subscripting instead. And since that moves the references to which elements get initialized to run-time, we have a fundamental incompatibility with definitive initialization. (The fixed-size array proposal I recently posted about does have a static indexing mode, but the point I’m making here is that it doesn’t scale from the perspective of the regular array interaction model.)

Besides banning fixed-size arrays forever and ever (which just hides the problem), we’re limited to:
* Mandatory assignment at declaration, and the initializing expression has to cover all elements
* If arrays keep a static indexing mode, apply DI to an array instance using that. This would mean changing the initialization sequence code every time the number of elements is adjusted. And the initialization would have to be from the static indexing mode for DI to recognize it (i.e. always “a.0 = 4”, no “a[0] = 4”) Note that if we gain an equivalent to C++’s constexpr, then static indexing mode could be spelled with the subscript operation.
* For each array instance not initialized on declaration, define a secret extra Boolean-array object that keeps the initialization state of each element of the first array. Of course, this means tracking each element read and raising a run-time error if not initialized first.
* Something I haven’t considered.

If anyone from the original Swift team is around: is this why you didn’t add fixed-size arrays at the start? (Or did you just forget?) I don’t think you missed a way to link FSAs to DI; the two are just incompatible (if you want to keep the way most people use arrays).

So I’m asking for either some way to make FSAs and DI work together that I missed. Or start a discussion on how undefined behavior on uninitialized-data reads should work on compiler, ABI, and run-time levels.

Right now, my solution is run-time deterministic initialization, but only to fixed-size arrays that are either local objects or stored instance properties. Other instances require the array to be initialized in one shot. To segregate code initializing an array, a special attribute suspends the full initialization requirement in function arguments.

Deterministic Initialization at Run-time

For each local object of a fixed-size array type that is not fully initialized at declaration and has at least one call to its subscript method and/or used as a fragmentary argument, there shall be a secret map object indicating which elements of the array have been initialized. When an element is initialized, either statically or dynamically, the corresponding flag in the initialization map shall be set. When an element is read statically or dynamically, the flag is checked before access, and a run-time error shall be triggered if the element has not been yet initialized. (The check can be elided if the element’s initialization and access were both static.) The same triggering occurs if the array as a whole is read and at least one element is uninitialized, unless the array’s access is being passed as a function argument with the corresponding parameter having the “fragmentary” attribute.

(An array that does not need run-time deterministic initialization checks still has the compile-time ones for it and its sub-objects, just like tuples.)

For each stored instance property of a fixed-size array type declared without a full initialization, then an element initialization map is made for that property at the start of each designated initializer. The properties’ elements’ initializations are confirmed like for local arrays, with the addition of a run-time error gets triggered if the initializer finishes with at least one property element still uninitialized. (The map is elided for a property if all access to its elements is static. Compile-time deterministic initialization still applies.)

Global fixed-size arrays and stored type properties of fixed-size array type must have their initializations done in one shot (i.e. let compile-time deterministic initialization work).

The “fragmentary” type attribute can only be applied to a parameter’s type in a method or function declaration, where the parameter is of a fixed-size array type and also marked with “inout”. It makes the array argument be passed by reference instead of copy, and be secretly accompanied by an in-out (or by-reference) object representing which elements of the array are already initialized. If an element is accessed for reading when the initialization map indicates that it hasn’t been initialized, a run-time error occurs. When an element is written to, the corresponding element in the initialization map is set to TRUE; the updates are sent back out through the secret map argument. When a function with a parameter with this attribute is called, the corresponding array is passed as the explicit argument and the element initialization map is passed as the secret argument. If the array argument does not have a map, like if it was fully initialized statically already, then an equivalent with indicators that all elements are initialized shall be passed.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I think that you're getting ahead of yourself. Fixed-size arrays are still useful even if they have to have been demonstrably initialized before you can use dynamic indices with them. A ton of people have already gotten into the habit of writing `int foo[40] = {}` in C.

The person with the initial suggestion regrets this habit and deliberately doesn’t want it. In other words, don’t support the waste of cycles to pre-initialize just for the elements to be immediately paved over with the real initial data. And we may make arrays of types that are heavy to initialize and may not have a default initializer, so even using a default-value term at declaration will lead to a big waste of cycles.

We eventually have to decide how to modify deterministic initialization. Do we take the safe path with dynamic deterministic initialization (and add extra resources)? Or the fast path with suspension of checks (and risk undefined behavior)? We’re probably going to lean toward the former, especially since we can limit its scope (and therefore cost).

···

On Jul 17, 2017, at 3:26 AM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I would like to encourage you to exercise your sense of priority and figure out the minimum changes that you need to make to the language to get something useful, without blocking avenues for expansion. I think that everyone, especially the people that you would be signing up for a tremendous amount of work with your current direction, will be happier this way.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

In my opinion, there is an easy three step plan :-) to solving this problem, riffing on Array:

1) Fixed size arrays should have an initializer to init all the elements to some concrete value.
2) They should have an init that takes a closure, and runs it once per element, passing in the index.
3) Either through a magic value or a third initializer, it should be possible to *explicitly* create a fixed size array with uninitialized garbage for the elements. This is important for specific optimizations, and should also come to Array as well.

IMO, it isn’t a problem that C allows arrays to be uninitialized - the problem is that it is a really bad default.

-Chris

···

On Jul 18, 2017, at 1:00 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 17, 2017, at 3:26 AM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I think that you're getting ahead of yourself. Fixed-size arrays are still useful even if they have to have been demonstrably initialized before you can use dynamic indices with them. A ton of people have already gotten into the habit of writing `int foo[40] = {}` in C.

The person with the initial suggestion regrets this habit and deliberately doesn’t want it. In other words, don’t support the waste of cycles to pre-initialize just for the elements to be immediately paved over with the real initial data. And we may make arrays of types that are heavy to initialize and may not have a default initializer, so even using a default-value term at declaration will lead to a big waste of cycles.

We eventually have to decide how to modify deterministic initialization. Do we take the safe path with dynamic deterministic initialization (and add extra resources)? Or the fast path with suspension of checks (and risk undefined behavior)? We’re probably going to lean toward the former, especially since we can limit its scope (and therefore cost).

I think that you're getting ahead of yourself. Fixed-size arrays are still useful even if they have to have been demonstrably initialized before you can use dynamic indices with them. A ton of people have already gotten into the habit of writing `int foo[40] = {}` in C.

The person with the initial suggestion regrets this habit and deliberately doesn’t want it. In other words, don’t support the waste of cycles to pre-initialize just for the elements to be immediately paved over with the real initial data. And we may make arrays of types that are heavy to initialize and may not have a default initializer, so even using a default-value term at declaration will lead to a big waste of cycles.

We eventually have to decide how to modify deterministic initialization. Do we take the safe path with dynamic deterministic initialization (and add extra resources)? Or the fast path with suspension of checks (and risk undefined behavior)? We’re probably going to lean toward the former, especially since we can limit its scope (and therefore cost).

Oh, I just posted that I just updated my proposal before I saw this in my in-box.

In my opinion, there is an easy three step plan :-) to solving this problem, riffing on Array:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers. My recent update made FSA-literals distinct from standard array literals.

Should there be an equivalent to “ExpressibleByArrayLiteral” for multi-dimensional literals? I don’t know, but it could wait for version 2.

1) Fixed size arrays should have an initializer to init all the elements to some concrete value.

let a = [4; default: “whatever”] // [4; String]

2) They should have an init that takes a closure, and runs it once per element, passing in the index.

let b = [2, 3; func: { Double($0.0 * $0.0 + $0.1 * $0.1) }] // [2, 3; Double]

The index, “$0” here, is passed as “[2; Int]”.

3) Either through a magic value or a third initializer, it should be possible to *explicitly* create a fixed size array with uninitialized garbage for the elements. This is important for specific optimizations, and should also come to Array as well.

let c = [6; 1, 2, 3] // [6; Int], last 3 elements uninitialized

Obviously, the literal can’t use a “default” or “func” term if you want to keep some elements uninitialized.

Leaving elements uninitialized is a big reason for leaving FSAs compound types. We should not violate the expectation that an initializer (which named types have) leaves all sub-objects initialized. So I’m against adding this feature to Array, unless you mean something like “size” vs. “capacity” in C++’s vector and you need to call something like “push_back” to add an element instead of directly using subscript. Since a FSA is a compound type, its sub-objects’ states are tracked with deterministic initialization, just like tuple members.

IMO, it isn’t a problem that C allows arrays to be uninitialized - the problem is that it is a really bad default.

I was struggling which way to go; add run-time deterministic initialization or allow undefined behavior. For now, it’s neither; the current compile-time deterministic initialization has to be followed. But compile-time DI isn’t big a setback as long as you have all the information you need to set every element before initialization-assignment (with a function term).

I read a post once wishing for a function to join tuples together as a giant tuple. I was wondering about the same thing for FSAs, where you have to specify which index you want to be the axis of the join (and all the non-axis dimensions have to have corresponding lengths being equal). This requires more advanced generics than we have now; but if implemented, we could build arrays in piecemeal then join them together for the final value. It could look like:

let d = joinArrays<2>( [2, 3, 7, 5, 9; default: 23], [2, 3, 4, 5, 9; func: { $0.0 + $0.4 }] ) // [2, 3, 11, 5, 9; Int], axis 2: 7 + 4 == 11

···

On Jul 22, 2017, at 3:02 PM, Chris Lattner <clattner@nondot.org> wrote:
On Jul 18, 2017, at 1:00 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 17, 2017, at 3:26 AM, Félix Cloutier <felixcca@yahoo.ca> wrote:


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

In my opinion, there is an easy three step plan :-) to solving this problem, riffing on Array:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

IMO, it isn’t a problem that C allows arrays to be uninitialized - the problem is that it is a really bad default.

I was struggling which way to go; add run-time deterministic initialization or allow undefined behavior. For now, it’s neither; the current compile-time deterministic initialization has to be followed. But compile-time DI isn’t big a setback as long as you have all the information you need to set every element before initialization-assignment (with a function term).

If you’re thinking of allowing something like:

var x : Int[4] // or whatever

// These are all initializations
x[0] = 1
x[1] = 2
x[2] = 3
x[3] = 4

Then it is possible to enable some simple cases (like this), but not the more useful and general cases. I’d suggest starting without this, since it could be added at any time in the future if there were a compelling reason to.

-Chris

···

On Jul 22, 2017, at 3:03 PM, Daryle Walker <darylew@mac.com> wrote:

I think I've already said that, but I agree that an incremental approach to this would be better.

···

Le 23 juil. 2017 à 15:57, Chris Lattner <clattner@nondot.org> a écrit :

On Jul 22, 2017, at 3:03 PM, Daryle Walker <darylew@mac.com> wrote:

In my opinion, there is an easy three step plan :-) to solving this problem, riffing on Array:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

Either way, in the context of fixed-size arrays, I think that it's a broader problem that anonymous types can't have anything attached to them. This also prevents fixed-size arrays from conforming to protocols, even Sequence, and Swift would need variadic generics or (possibly, depending on the syntax) non-type generic parameters to even create a wrapper.

Félix

My solution to tuples and fixed-size arrays not supporting attached interfaces is to make a strong type-alias to the compound type and add your interface there. And unlike alternatives added to the core language level, users who don’t want that particular extended interface (or want an incompatible one!) don’t have to live with it. It’s part of the “alternative types” proposal.

···

On Jul 23, 2017, at 7:27 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I think I've already said that, but I agree that an incremental approach to this would be better.

Le 23 juil. 2017 à 15:57, Chris Lattner <clattner@nondot.org> a écrit :

On Jul 22, 2017, at 3:03 PM, Daryle Walker <darylew@mac.com> wrote:

In my opinion, there is an easy three step plan :-) to solving this problem, riffing on Array:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

Either way, in the context of fixed-size arrays, I think that it's a broader problem that anonymous types can't have anything attached to them. This also prevents fixed-size arrays from conforming to protocols, even Sequence, and Swift would need variadic generics or (possibly, depending on the syntax) non-type generic parameters to even create a wrapper.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Agreed. However, solving that general problem is hard, and completely orthogonal to the win of having fixed sized arrays work.

-Chris

···

On Jul 23, 2017, at 4:27 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

Either way, in the context of fixed-size arrays, I think that it's a broader problem that anonymous types can't have anything attached to them. This also prevents fixed-size arrays from conforming to protocols, even Sequence, and Swift would need variadic generics or (possibly, depending on the syntax) non-type generic parameters to even create a wrapper.

The mere virtue of a strong typealias won't provide an implementation of the Sequence protocol, and as was just established, the language isn't equipped to provide an automatic implementation through the standard library. Your suggestion is an entry point for compiler magic. If we get into that territory, I would much rather have compiler magic that doesn't require me to find a human-readable name for an array type just for the privilege of iterating over its values, and that doesn't make identical array types incompatible with one another.

Félix

···

Le 23 juil. 2017 à 20:05, Daryle Walker <darylew@mac.com> a écrit :

On Jul 23, 2017, at 7:27 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I think I've already said that, but I agree that an incremental approach to this would be better.

Le 23 juil. 2017 à 15:57, Chris Lattner <clattner@nondot.org> a écrit :

On Jul 22, 2017, at 3:03 PM, Daryle Walker <darylew@mac.com> wrote:

In my opinion, there is an easy three step plan :-) to solving this problem, riffing on Array:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

Either way, in the context of fixed-size arrays, I think that it's a broader problem that anonymous types can't have anything attached to them. This also prevents fixed-size arrays from conforming to protocols, even Sequence, and Swift would need variadic generics or (possibly, depending on the syntax) non-type generic parameters to even create a wrapper.

My solution to tuples and fixed-size arrays not supporting attached interfaces is to make a strong type-alias to the compound type and add your interface there. And unlike alternatives added to the core language level, users who don’t want that particular extended interface (or want an incompatible one!) don’t have to live with it. It’s part of the “alternative types” proposal.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Is there really any doubt that we'll eventually get Variadic Generics and Non-Type Generic Parameters? They're always well-received whenever they come up, but they keep getting ruled out-of-scope before a proposal can be fully fleshed-out. I'm asking because it'd make it way easier to design a FSA proposal knowing that it could rely on those features. Personally, I'd even be ok with accepting such a proposal "pending the acceptance of its 'dependency proposals'" (with probably a quick re-review to make sure any subsequent proposals haven't materially changed how it'd work).

- Dave Sweeris

···

On Jul 24, 2017, at 9:37 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 23, 2017, at 4:27 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

Either way, in the context of fixed-size arrays, I think that it's a broader problem that anonymous types can't have anything attached to them. This also prevents fixed-size arrays from conforming to protocols, even Sequence, and Swift would need variadic generics or (possibly, depending on the syntax) non-type generic parameters to even create a wrapper.

Agreed. However, solving that general problem is hard, and completely orthogonal to the win of having fixed sized arrays work.

Right now, it's marked as "maybe" in the generic manifesto <https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-value-parameters&gt;\.

There are a number of features that get discussed from time-to-time, while they could fit into Swift's generics system, it's not clear that they belong in Swift at all. The important question for any feature in this category is not "can it be done" or "are there cool things we can express", but "how can everyday Swift developers benefit from the addition of such a feature?". Without strong motivating examples, none of these "maybes" will move further along.

Félix

···

Le 24 juil. 2017 à 10:06, David Sweeris <davesweeris@mac.com> a écrit :

On Jul 24, 2017, at 9:37 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 23, 2017, at 4:27 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

Well, fixed-size arrays don’t have initializers, for the same reason tuples don’t: they’re compound types instead of named types and they literally have nowhere to place initializer definitions. But like tuples, FSAs have a literal syntax that works as a substitute for full-blown initializers.

Ok, sure. They aren’t literally initializers in the stdlib (they are built into the compiler), but they have initialization semantics and can be spelled in whatever way makes ergonomic sense. Keeping them aligned with Array seems like a good starting point.

Either way, in the context of fixed-size arrays, I think that it's a broader problem that anonymous types can't have anything attached to them. This also prevents fixed-size arrays from conforming to protocols, even Sequence, and Swift would need variadic generics or (possibly, depending on the syntax) non-type generic parameters to even create a wrapper.

Agreed. However, solving that general problem is hard, and completely orthogonal to the win of having fixed sized arrays work.

Is there really any doubt that we'll eventually get Variadic Generics and Non-Type Generic Parameters? They're always well-received whenever they come up, but they keep getting ruled out-of-scope before a proposal can be fully fleshed-out. I'm asking because it'd make it way easier to design a FSA proposal knowing that it could rely on those features. Personally, I'd even be ok with accepting such a proposal "pending the acceptance of its 'dependency proposals'" (with probably a quick re-review to make sure any subsequent proposals haven't materially changed how it'd work).

- Dave Sweeris