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


(Jon Hull) #1

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()
  }
}


(Vladimir) #2

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jon Hull) #3

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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Charlie Monroe) #4

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@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@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@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


(Vladimir) #5

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@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@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@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