[swift-users] initializer with alternative

Doug Hill swiftusers at breaqz.com
Mon Jul 25 15:41:56 CDT 2016


If your self.init method fails by throwing an exception, the state of the class is essentially unknown. Trying to recover inside the convenience init method by calling another initializer seems problematic since you don't know what the state will be after the second init. Therefor, it's probably more correct to do the exception handling outside of this class like you did in the MakeTestClass function.

But just for the heck of it, I tried taking the second init outside the catch block, and put a flag that something failed. But Swift won't allow any uses of self after the first catch. For example (with errors on the lines the compiler reports):

convenience init( fromFile file:NSURL, fromBackupFile backupFile:NSURL ) throws
{
    var firstInitFailed = false

    do {
        try self.init( fromFile:file ) 
    } catch {
        do {
       	    firstInitFailed = true
		}
	}

    if  firstInitFailed == false {
	try self.init( fromFile:backupFile) // 'self' used inside 'catch' block reachable from self.init call
	}
} // 'self' used inside 'catch' block reachable from self.init call
This might be a bug in the compiler since the error message isn't correct; self isn't referenced in the catch block. Also the error message on the closing brace is puzzling.

In any case, this appears to imply that in Swift you can't do any error recovery that involves self inside of an init method, even if you get an exception from something other than calling self.init. This doesn't seem right if the throw was for something that doesn't affect the object state. For example, if you had a file system call that tried to create 'fromFile' and that call threw an exception. This shouldn't affect anything with class state and should be possible to handle it without affecting object initialization.

The third option is to move this file handling outside of the init method. For example:

convenience init( fromFile file:NSURL, fromBackupFile backupFile:NSURL ) throws
{
    try self.init(fromFile: file)

    self.openFile(fromFile: file, fromBackupFile: backupFile)
}

func openFile( fromFile file:NSURL, fromBackupFile backupFile:NSURL )
{
    do {
        // try to open the fromFile
    } catch {
        do {
            // try to open the backupFile
        }
    }
}

However, this changes the class' init behavior since the designated initializer can't do the file opening/handling. I'm guessing your best bet is going with the separate function to handle this. Or make it a type method.

Doug Hill



> On Jul 25, 2016, at 10:46 AM, J.E. Schotsman via swift-users <swift-users at swift.org> wrote:
> 
> Hello,
> 
> I have a class that can be initialized from a file.
> I would like to add a convenience init that uses a backup file if necessary.
> Writing a function for this is easy, but I can’t manage to turn this into an init function.
> 
> import Foundation
> 
> class TestClass
> 	{
> 	init( fromFile file:NSURL ) throws
> 		{
> 		
> 		}
> 	
> 	convenience init( fromFile file:NSURL, fromBackupFile backupFile:NSURL ) throws
> 		{
> 		do { try self.init( fromFile:file ) }
> 		catch {
> 			do { try self.init( fromFile:backupFile ) } // error: 'self' used inside 'catch' block reachable from self.init call
> 			}
> 		}
> 	}
> 
> func MakeTestClass( fromFile file:NSURL, fromBackupFile backupFile:NSURL ) throws -> TestClass
> 	{
> 	do { return try TestClass( fromFile:file ) } 
> 	catch { do { return try TestClass( fromFile:backupFile ) } } 
> 	}
> 
> Any suggestions?

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160725/8b67dbc9/attachment.html>


More information about the swift-users mailing list