[swift-evolution] [Idea] Set variables to "_" in two-stage init; remove IUO

Vladimir.S svabox at gmail.com
Thu Jun 16 07:37:41 CDT 2016


Yes, using the same example, you can make required init to be convenience init:

class MyBase {
     required init (coder: Int) {

     }

     required init (frame: Int) {

     }
}

class MyClass : MyBase {

     let x:Int
     let y:String
     let z:Double

     private init(isCoder: Bool, _ xValue: Int, _ zValue: Double) {
         // here you can decide what constants should be set for properties

         self.x = xValue
         self.y = (isCoder ? "Coder: " : "Frame: ") + "\(xValue) - \(zValue)"
         self.z = zValue

         if isCoder {
             super.init(coder: 1)
         } else {
             super.init(frame: 2)
         }
     }

     convenience required init (coder: Int) {
         self.init(isCoder: true, 1, 1.0)
     }

     convenience required init (frame: Int) {
         self.init(isCoder: false, 1, 1.0)
     }

    convenience init(x: Int) {
         self.init(isCoder: false, x, 1.0)
    }

    convenience init(z: Double) {
         self.init(isCoder: false, 1, z)
    }
}

print(MyClass(coder: 0).y)
print(MyClass(frame: 0).y)
print(MyClass(x: 10).y)
print(MyClass(z: 10.0).y)


On 16.06.2016 14:37, Charlie Monroe wrote:
> There's nothing stopping you from making init(frame:) and init?(coder:) convenience:
>
> public class ColorView: NSView {
> 	
> 	public required convenience init?(coder: NSCoder) {
> 		self.init(frame: CGRect(x: 0.0, y: 0.0, width: 20.0, height: 20.0))
> 	}
> 	
> 	private convenience override init(frame frameRect: CGRect) {
> 		self.init(color: NSColor.whiteColor())
> 	}
> 	
> 	public init(color: NSColor) {
> 		super.init(frame: CGRect(x: 0.0, y: 0.0, width: 20.0, height: 20.0))
> 	}
> 	
> }
>
> The only drawback is that init?(coder:) will always need to be public since it's `required`.
>
>
>> On Jun 16, 2016, at 1:27 PM, Jonathan Hull via swift-evolution <swift-evolution at swift.org> wrote:
>>
>> Good question/idea.
>>
>> The use case I have with this most often is -initWithCoder and some other init like -initWithFrame.  I don’t think you can make those convenience inits.  If there is a way to make that work though, I am all for it.
>>
>> The thing I do most often, when possible, is lazily set each variable from a closure so that I don’t have to worry about it in the inits.  I find this especially useful for creating subviews/layers.  It isn’t always an option though…
>>
>> Thanks,
>> Jon
>>
>>
>>
>>> On Jun 16, 2016, at 4:19 AM, Vladimir.S <svabox at gmail.com> wrote:
>>>
>>> The question is if we can solve the problem with special private init() and convenience inits ?
>>>
>>> class MyBase {
>>>   init () {
>>>
>>>   }
>>> }
>>>
>>> class MyClass : MyBase {
>>>
>>>   let x:Int
>>>   let y:String
>>>   let z:Double
>>>
>>>   private init(_ xValue: Int, _ zValue: Double) {
>>>       self.x = xValue
>>>       self.y = "\(xValue) - \(zValue)"
>>>       self.z = zValue
>>>
>>>       super.init()
>>>   }
>>>
>>>  convenience override init() {
>>>       self.init(1, 1.0)
>>>  }
>>>
>>>  convenience init(x: Int) {
>>>       self.init(x, 1.0)
>>>  }
>>>
>>>  convenience init(z: Double) {
>>>       self.init(1, z)
>>>  }
>>> }
>>>
>>> print(MyClass().y)
>>> print(MyClass(x: 10).y)
>>> print(MyClass(z: 10.0).y)
>>>
>>> Seems like we can. Any drawbacks?
>>>
>>> On 16.06.2016 9:27, Jonathan Hull via swift-evolution wrote:
>>>> I don’t remember a proposal for that, but I would definitely support one.
>>>> I use this pattern all the time (usually by initializing to a default
>>>> value first), and it would be nice to have an explicit/safe way to handle
>>>> it, (and to avoid waisting cycles creating an object I never use).
>>>>
>>>> Perhaps we should spell it @init or @initHelp:
>>>>
>>>> class MyClass : MySuperClass {
>>>>
>>>>   let x:Int
>>>>   let y:String
>>>>   let z:Double
>>>>
>>>>   @init func commonSetup() {
>>>>       self.y = “My String”
>>>>       self.z = 4.2
>>>>   }
>>>>
>>>>  init(x: Int) {
>>>>       self.x = x
>>>>       commonSetup() //No error because commonSetup() sets the value of
>>>> ‘y’ & ‘z'
>>>>       super.init()
>>>>  }
>>>> }
>>>>
>>>> Basically the @init functions would be inlined into the init.  They would
>>>> only be callable from inits, and could only be called a single time within
>>>> each init.
>>>>
>>>> Thanks,
>>>> Jon
>>>>
>>>>> I believe there was(was?) already a suggestion to introduce special methods
>>>>> that could be called from initializers. IMO this is a better solution to
>>>>> the problem as you really should not call 'usual' instance method until the
>>>>> instance is fully instantiated(super.init() called in your case):
>>>>>
>>>>> class MyClass : MySuperClass {
>>>>>
>>>>> 	let x : Int
>>>>> 	let y : String  //let!
>>>>>
>>>>> 	initfunc calcY(somePatam: Int) -> String {
>>>>> 		return ....
>>>>> 	}
>>>>>
>>>>> 	init(x: Int) {
>>>>> 		self.x = x
>>>>> 		self.y = assignY(5)
>>>>> 		super.init()
>>>>> 	}
>>>>> }
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>


More information about the swift-evolution mailing list