[Proposal] Swift 2.2: #if swift language version


(David Farler) #1

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
  print("Hello")
#else
  this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David


(Radek Pietruszewski) #2

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

— Radek

···

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

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


(Michel Fortin) #3

This is a change from how the #if directive currently works. Currently, it's a syntax error to write this:

  #if DEBUG
  @abaraka func test() {}
  #endif

even if DEBUG is false because the content is parsed regardless and @abaraka is not a valid attribute. The syntax inside the #if/#endif must be valid for the parser.

So this proposal implies a change in how #if is parsed. Should it works like the C preprocessor?

···

Le 18 déc. 2015 à 15:22, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

--
Michel Fortin
michel.fortin@michelf.ca
https://michelf.ca


(Chris Lattner) #4

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :-)

-Chris

···

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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


(David Farler) #5

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :slight_smile:

-Chris

Yep, you took the words out of my mouth re: the version components. If two components are enough though, then we should totally drop the quotes.

David

···

On Dec 18, 2015, at 12:29 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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


(David Farler) #6

I had considered this format but I don't think it reads as well as you'd expect for a version. It kind of makes it seem like each component is an independent argument, each with possibly a different meaning. It makes sense from a parsing point of view but I think we should allow folks to write it the same way they'd write it in normal prose, since it's not much more effort.

David

···

On Dec 18, 2015, at 12:48, Harlan Haskins <harlan@harlanhaskins.com> wrote:

How about

#if swift(2, 2, *)
#endif

?

On Dec 18, 2015, at 3:32 PM, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :slight_smile:

-Chris

Yep, you took the words out of my mouth re: the version components. If two components are enough though, then we should totally drop the quotes.

David

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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

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


(Douglas Gregor) #7

This feature LGTM, and I also prefer that we drop the quotes. Two levels of version number should be sufficient.

  - Doug

···

On Dec 18, 2015, at 12:29 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.


(Harlan Haskins) #8

How about

#if swift(2, 2, *)
#endif

?

···

On Dec 18, 2015, at 3:32 PM, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :slight_smile:

-Chris

Yep, you took the words out of my mouth re: the version components. If two components are enough though, then we should totally drop the quotes.

David

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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

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


(Harlan Haskins) #9

I agree — my reasoning was that it’s more like the current iOS availability statement.

I wonder if the iOS availability statement could use some work too? It’s kinda weird and magical ("why do I have to type that *?")

···

On Dec 18, 2015, at 3:56 PM, David Farler <dfarler@apple.com> wrote:

I had considered this format but I don't think it reads as well as you'd expect for a version. It kind of makes it seem like each component is an independent argument, each with possibly a different meaning. It makes sense from a parsing point of view but I think we should allow folks to write it the same way they'd write it in normal prose, since it's not much more effort.

David

On Dec 18, 2015, at 12:48, Harlan Haskins <harlan@harlanhaskins.com <mailto:harlan@harlanhaskins.com>> wrote:

How about

#if swift(2, 2, *)
#endif

?

On Dec 18, 2015, at 3:32 PM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :slight_smile:

-Chris

Yep, you took the words out of my mouth re: the version components. If two components are enough though, then we should totally drop the quotes.

David

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Radek Pietruszewski) #10

I agree — my reasoning was that it’s more like the current iOS availability statement.

Is it? You can do `#available(iOS 9.2, *)` there.

— Radek

···

On 18 Dec 2015, at 21:58, Harlan Haskins via swift-evolution <swift-evolution@swift.org> wrote:

I agree — my reasoning was that it’s more like the current iOS availability statement.

I wonder if the iOS availability statement could use some work too? It’s kinda weird and magical ("why do I have to type that *?")

On Dec 18, 2015, at 3:56 PM, David Farler <dfarler@apple.com <mailto:dfarler@apple.com>> wrote:

I had considered this format but I don't think it reads as well as you'd expect for a version. It kind of makes it seem like each component is an independent argument, each with possibly a different meaning. It makes sense from a parsing point of view but I think we should allow folks to write it the same way they'd write it in normal prose, since it's not much more effort.

David

On Dec 18, 2015, at 12:48, Harlan Haskins <harlan@harlanhaskins.com <mailto:harlan@harlanhaskins.com>> wrote:

How about

#if swift(2, 2, *)
#endif

?

On Dec 18, 2015, at 3:32 PM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :slight_smile:

-Chris

Yep, you took the words out of my mouth re: the version components. If two components are enough though, then we should totally drop the quotes.

David

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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 <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


(David Farler) #11

Chris brought something up that a few of us had discussed in the past: the ambiguity of what the operation does. It's implicitly "current version >= specified version", but I wonder how many people will want to compare otherwise or will assume the comparison is '=='.

We can fix this in two ways:

Option 1: #if swift(<x.y)

or

Option 2: #if swift > x.y

I thought I preferred Option 1 but I think Option 2 reads more how you would expect and somewhat reflects the regular syntax of the language, FWIW. I sketched out both implementations and they're about the same in complexity, so I would suggest Option 2, unless it's a strong goal to keep special sauce in build configurations as "function calls".

Maybe not all of the comparison operators are necessary, but in general this gives some flexibility to arrange checks (newer code at the top or at the bottom) and actually describes what comparison is happening.

David

···

On Dec 18, 2015, at 3:34 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

This feature LGTM, and I also prefer that we drop the quotes. Two levels of version number should be sufficient.

  - Doug

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


(David Farler) #12

Yes, that's right, it is a change but only for this new directive because one of its uses is to control exposure to syntax or API changes. Other build configurations such as 'os' and 'arch' will be unaffected.

I myself wouldn't want build configs to act like the C preprocessor, although that kind of change is probably out of this proposal's scope anyway, IMO.

David

···

On Dec 19, 2015, at 13:48, Michel Fortin <michel.fortin@michelf.ca> wrote:

Le 18 déc. 2015 à 15:22, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

This is a change from how the #if directive currently works. Currently, it's a syntax error to write this:

   #if DEBUG
   @abaraka func test() {}
   #endif

even if DEBUG is false because the content is parsed regardless and @abaraka is not a valid attribute. The syntax inside the #if/#endif must be valid for the parser.

So this proposal implies a change in how #if is parsed. Should it works like the C preprocessor?

--
Michel Fortin
michel.fortin@michel


(Félix Cloutier) #13

I don't really like how different this makes "#if swift" from "#if <anything else>". To me, that would be a violation of the principle of least astonishment.

···

Le 19 déc. 2015 à 17:08:13, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

On Dec 19, 2015, at 13:48, Michel Fortin <michel.fortin@michelf.ca> wrote:

Le 18 déc. 2015 à 15:22, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

This is a change from how the #if directive currently works. Currently, it's a syntax error to write this:

  #if DEBUG
  @abaraka func test() {}
  #endif

even if DEBUG is false because the content is parsed regardless and @abaraka is not a valid attribute. The syntax inside the #if/#endif must be valid for the parser.

So this proposal implies a change in how #if is parsed. Should it works like the C preprocessor?

--
Michel Fortin
michel.fortin@michel

Yes, that's right, it is a change but only for this new directive because one of its uses is to control exposure to syntax or API changes. Other build configurations such as 'os' and 'arch' will be unaffected.

I myself wouldn't want build configs to act like the C preprocessor, although that kind of change is probably out of this proposal's scope anyway, IMO.

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


(David Farler) #14

A bare 2.2 will work. Right now, 2.2.2 won't lex because of a requirement that member access of a numeric literal be named but, if we decide down the road that we really, really need another version component, it wouldn't be a ton of work to give an exception when parsing an #if config.

David

···

On Dec 18, 2015, at 1:09 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

I agree — my reasoning was that it’s more like the current iOS availability statement.

Is it? You can do `#available(iOS 9.2, *)` there.

— Radek

On 18 Dec 2015, at 21:58, Harlan Haskins via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I agree — my reasoning was that it’s more like the current iOS availability statement.

I wonder if the iOS availability statement could use some work too? It’s kinda weird and magical ("why do I have to type that *?")

On Dec 18, 2015, at 3:56 PM, David Farler <dfarler@apple.com <mailto:dfarler@apple.com>> wrote:

I had considered this format but I don't think it reads as well as you'd expect for a version. It kind of makes it seem like each component is an independent argument, each with possibly a different meaning. It makes sense from a parsing point of view but I think we should allow folks to write it the same way they'd write it in normal prose, since it's not much more effort.

David

On Dec 18, 2015, at 12:48, Harlan Haskins <harlan@harlanhaskins.com <mailto:harlan@harlanhaskins.com>> wrote:

How about

#if swift(2, 2, *)
#endif

?

On Dec 18, 2015, at 3:32 PM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

David know this already, but I’m a huge fan of this feature. :slight_smile:

-Chris

Yep, you took the words out of my mouth re: the version components. If two components are enough though, then we should totally drop the quotes.

David

— Radek

On 18 Dec 2015, at 21:22, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello everyone,

For Swift 2.2, I'd like to add the following build configuration to check for the Swift language version. This is meant to be a short proposal, so let's start with a simple example, compiling with the 2.2 compiler:

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

The semantics of the build configuration is, "is the Swift language version at least X?". If it is, the active block is parsed and compiled into your program. Like the other build configuration blocks, this isn't line-based, but break on whole statements and declarations. Unlike the other build configurations, however, the inactive block will not parse or emit syntax errors, so you can include syntax for older Swift language revisions in the same file if you prefer.

It sounds like a lot of folks have been wanting something like this, which is why I'm suggesting it for the Swift 2.2 release. I'm curious to hear your feedback!

Best,
David
_______________________________________________
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 <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


(David Farler) #15

I don't know if I would say it violates the principle of least surprise because it wouldn't actually be a surprise in this case, since it's the whole reason you would choose to use `#if swift` – to ignore irrelevant syntax errors.

The difference is also smaller than you might think. The #else branches in the other build configurations parse because presumably the language's syntax wouldn't change between operating systems or architectures, however they never go through type checking or semantic analysis. For example:

cat -n test.swift

1 #if os(iOS)
2 print("Hello")
3 #else
4 print("Hello")
5 #endif

Compiling for OS X, both branches are valid Swift and would actually type check fine, but:

xcrun -sdk macosx swiftc -dump-ast test.swift

(source_file
  (top_level_code_decl
    (brace_stmt
      (#if_stmt
        (#if:
          (call_expr type='<null>'

...snip -- all null types up to here.

        #else
          (elements
            (top_level_code_decl
              (brace_stmt
                (call_expr type='()'

...snip -- all typed up to here.

So, maybe we should revisit the other build configurations in the future, that it's maybe not worth it to even parse any inactive branches, but I don't think the difference is so strong that we shouldn't reuse the #if syntax for this now.

David

···

On Dec 19, 2015, at 2:17 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I don't really like how different this makes "#if swift" from "#if <anything else>". To me, that would be a violation of the principle of least astonishment.

Le 19 déc. 2015 à 17:08:13, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

On Dec 19, 2015, at 13:48, Michel Fortin <michel.fortin@michelf.ca> wrote:

Le 18 déc. 2015 à 15:22, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

This is a change from how the #if directive currently works. Currently, it's a syntax error to write this:

  #if DEBUG
  @abaraka func test() {}
  #endif

even if DEBUG is false because the content is parsed regardless and @abaraka is not a valid attribute. The syntax inside the #if/#endif must be valid for the parser.

So this proposal implies a change in how #if is parsed. Should it works like the C preprocessor?

--
Michel Fortin
michel.fortin@michel

Yes, that's right, it is a change but only for this new directive because one of its uses is to control exposure to syntax or API changes. Other build configurations such as 'os' and 'arch' will be unaffected.

I myself wouldn't want build configs to act like the C preprocessor, although that kind of change is probably out of this proposal's scope anyway, IMO.

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


(Félix Cloutier) #16

It's not surprising that what's inside an #if swift block isn't compiled, but since it doesn't, it might be surprising that what is inside an #if DEBUG block is compiled, no?

···

Le 19 déc. 2015 à 17:58:35, David Farler <dfarler@apple.com> a écrit :

I don't know if I would say it violates the principle of least surprise because it wouldn't actually be a surprise in this case, since it's the whole reason you would choose to use `#if swift` – to ignore irrelevant syntax errors.

The difference is also smaller than you might think. The #else branches in the other build configurations parse because presumably the language's syntax wouldn't change between operating systems or architectures, however they never go through type checking or semantic analysis. For example:

cat -n test.swift

1 #if os(iOS)
2 print("Hello")
3 #else
4 print("Hello")
5 #endif

Compiling for OS X, both branches are valid Swift and would actually type check fine, but:

xcrun -sdk macosx swiftc -dump-ast test.swift

(source_file
(top_level_code_decl
   (brace_stmt
     (#if_stmt
       (#if:
         (call_expr type='<null>'

...snip -- all null types up to here.

       #else
         (elements
           (top_level_code_decl
             (brace_stmt
               (call_expr type='()'

...snip -- all typed up to here.

So, maybe we should revisit the other build configurations in the future, that it's maybe not worth it to even parse any inactive branches, but I don't think the difference is so strong that we shouldn't reuse the #if syntax for this now.

David

On Dec 19, 2015, at 2:17 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I don't really like how different this makes "#if swift" from "#if <anything else>". To me, that would be a violation of the principle of least astonishment.

Le 19 déc. 2015 à 17:08:13, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

On Dec 19, 2015, at 13:48, Michel Fortin <michel.fortin@michelf.ca> wrote:

Le 18 déc. 2015 à 15:22, David Farler via swift-evolution <swift-evolution@swift.org> a écrit :

#if swift("2.2")
print("Hello")
#else
this code will not parse or emit diagnostics
#endif

This is a change from how the #if directive currently works. Currently, it's a syntax error to write this:

#if DEBUG
@abaraka func test() {}
#endif

even if DEBUG is false because the content is parsed regardless and @abaraka is not a valid attribute. The syntax inside the #if/#endif must be valid for the parser.

So this proposal implies a change in how #if is parsed. Should it works like the C preprocessor?

--
Michel Fortin
michel.fortin@michel

Yes, that's right, it is a change but only for this new directive because one of its uses is to control exposure to syntax or API changes. Other build configurations such as 'os' and 'arch' will be unaffected.

I myself wouldn't want build configs to act like the C preprocessor, although that kind of change is probably out of this proposal's scope anyway, IMO.

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


(Javier Soto) #17

What's the intended most common use case for this? The one that I can think
of that will show up very often is "declare this function only if Swift
version is >= X because it relies on some new feature"
In that case, would it make sense for consistency to also be able to mark a
function (or type) as "only available on Swift >= X", like you do with ios
releases? (ie @available(swift, 2.2))

···

On Sat, Dec 19, 2015 at 1:28 AM David Farler via swift-evolution < swift-evolution@swift.org> wrote:

> On Dec 18, 2015, at 3:34 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>
>>
>> On Dec 18, 2015, at 12:29 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>>>
>>> On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via > swift-evolution <swift-evolution@swift.org> wrote:
>>>
>>> Sounds like it could be super useful for libraries!
>>>
>>> How about we drop the quote marks, though? If we have `os(iOS)` and
`#available(iOS 9, *)` (in other context), why not `swift(2.2)`?
>>
>> I agree with Radek.
>>
>> The argument to use a string is if we wanted to support subversions,
e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string,
because 2.2.1 isn’t a valid floating point literal - the lexer will be
displeased.
>>
>> However, I don’t think we *want* the feature to be able to do that.
The most important use case for this feature is to handle syntactic
differences across swift versions, and we don’t want those in
sub-versions. Given that, it seems better to keep the syntax clean and
simple.
>
> This feature LGTM, and I also prefer that we drop the quotes. Two levels
of version number should be sufficient.
>
> - Doug
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

Chris brought something up that a few of us had discussed in the past: the
ambiguity of what the operation does. It's implicitly "current version >=
specified version", but I wonder how many people will want to compare
otherwise or will assume the comparison is '=='.

We can fix this in two ways:

Option 1: #if swift(<x.y)

or

Option 2: #if swift > x.y

I thought I preferred Option 1 but I think Option 2 reads more how you
would expect and somewhat reflects the regular syntax of the language,
FWIW. I sketched out both implementations and they're about the same in
complexity, so I would suggest Option 2, unless it's a strong goal to keep
special sauce in build configurations as "function calls".

Maybe not all of the comparison operators are necessary, but in general
this gives some flexibility to arrange checks (newer code at the top or at
the bottom) and actually describes what comparison is happening.

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

--
Javier Soto


(Jordan Rose) #18

I don't like either of these. I especially don't like option 2 because it makes "swift" something magic while user flags are still limited to booleans, and I don't think we're likely to change user flags any time soon. But I don't like option 1 either. We didn't do it for "if #available(…)", and I don't think we need to do it here either.

Jordan

···

On Dec 19, 2015, at 1:28 , David Farler via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 3:34 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:29 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

Sounds like it could be super useful for libraries!

How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?

I agree with Radek.

The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.

However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.

This feature LGTM, and I also prefer that we drop the quotes. Two levels of version number should be sufficient.

  - Doug

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

Chris brought something up that a few of us had discussed in the past: the ambiguity of what the operation does. It's implicitly "current version >= specified version", but I wonder how many people will want to compare otherwise or will assume the comparison is '=='.

We can fix this in two ways:

Option 1: #if swift(<x.y)

or

Option 2: #if swift > x.y

I thought I preferred Option 1 but I think Option 2 reads more how you would expect and somewhat reflects the regular syntax of the language, FWIW. I sketched out both implementations and they're about the same in complexity, so I would suggest Option 2, unless it's a strong goal to keep special sauce in build configurations as "function calls".

Maybe not all of the comparison operators are necessary, but in general this gives some flexibility to arrange checks (newer code at the top or at the bottom) and actually describes what comparison is happening.


(Ludovic LANDRY) #19

@felix Swift 3 will stabilize ABI (binary level compatibility) but not the
standard library interfaces (cf. https://github.com/apple/swift-evolution >
Out of Scope > Full source compatibility).

Even is they are stabilized in the future, there can still be some API
added in future Swift versions.

···

On Sat, Dec 19, 2015 at 12:26 PM, Félix Cloutier <swift-evolution@swift.org> wrote:

My understanding is that Swift 3 will stabilize the ABI and the standard
library interfaces. Given that, I'm not sure what you'd use it for either.

Le 19 déc. 2015 à 14:26:24, Javier Soto via swift-evolution < > swift-evolution@swift.org> a écrit :

What's the intended most common use case for this? The one that I can
think of that will show up very often is "declare this function only if
Swift version is >= X because it relies on some new feature"
In that case, would it make sense for consistency to also be able to mark
a function (or type) as "only available on Swift >= X", like you do with
ios releases? (ie @available(swift, 2.2))
On Sat, Dec 19, 2015 at 1:28 AM David Farler via swift-evolution < > swift-evolution@swift.org> wrote:

> On Dec 18, 2015, at 3:34 PM, Douglas Gregor via swift-evolution < >> swift-evolution@swift.org> wrote:
>
>>
>> On Dec 18, 2015, at 12:29 PM, Chris Lattner via swift-evolution < >> swift-evolution@swift.org> wrote:
>>
>>>
>>> On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via >> swift-evolution <swift-evolution@swift.org> wrote:
>>>
>>> Sounds like it could be super useful for libraries!
>>>
>>> How about we drop the quote marks, though? If we have `os(iOS)` and
`#available(iOS 9, *)` (in other context), why not `swift(2.2)`?
>>
>> I agree with Radek.
>>
>> The argument to use a string is if we wanted to support subversions,
e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string,
because 2.2.1 isn’t a valid floating point literal - the lexer will be
displeased.
>>
>> However, I don’t think we *want* the feature to be able to do that.
The most important use case for this feature is to handle syntactic
differences across swift versions, and we don’t want those in
sub-versions. Given that, it seems better to keep the syntax clean and
simple.
>
> This feature LGTM, and I also prefer that we drop the quotes. Two
levels of version number should be sufficient.
>
> - Doug
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

Chris brought something up that a few of us had discussed in the past:
the ambiguity of what the operation does. It's implicitly "current version
>= specified version", but I wonder how many people will want to compare
otherwise or will assume the comparison is '=='.

We can fix this in two ways:

Option 1: #if swift(<x.y)

or

Option 2: #if swift > x.y

I thought I preferred Option 1 but I think Option 2 reads more how you
would expect and somewhat reflects the regular syntax of the language,
FWIW. I sketched out both implementations and they're about the same in
complexity, so I would suggest Option 2, unless it's a strong goal to keep
special sauce in build configurations as "function calls".

Maybe not all of the comparison operators are necessary, but in general
this gives some flexibility to arrange checks (newer code at the top or at
the bottom) and actually describes what comparison is happening.

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

--
Javier Soto _______________________________________________
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

--
Cordialement,
Ludovic Landry


(David Farler) #20

That is a fair point of comparison, although this should work for both statements and declarations, in which case the extra attribute style would be redundant. Maybe the implicit >= is good enough. I'd like to keep it as simple as possible.

David

···

On Dec 19, 2015, at 11:26, Javier Soto <javier.api@gmail.com> wrote:

What's the intended most common use case for this? The one that I can think of that will show up very often is "declare this function only if Swift version is >= X because it relies on some new feature"
In that case, would it make sense for consistency to also be able to mark a function (or type) as "only available on Swift >= X", like you do with ios releases? (ie @available(swift, 2.2))

On Sat, Dec 19, 2015 at 1:28 AM David Farler via swift-evolution <swift-evolution@swift.org> wrote:

> On Dec 18, 2015, at 3:34 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:
>
>>
>> On Dec 18, 2015, at 12:29 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
>>
>>>
>>> On Dec 18, 2015, at 12:25 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:
>>>
>>> Sounds like it could be super useful for libraries!
>>>
>>> How about we drop the quote marks, though? If we have `os(iOS)` and `#available(iOS 9, *)` (in other context), why not `swift(2.2)`?
>>
>> I agree with Radek.
>>
>> The argument to use a string is if we wanted to support subversions, e.g. like “#if swift(2.2.1)”. This requires the parameter to be a string, because 2.2.1 isn’t a valid floating point literal - the lexer will be displeased.
>>
>> However, I don’t think we *want* the feature to be able to do that. The most important use case for this feature is to handle syntactic differences across swift versions, and we don’t want those in sub-versions. Given that, it seems better to keep the syntax clean and simple.
>
> This feature LGTM, and I also prefer that we drop the quotes. Two levels of version number should be sufficient.
>
> - Doug
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

Chris brought something up that a few of us had discussed in the past: the ambiguity of what the operation does. It's implicitly "current version >= specified version", but I wonder how many people will want to compare otherwise or will assume the comparison is '=='.

We can fix this in two ways:

Option 1: #if swift(<x.y)

or

Option 2: #if swift > x.y

I thought I preferred Option 1 but I think Option 2 reads more how you would expect and somewhat reflects the regular syntax of the language, FWIW. I sketched out both implementations and they're about the same in complexity, so I would suggest Option 2, unless it's a strong goal to keep special sauce in build configurations as "function calls".

Maybe not all of the comparison operators are necessary, but in general this gives some flexibility to arrange checks (newer code at the top or at the bottom) and actually describes what comparison is happening.

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

--
Javier Soto