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


(Karl) #1

Say you have the following code. There is a property on MyClass (‘y’) which is derived from other data via an instance method; Two-stage initialisation.

class MySuperClass {
  init() {}
}

class MyClass : MySuperClass {

  let x : Int
  var y : String

  init(x: Int) {

    self.x = x
    super.init()
    y = someInstanceMethod()
  }
}

The code won’t compile because you call super.init before initialising all properties. The way to work-around this so far is to make the type of ‘y’ an implicitly-unwrapped optional. I don’t think it’s very elegant to have to change the type of ‘y’ in this case - it exposes implementation details and implies that the value may sometimes be nil, which is not the case.

What about if we allowed you to explicitly declare that it’s okay for ‘y’ not to be initialised before calling super.init? Perhaps by assigning it to the underscore:

self.x = x
y = _
super.init()
y = someInstanceMethod()

'y' would still effectively work as an implicitly-unwrapped optional - the value would be initialised to nil, and any attempt to use it before it is initialised would be a fatal runtime error as with an IUO. This also means that it couldn’t be a “let” value.

This change wouldn’t give you any additional safety when using two-stage initialisation; it would simply not require you to change the type of the property when doing so.

Thoughts?

Karl


(Charlie Monroe) #2

Is there a particular reason for not using lazy var here?

class MySuperClass {
  init() {}
}

class MyClass : MySuperClass {

  let x: Int
  lazy var y: String = self.someInstanceMethod()

  init(x: Int) {
    self.x = x
    super.init()
  }

  func someInstanceMethod() -> String {
    return "Kaboom"
  }
}

···

On Jun 15, 2016, at 2:22 PM, Karl via swift-evolution <swift-evolution@swift.org> wrote:

Say you have the following code. There is a property on MyClass (‘y’) which is derived from other data via an instance method; Two-stage initialisation.

class MySuperClass {
  init() {}
}

class MyClass : MySuperClass {

  let x : Int
  var y : String

  init(x: Int) {

    self.x = x
    super.init()
    y = someInstanceMethod()
  }
}

The code won’t compile because you call super.init before initialising all properties. The way to work-around this so far is to make the type of ‘y’ an implicitly-unwrapped optional. I don’t think it’s very elegant to have to change the type of ‘y’ in this case - it exposes implementation details and implies that the value may sometimes be nil, which is not the case.

What about if we allowed you to explicitly declare that it’s okay for ‘y’ not to be initialised before calling super.init? Perhaps by assigning it to the underscore:

self.x = x
y = _
super.init()
y = someInstanceMethod()

'y' would still effectively work as an implicitly-unwrapped optional - the value would be initialised to nil, and any attempt to use it before it is initialised would be a fatal runtime error as with an IUO. This also means that it couldn’t be a “let” value.

This change wouldn’t give you any additional safety when using two-stage initialisation; it would simply not require you to change the type of the property when doing so.

Thoughts?

Karl
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #3

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

···

On 15.06.2016 15:22, Karl via swift-evolution wrote:

Say you have the following code. There is a property on MyClass (‘y’)
which is derived from other data via an instance method; Two-stage
initialisation.

class MySuperClass { init() {} }

class MyClass : MySuperClass {

let x : Int var y : String

init(x: Int) {

self.x = x super.init() y = someInstanceMethod() } }

The code won’t compile because you call super.init before initialising
all properties. The way to work-around this so far is to make the type
of ‘y’ an implicitly-unwrapped optional. I don’t think it’s very elegant
to have to change the type of ‘y’ in this case - it exposes
implementation details and implies that the value may sometimes be nil,
which is not the case.

What about if we allowed you to explicitly declare that it’s okay for
‘y’ not to be initialised before calling super.init? Perhaps by
assigning it to the underscore:

self.x = x y = _ super.init() y = someInstanceMethod()

'y' would still effectively work as an implicitly-unwrapped optional -
the value would be initialised to nil, and any attempt to use it before
it is initialised would be a fatal runtime error as with an IUO. This
also means that it couldn’t be a “let” value.

This change wouldn’t give you any additional safety when using two-stage
initialisation; it would simply not require you to change the type of
the property when doing so.

Thoughts?

Karl _______________________________________________ swift-evolution
mailing list swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Karl) #4

Maybe there are several initialisers, with different ways of calculating 'y' depending on what you give it.
  
Karl

···

  
On Jun 15, 2016 at 2:26 PM, <Charlie Monroe (mailto:charlie@charliemonroe.net)> wrote:
  
Is there a particular reason for not using lazy var here?

class MySuperClass {
init() {}
}

class MyClass : MySuperClass {

let x: Int
lazy var y: String = self.someInstanceMethod()

init(x: Int) {
self.x = x
super.init()
}

func someInstanceMethod() -> String {
return "Kaboom"
}
}

> On Jun 15, 2016, at 2:22 PM, Karl via swift-evolution <swift-evolution@swift.org (mailto:swift-evolution@swift.org)> wrote:
>
> Say you have the following code. There is a property on MyClass (‘y’) which is derived from other data via an instance method; Two-stage initialisation.
>
> class MySuperClass {
> init() {}
> }
>
> class MyClass : MySuperClass {
>
> let x : Int
> var y : String
>
> init(x: Int) {
>
> self.x = x
> super.init()
> y = someInstanceMethod()
> }
> }
>
> The code won’t compile because you call super.init before initialising all properties. The way to work-around this so far is to make the type of ‘y’ an implicitly-unwrapped optional. I don’t think it’s very elegant to have to change the type of ‘y’ in this case - it exposes implementation details and implies that the value may sometimes be nil, which is not the case.
>
> What about if we allowed you to explicitly declare that it’s okay for ‘y’ not to be initialised before calling super.init? Perhaps by assigning it to the underscore:
>
> self.x = x
> y = _
> super.init()
> y = someInstanceMethod()
>
> 'y' would still effectively work as an implicitly-unwrapped optional - the value would be initialised to nil, and any attempt to use it before it is initialised would be a fatal runtime error as with an IUO. This also means that it couldn’t be a “let” value.
>
> This change wouldn’t give you any additional safety when using two-stage initialisation; it would simply not require you to change the type of the property when doing so.
>
> Thoughts?
>
> Karl
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org (mailto:swift-evolution@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution