Failable-initializer problems: mistake in book, possible compiler bug

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Failable-initializer problems: mistake in book, possible compiler bug

Jens Alfke
I’m trying to figure out the rules for stored-property initialization and failable initializers, specifically how the heck I can have an initializer fail when its class contains stored properties with no default values. In doing so I’ve found mistake in an example the Swift Language book, and possibly a problem with the compiler.

So. The “Failable Initializers For Classes” section of the book* gives the following example of how to satisfy the requirement that all properties of a class have to have a value before the initializer can return nil:

class Product {
    let name: String!
    init?(name: String) {
        self.name = name
        if name.isEmpty { return nil }
    }
}

It then says “This default value of nil in turn means that all of the properties introduced by the Product class have a valid initial value. As a result, the failable initializer for Product can trigger an initialization failure at the start of the initializer if it is passed an empty string, before assigning a specific value to the name property within the initializer.”

But this is wrong: The example does not fail before assigning a specific value to ‘name’. It fails afterwards. As a result it isn’t even necessary in the example to make ‘name’ explicitly unwrapped: you can take out the “!” and it still compiles.

To fix the example so it demonstrates what it means to demonstrate, swap the two lines in the initializer, so the nil return occurs before the assignment to self.name. Unfortunately, it then fails to compile!

class Product {
    let name: String!
    init?(name: String) {
        if name.isEmpty { return nil } // <—Error!
        self.name = name
    }
}

The “return nil” statement is flagged with the error "All stored properties of a class instance must be initialized before returning nil from an initializer”. As far as I can tell, this error is wrong, because the ‘name’ property has a valid initial value of nil.

And worse, my actual code is running into the same error, so I can’t figure out how to make my initializer failable.

(I’m using the brand-new Xcode 6.3.2 on OS X 10.10.4 14E17e, btw.)

—Jens

* It’d be really nice if the Swift books had numbered sections, since they have no stable page numbers to refer to things by.

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/4A180E58-709C-424A-8D9D-7D80309D4DFF%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Failable-initializer problems: mistake in book, possible compiler bug

Chris Lattner

On May 19, 2015, at 12:12 PM, Jens Alfke <[hidden email]> wrote:

I’m trying to figure out the rules for stored-property initialization and failable initializers, specifically how the heck I can have an initializer fail when its class contains stored properties with no default values. In doing so I’ve found mistake in an example the Swift Language book, and possibly a problem with the compiler.

So. The “Failable Initializers For Classes” section of the book* gives the following example of how to satisfy the requirement that all properties of a class have to have a value before the initializer can return nil:

class Product {
    let name: String!
    init?(name: String) {
        self.name = name
        if name.isEmpty { return nil }
    }
}

It then says “This default value of nil in turn means that all of the properties introduced by the Product class have a valid initial value. As a result, the failable initializer for Product can trigger an initialization failure at the start of the initializer if it is passed an empty string, before assigning a specific value to the name property within the initializer.”

But this is wrong: The example does not fail before assigning a specific value to ‘name’. It fails afterwards. As a result it isn’t even necessary in the example to make ‘name’ explicitly unwrapped: you can take out the “!” and it still compiles.

This is a case where the book is out of sync with language changes that went into Xcode 6.3.  The recommended pattern for this is to turn the ‘let’ into a ‘var'.

-Chris

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/CC060E1E-BDE9-42CC-9C52-799B49C9C904%40apple.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Failable-initializer problems: mistake in book, possible compiler bug

Jens Alfke

On May 19, 2015, at 5:25 PM, Chris Lattner <[hidden email]> wrote:

This is a case where the book is out of sync with language changes that went into Xcode 6.3.  The recommended pattern for this is to turn the ‘let’ into a ‘var'.

What are those language changes? From my experimentation, the compiler's are-all-properties-initialized test just seems broken. (Or at best, totally unintuitive.)

I don’t want to change properties into vars just because they need one-time initialization. I want them immutable, dammit.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/126CC126-08B2-457E-A0E0-1430727470B1%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Failable-initializer problems: mistake in book, possible compiler bug

Chris Lattner
On May 19, 2015, at 8:01 PM, Jens Alfke <[hidden email]> wrote:
On May 19, 2015, at 5:25 PM, Chris Lattner <[hidden email]> wrote:

This is a case where the book is out of sync with language changes that went into Xcode 6.3.  The recommended pattern for this is to turn the ‘let’ into a ‘var'.

What are those language changes? From my experimentation, the compiler's are-all-properties-initialized test just seems broken. (Or at best, totally unintuitive.)

The most relevant change is that any let value may only be initialized, they cannot be reassigned in any circumstances.  In Swift 1.1 and earlier, there was an interesting loophole that allowed let properties to be multiply assigned within an initializer.

As part of this change, default initialization of optional let properties was suppressed: if it weren’t, you could never provide the value you want (it would be initialized to nil always).

I don’t want to change properties into vars just because they need one-time initialization. I want them immutable, dammit.

I understand.  The “all properties must be initialized before failing” is an unfortunate limitation that we’re eager to fix for a number of reasons.  In case it isn’t clear, we consider it a short-coming, not a feature.

-Chris

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/53254332-F583-4A2F-AEF6-A8B792232FF6%40apple.com.
For more options, visit https://groups.google.com/d/optout.