SE-0359: Build-Time Constant Values

Hello Swift community,

The review of SE-0359 "Build-Time Constant Values" begins now and runs through June 6, 2022.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager. When emailing the review manager directly, please keep the proposal link at the top of the message.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/main/process.md

Thank you,

Doug Gregor
Review Manager

17 Likes

Very very quick comment, which I am sure it is an overblown worry Doug can quell super quickly :slight_smile:

Ergonomics of the recently-pitched Foundation.URL would benefit greatly from the ability to require the string argument to be compile-time constant. With evolving compile-time evaluation facilities, Swift may even gain an ability to perform compile-time validation of such URLs even though the user may never be able to express a fully compile-time constant Foundation.URL type because this type is a part of an ABI-stable SDK. While a type like StaticString may be used to require that the argument string must be static, which string is chosen can still be determined at runtime, e.g.:

URL(Bool.random() ? "https://valid.url.com" : "invalid url . com")

Would you see URL not accepting runtime strings that cannot be evaluated at compile time anymore (hope not) or this is having both?

This proposal gave me some faint vibes of “hardcoded strings, hardcoded strings everywhere” (I agree it is a reductive way to look at build time values), but it is very likely an overreaction :). Right?

2 Likes

I interpret the proposal as saying there would be both:

init?(string: String)                 // runtime strings, failable
init(@const _ string: String)         // compile-time strings, non-failable

I think the important difference here is the potential for errors. With a run-time-provided string, you need an optional return (init?) or a throwing initializer so you can report a malformed URL string. With the constant string, you don't have the potential for runtime failures due to bad data, so you want a non-failable, non-throwing initializer.

Doug

10 Likes

+1

I’m a fan of this, and especially for the future directions. In particular, I look forward to compile time computed initializers, which might help out in embedded applications by reducing code size, and proving more opportunities for optimization.

I read through the entire proposal and followed the discussions.

And it simply pleases me that values can be locked down to a no-doubt-about-it unchangeable form.

2 Likes

I think @const parameters will quickly become a nuisance unless some level of inference is available in the same release. The need to write two separate methods will be troublesome, when most are essentially reconst anyway (by analogy to rethrows). It will annoy library authors to have to write double, and will annoy clients even more when one of the two was neglected.

But I like the eventual goal of being able to do @const zero = pow(e, i * pi) + 1 and have nothing right of the = survive into the binary.

6 Likes

Forgive me but would “i” also be a @const in your example? Would this compile in this case or complain i is not uniquely known at build time?

At its declaration elsewhere, i would likely need to be marked @const, yes. (Although we are in future direction territory, which would be open to debate at that time.)

I am missing Optionals in the list of const-able types.

I would expect this to come with build-time evaluation so life will be easier and we can quickly expand the usage. As for now the feature is still too "weak" to be utilized.

I still don’t quite like the idea of an attribute. Is there any reason that we cannot make it a part of the type system? That is, we can have a series of new types called const P (combined using existing any P rules), and, like how we’re using non-async functions as async, allow implicit transformation from const P to P?

Consider the following example:

@propertyWrapper
struct SpecialSerializationSauce {
  init(key: const String) {...}
}

// compiles because string literal is inferred as `const String`
struct Foo {
  @SpecialSerializationSauce(key: "title") 
  var someSpecialTitleProperty: String
}

P.S. If there’re any source-breaking issues, we can delay the const-prioritized inference to Swift 6.

1 Like

+1, I agree with the proposal as written.

Excited about this (I think I'm rather excited about future directions).
Not in-depth study but have been following this topic.

  • This is definitely one of the missing features of Swift.
  • I love how its expression is settled with @ attribution. Just like mentioned in the proposal, it'll allow more flexibility. Also feels Swifty.

Only concern I had was its identifier: const. It felt or read like @const const value ... or @let let value ..., I mean it's only named @const because it was not a reserved word in Swift yet.

Then this, in the proposal was convincing:

... the potential use of this attribute for various optimization purposes also lends itself to indicate the additional immutability guarantees on top of a plain let (which can be initialized with a dynamic value), ...

So with this concept, const is a good balance... I guess (at least, so far.).

Has this changed at all since the pitch?

1 Like

Strong -1.

IMO from having to maintain a large codebase with a mix of developer levels, this is going to turn out very very poorly.

Developers will see @const in the codebase and due to its use in other languages we will very shortly start seeing @const appended to all and every let variable possible.

This keyword is an open invitation to cargo cult programming. Without any particular reason, code reviewers will start saying "add a @const here", because surely it can only be a positive to mark something const. Eventually, all lets will be marked @const, and the sane engineer in the room will start to wonder what's the point of @const let x = 11 when the compiler should have already inferred that.

I strongly believe @const should only be permitted as part of an API requirement to prevent this from happening. And it will happen.

8 Likes

If I understand the proposal correctly, this "feature" adds no new capability to the language. It might, some day, allow for new capabilities, and I think it's best to hold off until those other proposals are ready.

Would the Core Team have accepted a proposal to add async and await keywords without any actual functionality or design for a concurrency system to use them with?

12 Likes

I find this proposal an important step for introducing more compile-time features in Swift.

I just disagree with the decision to not require ‘get’ in protocol declarations. While I understand that it’s somewhat verbose, const member requirements are also not a newly designed feature. All other protocol-member requirements need to have ‘get’, and I don’t think the proposal makes a strong enough case to break away from this pattern. Unless we plan to allow more members to be written without specifying the accessor, this decisions seems to is inconsistent for no good reason.

11 Likes

I think the proposal does a good job of outlining potential future directions, referencing quite popular features (like a constant, result-builder-based package manifest). There also seems to be a strong push by the Foundation team to validate URLs at compile time, so I’m confident this will not end up as a useless feature.

As I wrote, I believe this proposal, which does nothing on its own for the capabilities of the language, should be deferred until a useful feature which requires this capability is at least proposed. Perhaps even pitched.

I find this proposal premature and have reservations along the lines of @ebg's with respect to code evolution between acceptance and the emergence of those "future directions".

7 Likes

+1 for compile time

I agree with the worry that most declarations will become @const let thus this becoming verbose. I would recommend using val for declarations thought I think this can be done after once more of the compile time facilities is available.

Since we have regex literal in review. How could a regex string now be turned into a regex literal using this proposal?

This proposal is self motivating. It brings Swift to feature parity with other languages and improves performance of applications by eliminating runtime cost of static variables.

1 Like

I don't believe this feature can actually deliver on those promises, though. Firstly - what has been proposed by the Foundation team is that URLs specified as string literals will fail at runtime rather than return an optional. So when you write:

let url = URL(string: "http://example.com")!
//                                         ^ ---- This

The force-unwrap is now implicit. That is it. No compile-time validation. You don't write the force-unwrap, but it's like an Array subscript in that it will trap at runtime and crash your app if it fails. The force unwrap is still there.

I mentioned this when the Foundation team posted their pitch - they are talking about this like it is compile-time validation, and people might be mistaken in to thinking that it is, but it isn't. It's a built-in force-unwrap and that can be a pretty significant difference.

Ergonomics of the recently-pitched Foundation.URL would benefit greatly from the ability to require the string argument to be compile-time constant. [...] While a type like StaticString may be used to require that the argument string must be static, which string is chosen can still be determined at runtime, e.g.:

URL(Bool.random() ? "https://valid.url.com" : "invalid url . com")

EDIT: I misunderstood this. It is a (minor) expressivity feature.

But this part doesn't make a huge amount of sense:

With evolving compile-time evaluation facilities, Swift may even gain an ability to perform compile-time validation of such URLs even though the user may never be able to express a fully compile-time constant Foundation.URL type because this type is a part of an ABI-stable SDK.

On the one hand, we can validate URL values at compile time even though it's part of an ABI-stable SDK, but on the other hand, we can't create "fully compile-time constants" because it's part of an ABI-stable SDK?

So... what about if we validate the URL and say it is valid, but that turns out to be a bug? The OS updates, fixes the bug, now it says the URL is invalid -- but we already compiled the code and said it was valid! What are we going to do? Throw the App in to a crash loop? Let it continue with an invalid value?

That may be what happens now, but at least now we return an Optional. We give the user the opportunity to handle errors (or trap, if they decide to), and we don't present any kind of illusion of compile-time validation.

This proposal makes very big promises, but I highly doubt it can deliver on them. It is extremely vague and presents concepts in a misleading way.

11 Likes

I don't believe this is the case. This proposal does not add the compiler optimizations of constant folding and propagation. Those already exist. This proposal simply causes a build failure if the developer wants to enforce the possibility for the compiler to use those optimizations. This proposal does not even provide any guarantees that these optimizations will definitely take place for @const values.

7 Likes