Proposal: Compile-time parameters

The text of this proposal is available at Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub (I'm not yet confident enough for the whole pull-request stuff ;-)

Depending on the time you read this, the Wiki-version might lack some typos and other errors...
Introduction

Generics are often seen as "simplified templates": They are not as powerful, but have the benefit of being less complicated and dangerous. The feature illustrated here should not only make Swift more powerful, but also safer by adding basic datatypes like fixed-size arrays.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

Right now, we can have something like let m = Matrix(rows: 3, columns: 4) easily. There's just the problem that the compiler cannot deduce which matrices are "compatible", as there is only one Matrix-type. If we had a way to tell the compiler that "rows" and "columns" have an effect on the type, errors due to dimension mismatches could be eliminated (vector math, but also functions like zip would benefit from this).

Additionally, the proposal would make it possible to create unit systems, so that calculations are checked for matching quantities (so you cannot add a force to a velocity without causing an error).

Currently, there is no elegant way to declare a C-type array of a fixed size; this is a fundamental problem that could be solved with the syntax presented here.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub solution

The basic idea is quite simple: We just need a way to tell the compile that there are some parameters that have impact on their type. On possible syntax would be

struct Matrix<T: ScalarType, let rows: UInt, let columns: UInt> {
...
subscript(row: UInt, column: UInt) -> T {
    set(value) {
        if row < rows && column < columns {
            // set the entry
        } else {
            // out of bounds - that is not allowed
        }
    }
...
}
<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub design

I think its easy to grasp with the example: In addition to type parameters, we introduce constants that are defined in a similar way:

let [identifier]: [type]

e.g.

struct FloatVector<let dimensions: UInt>...

Unlike templates, compile-time parameters (as the name already suggests) could live inside libs, without disclosing details about their implementation.

From the inside of the parametrized object, compile-time parameters would be used like normal let-parameters/members.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

The behavior should be similar to generics, so the position of each parameter in the list is fixed. To make things clearer, I suggest to accept (optional) labels, so that the two following statements are valid:

let force: FloatVector<dimensions: 3>

let impulse: FloatVector<3>

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub for parameter values

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub extension: Limitations

It would nice to have where-clauses on the parameters to disallow certain values or value-combinations.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub on existing code

None, it's a new feature that does not affect existing code - but it might be a good opportunity to improve the generics syntax as well: There have also been wishes for labeled type parameters, and as far as I can see, those should be allowed, too.

To further increase consistency, the generics-syntax could be changed (struct Array<type T>... or struct Array<T: type where ...>), but that is not coupled with this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub considered

Actually, the let-syntax is not my preferred choice - but there is a collision with generics, and relying on capitalization to distinguish MyClass<size: Int> and MyClass<V: UIView> seems strange. It could still be possible to drop let without confusing the compiler, but I'm concerned about confusing the user:

It makes no sense to declare a generic parameter that is restricted to a subtype of something that is final, but that isn't obvious to a human reader.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub parameters

It would be possible to keep the parameters in the initializer (or function) and mark them with a keyword: init(static dimensions: Int) {...

Especially for types, this would be cumbersome, as you can have many initializers.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub kind of braces

Instead of grouping value parameters with type parameters, they could be separated:

class Test[Size: Int]<T> or class Test(size: Int)<T>

The benefit would be that let isn't needed anymore, but as compile-time parameters are very similar to generics, it would be nice to resemble that in the syntax. Especially the square-braces have a very different, established meaning (array subscript), so I'd strongly advice not to consider them.

Normal parenthesis don't have that problem at the declaration site, but lack an obvious instantiation syntax that doesn't collide with init parameters.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub types

The current "solution" is declaring a type for every case you want to cover.

This approach works good enough in simple situations (e.g. Vector4), but it scales badly:

It is tedious to declare new variants, and the only way to express their tight resemblance is a coherent naming scheme that isn't enforced.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub and preprocessors

It is possible to generate distinct types using macros - but as there is no build-in support for those, this is quite cumbersome.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

There has been a discussion about a shorthand to declare tuples with a fixed number of elements.

This solution would have the benefit of automatic compatibility with C-structs - but the downside of not having the power of Swift structs (and classes): Tuples can't have methods, and this is a major drawback.

So, the tuple-extension is no real alternative, but both ideas would fit together without redundancy.

Values as generic parameters are an area of interest to us for future expansion, not something we're philosophically opposed to, but they're out of scope for Swift 3. The design would have to take into account a model for compile-time constant values, which defines exactly what kinds of types and expressions can be used as compile-time literals in things like fixed array bounds and enum raw values in addition to general type parameters.

-Joe

···

On Jan 30, 2016, at 7:10 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

The text of this proposal is available at Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub (I'm not yet confident enough for the whole pull-request stuff ;-)

Depending on the time you read this, the Wiki-version might lack some typos and other errors...
Introduction

Generics are often seen as "simplified templates": They are not as powerful, but have the benefit of being less complicated and dangerous. The feature illustrated here should not only make Swift more powerful, but also safer by adding basic datatypes like fixed-size arrays.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

Right now, we can have something like let m = Matrix(rows: 3, columns: 4) easily. There's just the problem that the compiler cannot deduce which matrices are "compatible", as there is only one Matrix-type. If we had a way to tell the compiler that "rows" and "columns" have an effect on the type, errors due to dimension mismatches could be eliminated (vector math, but also functions like zip would benefit from this).

Additionally, the proposal would make it possible to create unit systems, so that calculations are checked for matching quantities (so you cannot add a force to a velocity without causing an error).

Currently, there is no elegant way to declare a C-type array of a fixed size; this is a fundamental problem that could be solved with the syntax presented here.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub solution

The basic idea is quite simple: We just need a way to tell the compile that there are some parameters that have impact on their type. On possible syntax would be

struct Matrix<T: ScalarType, let rows: UInt, let columns: UInt> {
...
subscript(row: UInt, column: UInt) -> T {
    set(value) {
        if row < rows && column < columns {
            // set the entry
        } else {
            // out of bounds - that is not allowed
        }
    }
...
}
<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub design

I think its easy to grasp with the example: In addition to type parameters, we introduce constants that are defined in a similar way:

let [identifier]: [type]

e.g.

struct FloatVector<let dimensions: UInt>...

Unlike templates, compile-time parameters (as the name already suggests) could live inside libs, without disclosing details about their implementation.

From the inside of the parametrized object, compile-time parameters would be used like normal let-parameters/members.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

The behavior should be similar to generics, so the position of each parameter in the list is fixed. To make things clearer, I suggest to accept (optional) labels, so that the two following statements are valid:

let force: FloatVector<dimensions: 3>

let impulse: FloatVector<3>

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub for parameter values

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub extension: Limitations

It would nice to have where-clauses on the parameters to disallow certain values or value-combinations.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub on existing code

None, it's a new feature that does not affect existing code - but it might be a good opportunity to improve the generics syntax as well: There have also been wishes for labeled type parameters, and as far as I can see, those should be allowed, too.

To further increase consistency, the generics-syntax could be changed (struct Array<type T>... or struct Array<T: type where ...>), but that is not coupled with this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub considered

Actually, the let-syntax is not my preferred choice - but there is a collision with generics, and relying on capitalization to distinguish MyClass<size: Int> and MyClass<V: UIView> seems strange. It could still be possible to drop let without confusing the compiler, but I'm concerned about confusing the user:

It makes no sense to declare a generic parameter that is restricted to a subtype of something that is final, but that isn't obvious to a human reader.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub parameters

It would be possible to keep the parameters in the initializer (or function) and mark them with a keyword: init(static dimensions: Int) {...

Especially for types, this would be cumbersome, as you can have many initializers.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub kind of braces

Instead of grouping value parameters with type parameters, they could be separated:

class Test[Size: Int]<T> or class Test(size: Int)<T>

The benefit would be that let isn't needed anymore, but as compile-time parameters are very similar to generics, it would be nice to resemble that in the syntax. Especially the square-braces have a very different, established meaning (array subscript), so I'd strongly advice not to consider them.

Normal parenthesis don't have that problem at the declaration site, but lack an obvious instantiation syntax that doesn't collide with init parameters.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub types

The current "solution" is declaring a type for every case you want to cover.

This approach works good enough in simple situations (e.g. Vector4), but it scales badly:

It is tedious to declare new variants, and the only way to express their tight resemblance is a coherent naming scheme that isn't enforced.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub and preprocessors

It is possible to generate distinct types using macros - but as there is no build-in support for those, this is quite cumbersome.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

There has been a discussion about a shorthand to declare tuples with a fixed number of elements.

This solution would have the benefit of automatic compatibility with C-structs - but the downside of not having the power of Swift structs (and classes): Tuples can't have methods, and this is a major drawback.

So, the tuple-extension is no real alternative, but both ideas would fit together without redundancy.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm not against the feature (I participated in the original type-safe units discussion), but I think that the core team's focus is elsewhere for Swift 3.

Félix

···

Le 30 janv. 2016 à 10:10:15, Tino Heth via swift-evolution <swift-evolution@swift.org> a écrit :

The text of this proposal is available at Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub (I'm not yet confident enough for the whole pull-request stuff ;-)

Depending on the time you read this, the Wiki-version might lack some typos and other errors...
Introduction

Generics are often seen as "simplified templates": They are not as powerful, but have the benefit of being less complicated and dangerous. The feature illustrated here should not only make Swift more powerful, but also safer by adding basic datatypes like fixed-size arrays.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

Right now, we can have something like let m = Matrix(rows: 3, columns: 4) easily. There's just the problem that the compiler cannot deduce which matrices are "compatible", as there is only one Matrix-type. If we had a way to tell the compiler that "rows" and "columns" have an effect on the type, errors due to dimension mismatches could be eliminated (vector math, but also functions like zip would benefit from this).

Additionally, the proposal would make it possible to create unit systems, so that calculations are checked for matching quantities (so you cannot add a force to a velocity without causing an error).

Currently, there is no elegant way to declare a C-type array of a fixed size; this is a fundamental problem that could be solved with the syntax presented here.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub solution

The basic idea is quite simple: We just need a way to tell the compile that there are some parameters that have impact on their type. On possible syntax would be

struct Matrix<T: ScalarType, let rows: UInt, let columns: UInt> {
...
subscript(row: UInt, column: UInt) -> T {
    set(value) {
        if row < rows && column < columns {
            // set the entry
        } else {
            // out of bounds - that is not allowed
        }
    }
...
}
<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub design

I think its easy to grasp with the example: In addition to type parameters, we introduce constants that are defined in a similar way:

let [identifier]: [type]

e.g.

struct FloatVector<let dimensions: UInt>...

Unlike templates, compile-time parameters (as the name already suggests) could live inside libs, without disclosing details about their implementation.

From the inside of the parametrized object, compile-time parameters would be used like normal let-parameters/members.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

The behavior should be similar to generics, so the position of each parameter in the list is fixed. To make things clearer, I suggest to accept (optional) labels, so that the two following statements are valid:

let force: FloatVector<dimensions: 3>

let impulse: FloatVector<3>

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub for parameter values

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub extension: Limitations

It would nice to have where-clauses on the parameters to disallow certain values or value-combinations.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub on existing code

None, it's a new feature that does not affect existing code - but it might be a good opportunity to improve the generics syntax as well: There have also been wishes for labeled type parameters, and as far as I can see, those should be allowed, too.

To further increase consistency, the generics-syntax could be changed (struct Array<type T>... or struct Array<T: type where ...>), but that is not coupled with this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub considered

Actually, the let-syntax is not my preferred choice - but there is a collision with generics, and relying on capitalization to distinguish MyClass<size: Int> and MyClass<V: UIView> seems strange. It could still be possible to drop let without confusing the compiler, but I'm concerned about confusing the user:

It makes no sense to declare a generic parameter that is restricted to a subtype of something that is final, but that isn't obvious to a human reader.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub parameters

It would be possible to keep the parameters in the initializer (or function) and mark them with a keyword: init(static dimensions: Int) {...

Especially for types, this would be cumbersome, as you can have many initializers.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub kind of braces

Instead of grouping value parameters with type parameters, they could be separated:

class Test[Size: Int]<T> or class Test(size: Int)<T>

The benefit would be that let isn't needed anymore, but as compile-time parameters are very similar to generics, it would be nice to resemble that in the syntax. Especially the square-braces have a very different, established meaning (array subscript), so I'd strongly advice not to consider them.

Normal parenthesis don't have that problem at the declaration site, but lack an obvious instantiation syntax that doesn't collide with init parameters.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub types

The current "solution" is declaring a type for every case you want to cover.

This approach works good enough in simple situations (e.g. Vector4), but it scales badly:

It is tedious to declare new variants, and the only way to express their tight resemblance is a coherent naming scheme that isn't enforced.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub and preprocessors

It is possible to generate distinct types using macros - but as there is no build-in support for those, this is quite cumbersome.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

There has been a discussion about a shorthand to declare tuples with a fixed number of elements.

This solution would have the benefit of automatic compatibility with C-structs - but the downside of not having the power of Swift structs (and classes): Tuples can't have methods, and this is a major drawback.

So, the tuple-extension is no real alternative, but both ideas would fit together without redundancy.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

This seems very much like macros which are sadly but understandably out of
scope for Swift 3.0.

···

On Sat, Jan 30, 2016 at 9:44 PM, Félix Cloutier <swift-evolution@swift.org> wrote:

I'm not against the feature (I participated in the original type-safe
units discussion), but I think that the core team's focus is elsewhere for
Swift 3.

Félix

Le 30 janv. 2016 à 10:10:15, Tino Heth via swift-evolution < > swift-evolution@swift.org> a écrit :

The text of this proposal is available at
Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub (I'm
not yet confident enough for the whole pull-request stuff ;-)
Depending on the time you read this, the Wiki-version might lack some
typos and other errors...
Introduction

Generics are often seen as "simplified templates": They are not as
powerful, but have the benefit of being less complicated and dangerous. The
feature illustrated here should not only make Swift more powerful, but also
safer by adding basic datatypes like fixed-size arrays.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub;
Motivation

Right now, we can have something like let m = Matrix(rows: 3, columns: 4) easily.
There's just the problem that the compiler cannot deduce which matrices are
"compatible", as there is only one Matrix-type. If we had a way to tell the
compiler that "rows" and "columns" have an effect on the type, errors due
to dimension mismatches could be eliminated (vector math, but also
functions like zip would benefit from this).

Additionally, the proposal would make it possible to create unit systems,
so that calculations are checked for matching quantities (so you cannot add
a force to a velocity without causing an error).

Currently, there is no elegant way to declare a C-type array of a fixed
size; this is a fundamental problem that could be solved with the syntax
presented here.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
solution

The basic idea is quite simple: We just need a way to tell the compile
that there are some parameters that have impact on their type. On possible
syntax would be

struct Matrix<T: ScalarType, let rows: UInt, let columns: UInt> {
...
subscript(row: UInt, column: UInt) -> T {
    set(value) {
        if row < rows && column < columns {
            // set the entry
        } else {
            // out of bounds - that is not allowed
        }
    }
...
}

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
design

I think its easy to grasp with the example: In addition to type
parameters, we introduce constants that are defined in a similar way:

let [identifier]: [type]

e.g.

struct FloatVector<let dimensions: UInt>...

Unlike templates, compile-time parameters (as the name already suggests)
could live inside libs, without disclosing details about their
implementation.

From the inside of the parametrized object, compile-time parameters would
be used like normal let-parameters/members.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub;
Instantiation

The behavior should be similar to generics, so the position of each
parameter in the list is fixed. To make things clearer, I suggest to accept
(optional) labels, so that the two following statements are valid:

let force: FloatVector<dimensions: 3>

let impulse: FloatVector<3>

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
for parameter values

Although integer-type parameters are most likely the only ones with a
broad use case, any type implementing one of the ...LiteralCovertible protocols
could be used. Enums and other entities could make sense as well, but this
is beyond the scope of this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
extension: Limitations

It would nice to have where-clauses on the parameters to disallow certain
values or value-combinations.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
on existing code

None, it's a new feature that does not affect existing code - but it might
be a good opportunity to improve the generics syntax as well: There have
also been wishes for labeled type parameters, and as far as I can see,
those should be allowed, too.

To further increase consistency, the generics-syntax could be changed (struct
Array<type T>... or struct Array<T: type where ...>), but that is not
coupled with this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
considered

Actually, the let-syntax is not my preferred choice - but there is a
collision with generics, and relying on capitalization to distinguish MyClass<size:
> and MyClass<V: UIView> seems strange. It could still be possible to
drop let without confusing the compiler, but I'm concerned about
confusing the user:

It makes no sense to declare a generic parameter that is restricted to a
subtype of something that is final, but that isn't obvious to a human
reader.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
parameters

It would be possible to keep the parameters in the initializer (or
function) and mark them with a keyword: init(static dimensions: Int) {...

Especially for types, this would be cumbersome, as you can have many
initializers.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
kind of braces

Instead of grouping value parameters with type parameters, they could be
separated:

class Test[Size: Int]<T> or class Test(size: Int)<T>

The benefit would be that let isn't needed anymore, but as compile-time
parameters are very similar to generics, it would be nice to resemble that
in the syntax. Especially the square-braces have a very different,
established meaning (array subscript), so I'd strongly advice not to
consider them.

Normal parenthesis don't have that problem at the declaration site, but
lack an obvious instantiation syntax that doesn't collide with init
parameters.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
types

The current "solution" is declaring a type for every case you want to
cover.

This approach works good enough in simple situations (e.g. Vector4), but
it scales badly:

It is tedious to declare new variants, and the only way to express their
tight resemblance is a coherent naming scheme that isn't enforced.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub
and preprocessors

It is possible to generate distinct types using macros - but as there is
no build-in support for those, this is quite cumbersome.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub;
Tuples

There has been a discussion about a shorthand to declare tuples with a
fixed number of elements.

This solution would have the benefit of automatic compatibility with
C-structs - but the downside of not having the power of Swift structs (and
classes): Tuples can't have methods, and this is a major drawback.
So, the tuple-extension is no real alternative, but both ideas would fit
together without redundancy.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

Does this imply that only literals would be allowed? That would be too limiting because then my example with a generic frameworks for physical units in the "type safe..." thread would not be possible as it requires expressions at least in where clauses.

-Thorsten

···

Am 30.01.2016 um 16:10 schrieb Tino Heth via swift-evolution <swift-evolution@swift.org>:

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

This might dramatically expand the power of a macro system, but I don’t think it really constitutes one by itself. I think. Depends on what “macro” means to you.

Anyway, for the record (since it’s apparently out of scope for Swift 3) this will get a huge +1 from me when it’s time to start talking about Swift x, {x ∈ ℝ | x > 3} (I think that’s the proper set notation).

- Dave Sweeris

···

On Jan 30, 2016, at 12:55, T.J. Usiyan via swift-evolution <swift-evolution@swift.org> wrote:

This seems very much like macros which are sadly but understandably out of scope for Swift 3.0.

On Sat, Jan 30, 2016 at 9:44 PM, Félix Cloutier <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I'm not against the feature (I participated in the original type-safe units discussion), but I think that the core team's focus is elsewhere for Swift 3.

Félix

Le 30 janv. 2016 à 10:10:15, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

The text of this proposal is available at Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub (I'm not yet confident enough for the whole pull-request stuff ;-)

Depending on the time you read this, the Wiki-version might lack some typos and other errors...
Introduction

Generics are often seen as "simplified templates": They are not as powerful, but have the benefit of being less complicated and dangerous. The feature illustrated here should not only make Swift more powerful, but also safer by adding basic datatypes like fixed-size arrays.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

Right now, we can have something like let m = Matrix(rows: 3, columns: 4) easily. There's just the problem that the compiler cannot deduce which matrices are "compatible", as there is only one Matrix-type. If we had a way to tell the compiler that "rows" and "columns" have an effect on the type, errors due to dimension mismatches could be eliminated (vector math, but also functions like zip would benefit from this).

Additionally, the proposal would make it possible to create unit systems, so that calculations are checked for matching quantities (so you cannot add a force to a velocity without causing an error).

Currently, there is no elegant way to declare a C-type array of a fixed size; this is a fundamental problem that could be solved with the syntax presented here.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub solution

The basic idea is quite simple: We just need a way to tell the compile that there are some parameters that have impact on their type. On possible syntax would be

struct Matrix<T: ScalarType, let rows: UInt, let columns: UInt> {
...
subscript(row: UInt, column: UInt) -> T {
    set(value) {
        if row < rows && column < columns {
            // set the entry
        } else {
            // out of bounds - that is not allowed
        }
    }
...
}
<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub design

I think its easy to grasp with the example: In addition to type parameters, we introduce constants that are defined in a similar way:

let [identifier]: [type]

e.g.

struct FloatVector<let dimensions: UInt>...

Unlike templates, compile-time parameters (as the name already suggests) could live inside libs, without disclosing details about their implementation.

From the inside of the parametrized object, compile-time parameters would be used like normal let-parameters/members.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

The behavior should be similar to generics, so the position of each parameter in the list is fixed. To make things clearer, I suggest to accept (optional) labels, so that the two following statements are valid:

let force: FloatVector<dimensions: 3>

let impulse: FloatVector<3>

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub for parameter values

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub extension: Limitations

It would nice to have where-clauses on the parameters to disallow certain values or value-combinations.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub on existing code

None, it's a new feature that does not affect existing code - but it might be a good opportunity to improve the generics syntax as well: There have also been wishes for labeled type parameters, and as far as I can see, those should be allowed, too.

To further increase consistency, the generics-syntax could be changed (struct Array<type T>... or struct Array<T: type where ...>), but that is not coupled with this proposal.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub considered

Actually, the let-syntax is not my preferred choice - but there is a collision with generics, and relying on capitalization to distinguish MyClass<size: Int> and MyClass<V: UIView> seems strange. It could still be possible to drop let without confusing the compiler, but I'm concerned about confusing the user:

It makes no sense to declare a generic parameter that is restricted to a subtype of something that is final, but that isn't obvious to a human reader.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub parameters

It would be possible to keep the parameters in the initializer (or function) and mark them with a keyword: init(static dimensions: Int) {...

Especially for types, this would be cumbersome, as you can have many initializers.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub kind of braces

Instead of grouping value parameters with type parameters, they could be separated:

class Test[Size: Int]<T> or class Test(size: Int)<T>

The benefit would be that let isn't needed anymore, but as compile-time parameters are very similar to generics, it would be nice to resemble that in the syntax. Especially the square-braces have a very different, established meaning (array subscript), so I'd strongly advice not to consider them.

Normal parenthesis don't have that problem at the declaration site, but lack an obvious instantiation syntax that doesn't collide with init parameters.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub types

The current "solution" is declaring a type for every case you want to cover.

This approach works good enough in simple situations (e.g. Vector4), but it scales badly:

It is tedious to declare new variants, and the only way to express their tight resemblance is a coherent naming scheme that isn't enforced.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub and preprocessors

It is possible to generate distinct types using macros - but as there is no build-in support for those, this is quite cumbersome.

<Compile time parameters · SwiftInofficialEvolution/Home Wiki · GitHub

There has been a discussion about a shorthand to declare tuples with a fixed number of elements.

This solution would have the benefit of automatic compatibility with C-structs - but the downside of not having the power of Swift structs (and classes): Tuples can't have methods, and this is a major drawback.

So, the tuple-extension is no real alternative, but both ideas would fit together without redundancy.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

Does this imply that only literals would be allowed?

For declaration: Yes, I think it is the simplest way to prevent confusion.
In the implementation, it should be possible to use compile-time parameters to instantiate new variants (like using a m x n matrix to generate a vector of size m * n, or creating a array of size 4 by adding a value to an array of size 3).

Although integer-type parameters are most likely the only ones with a broad use case, any type implementing one of the ...LiteralCovertible protocols could be used. Enums and other entities could make sense as well, but this is beyond the scope of this proposal.

Does this imply that only literals would be allowed?

For declaration: Yes, I think it is the simplest way to prevent confusion.
In the implementation, it should be possible to use compile-time parameters to instantiate new variants (like using a m x n matrix to generate a vector of size m * n, or creating a array of size 4 by adding a value to an array of size 3).

This seems very much like macros

What lead to this conclusion? I'm afraid there must be a major ambiguity in my text, as the idea shares much more similarity with generics, and I would say the latter are actually more macro-like...