Proposal: Compile-time parameters


(Tino) #1

The text of this proposal is available at https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters (I'm not yet confident enough for the whole pull-request stuff :wink:

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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#motivation>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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#proposed-solution>Proposed 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
聽聽聽聽聽聽聽聽}
聽聽聽聽}
...
}
<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#detailed-design>Detailed 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#instantiation>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>

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#limitations-for-parameter-values>Limitations 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#possible-extension-limitations>Possible extension: Limitations

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

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#impact-on-existing-code>Impact 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#alternatives-considered>Alternatives 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#marked-parameters>Marked 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#different-kind-of-braces>Different 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#separate-types>Separate 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#macros-and-preprocessors>Macros 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#tuples>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.


Should labeled variadic parameters accept 0 arguments?
(Joe Groff) #2

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 https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters (I'm not yet confident enough for the whole pull-request stuff :wink:

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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#motivation>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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#proposed-solution>Proposed 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
聽聽聽聽聽聽聽聽}
聽聽聽聽}
...
}
<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#detailed-design>Detailed 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#instantiation>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>

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#limitations-for-parameter-values>Limitations 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#possible-extension-limitations>Possible extension: Limitations

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

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#impact-on-existing-code>Impact 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#alternatives-considered>Alternatives 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#marked-parameters>Marked 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#different-kind-of-braces>Different 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#separate-types>Separate 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#macros-and-preprocessors>Macros 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#tuples>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


(F茅lix Cloutier) #3

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 https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters (I'm not yet confident enough for the whole pull-request stuff :wink:

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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#motivation>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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#proposed-solution>Proposed 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
聽聽聽聽聽聽聽聽}
聽聽聽聽}
...
}
<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#detailed-design>Detailed 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#instantiation>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>

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#limitations-for-parameter-values>Limitations 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#possible-extension-limitations>Possible extension: Limitations

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

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#impact-on-existing-code>Impact 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#alternatives-considered>Alternatives 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#marked-parameters>Marked 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#different-kind-of-braces>Different 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#separate-types>Separate 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#macros-and-preprocessors>Macros 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#tuples>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


(TJ Usiyan) #4

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
https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters (I'm
not yet confident enough for the whole pull-request stuff :wink:
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#motivation>
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#proposed-solution>Proposed
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
聽聽聽聽聽聽聽聽}
聽聽聽聽}
...
}

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#detailed-design>Detailed
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#instantiation>
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>

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#limitations-for-parameter-values>Limitations
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#possible-extension-limitations>Possible
extension: Limitations

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

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#impact-on-existing-code>Impact
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#alternatives-considered>Alternatives
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#marked-parameters>Marked
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#different-kind-of-braces>Different
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#separate-types>Separate
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#macros-and-preprocessors>Macros
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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#tuples>
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


(Thorsten Seitz) #5

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.


(David Sweeris) #6

This might dramatically expand the power of a macro system, but I don鈥檛 think it really constitutes one by itself. I think. Depends on what 鈥渕acro鈥 means to you.

Anyway, for the record (since it鈥檚 apparently out of scope for Swift 3) this will get a huge +1 from me when it鈥檚 time to start talking about Swift x, {x 鈭 鈩 | x > 3} (I think that鈥檚 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 https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters (I'm not yet confident enough for the whole pull-request stuff :wink:

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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#motivation>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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#proposed-solution>Proposed 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
聽聽聽聽聽聽聽聽}
聽聽聽聽}
...
}
<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#detailed-design>Detailed 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#instantiation>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>

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#limitations-for-parameter-values>Limitations 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#possible-extension-limitations>Possible extension: Limitations

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

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#impact-on-existing-code>Impact 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#alternatives-considered>Alternatives 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#marked-parameters>Marked 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#different-kind-of-braces>Different 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#separate-types>Separate 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#macros-and-preprocessors>Macros 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.

<https://github.com/SwiftTypesafeCalculations/Home/wiki/Compile-time-parameters#tuples>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 <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


(Tino) #7

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).


(Tino) #8

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).


(Tino) #9

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...