Initializers


(Victor Petrescu) #1

Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the last
10 years or so and lately I had the chance to try swift. I have a
suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please
redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being
totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

*Now... I see the use of this. It ensure that all members are initialized.
For example if A had a private variable (another strange choice here with
what private means in swift but I haven't thought on it yet so... maybe is
a cool choice), the B init could not initialize it. I also understand that
the cases when you need this minor performance gain are rather rare (but
they do still exist). So I guess the choice for the super.init() had that
reasoning.*
Still... my suggestion would be to give a warning, maybe force a key word
before the init (like iKnowWhatImDoing init() {}), THEN in case vars are
still not inited give a runtime error (afaik Objective C for example gives
a warning). That ensures everything is ok and also allows programmers that
have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before
also... If this was discussed before can you please point me to the
discussion? I like to understand the choices for the tools I use.

P.S. Please excuse any grammatical errors... English is not my first
language.

Thank you for your time and have a great day,
Petrescu Victor


(Jaden Geller) #2

It seems to me that A should provide an `init(x: Int = 1) { self.x = x }` initializer in such case so B may call `super.init(x: 2)`. This initializer could even be made internal if necessary, but it honestly seems weird for a superclass to default initialize to a certain value and a subclass to default initialize to another.

Regardless, I definitely don’t think introducing unsafely is the right choice. If anything, there ought to be a compiler optimization (if there isn’t one already) that’ll eliminate these duplicate assignments—and I would bet there is if `super.init()` can be inlined.

···

On Jan 28, 2017, at 10:07 AM, Victor Petrescu via swift-evolution <swift-evolution@swift.org> wrote:

Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the last 10 years or so and lately I had the chance to try swift. I have a suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

Now... I see the use of this. It ensure that all members are initialized. For example if A had a private variable (another strange choice here with what private means in swift but I haven't thought on it yet so... maybe is a cool choice), the B init could not initialize it. I also understand that the cases when you need this minor performance gain are rather rare (but they do still exist). So I guess the choice for the super.init() had that reasoning.

Still... my suggestion would be to give a warning, maybe force a key word before the init (like iKnowWhatImDoing init() {}), THEN in case vars are still not inited give a runtime error (afaik Objective C for example gives a warning). That ensures everything is ok and also allows programmers that have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before also... If this was discussed before can you please point me to the discussion? I like to understand the choices for the tools I use.

P.S. Please excuse any grammatical errors... English is not my first language.

Thank you for your time and have a great day,
Petrescu Victor
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Robert Widmann) #3

This seems to contradict Swift’s goal of being safe by default <https://swift.org/about/>, no? It would make me incredibly uncomfortable if there were a backdoor in DI, even if that backdoor emitted traps when it fails.

···

On Jan 28, 2017, at 1:07 PM, Victor Petrescu via swift-evolution <swift-evolution@swift.org> wrote:

Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the last 10 years or so and lately I had the chance to try swift. I have a suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

Now... I see the use of this. It ensure that all members are initialized. For example if A had a private variable (another strange choice here with what private means in swift but I haven't thought on it yet so... maybe is a cool choice), the B init could not initialize it. I also understand that the cases when you need this minor performance gain are rather rare (but they do still exist). So I guess the choice for the super.init() had that reasoning.

Still... my suggestion would be to give a warning, maybe force a key word before the init (like iKnowWhatImDoing init() {}), THEN in case vars are still not inited give a runtime error (afaik Objective C for example gives a warning). That ensures everything is ok and also allows programmers that have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before also... If this was discussed before can you please point me to the discussion? I like to understand the choices for the tools I use.

P.S. Please excuse any grammatical errors... English is not my first language.

Thank you for your time and have a great day,
Petrescu Victor
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(John McCall) #4

Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the last 10 years or so and lately I had the chance to try swift. I have a suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

Now... I see the use of this. It ensure that all members are initialized. For example if A had a private variable (another strange choice here with what private means in swift but I haven't thought on it yet so... maybe is a cool choice), the B init could not initialize it. I also understand that the cases when you need this minor performance gain are rather rare (but they do still exist). So I guess the choice for the super.init() had that reasoning.

Still... my suggestion would be to give a warning, maybe force a key word before the init (like iKnowWhatImDoing init() {}), THEN in case vars are still not inited give a runtime error (afaik Objective C for example gives a warning). That ensures everything is ok and also allows programmers that have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before also... If this was discussed before can you please point me to the discussion? I like to understand the choices for the tools I use.

What problem are you trying to solve here? Are you annoyed at having to write super.init() and/or initialize your instance variables instead of having the compiler "do the right thing" automatically, or are you worried that calling super.init() will be a small but unnecessary expense at runtime? Because these seem like completely different problems that should be addressed in completely different ways.

John.

···

On Jan 28, 2017, at 1:07 PM, Victor Petrescu via swift-evolution <swift-evolution@swift.org> wrote:

P.S. Please excuse any grammatical errors... English is not my first language.

Thank you for your time and have a great day,
Petrescu Victor
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Sweeris) #5

IIUC, it wouldn’t contradict that goal if the compiler could guarantee that everything still gets initialized. I don’t know how that would work with classes that have private/fileprivate properties, though. If you’re subclassing something from the same project, the compiler could just look, but seeing as how exposing those things would kinda defeat the purpose, I don’t think there’s an existing mechanism for it to check 3rd party classes. Maybe we could add a flag to classes’ binary format indicating whether it’s possible for the compiler to infer if super.init() can be safely skipped?

I don’t have a opinion yet on whether this proposal is a good idea… I’m just commenting on (my understanding of) Swift’s safety goals.

- Dave Sweeris

···

On Jan 30, 2017, at 12:36 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

This seems to contradict Swift’s goal of being safe by default <https://swift.org/about/>, no?


(Joe Groff) #6

There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first.

-Joe

···

On Jan 30, 2017, at 12:36 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

This seems to contradict Swift’s goal of being safe by default, no? It would make me incredibly uncomfortable if there were a backdoor in DI, even if that backdoor emitted traps when it fails.


(David Hart) #7

This seems to contradict Swift’s goal of being safe by default, no? It would make me incredibly uncomfortable if there were a backdoor in DI, even if that backdoor emitted traps when it fails.

There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first.

And we've been trying to close that door :door: :slight_smile:

···

On 30 Jan 2017, at 23:08, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 30, 2017, at 12:36 PM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

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


(Victor Petrescu) #8

I also thought at most of the issues presented before making the
suggestion. Let me adress each one (in the order of how I see their
importance) and explain my point of view:

1. Most inportant - safety: As Robert Widmann (and others) pointed out
swift is safe by default. And I love that about swift. Is the main reason I
migrated towards it. Still, I highlight the "by default" part. I am
suggesting adding a little keyword to explicit say that the developer
doesn't want to call the parent init() (let's say that keyword is 'exp').
This means my B class would become something like this:

class B:A {
    exp override init() {
        x = 2;
    }
}

This way swift still remains safe by default. A developer can still be sure
that everything is safe unless he explicitly choosed to wave that safety
for a little performance boost. Imo, that should be the developers choice.

2. Private variables: Well... those are a pain. David Sweeris idea of a
flag sounds nice to me, but I don't know if there would be any undesired
consequences for this. Basically if that flag is not set and 'exp' a
compile error is shown.

3. Regarding the 3 points made by Jaded Geller:
    - Safety (see point 1.)
    - Compiler optimization to eliminate duplicate: If this is
possible/exists it would/is totally solving the issue in an elegant way. In
my test it appeared it does not exist. Is it possible to make compiler skip
the x = 1 line (personally I can't see how but maybe someone can prove me
wrong - I would really love that because it would be exactly what I need)?
    - Regarding the workaround proposed: Yes, it works in the simple
particular case I exposed, but in real life cases is not practical (imagine
you have 30 variables).

4. Joe Groff says there is already a backdoor of sorts ("There already is a
backdoor of sorts. This is one of the intended use cases for
implicitly-unwrapped optionals. If you don't want to be hassled by DI,
declare a property as T! type, and it will be implicitly initialized to
nil, and trap if you try to use it as an unwrapped T without initializing
it first."): I'm assuming by T you mean generics. If that is true that may
already solve the problem but... generics are a new concept for me (first
time I really encountered and used them is now, in swift) but to my
understanding their role is to deal with cases you don't know the type. Can
you please show how to use this to work around the posted issue?

Sidenote: There may be another workaround using optionals (Joe Groff answer
made it pop in my mind) but... I know the type and value for the variable,
it is not optional or nil. Unwrapping each time someone needs it does not
look like the best solution to me.
Sidenote: Is not that strange to have a superclass to initialize to
something then the subclass to anothe value (I had multiple real cases like
this where it was helpful - example carFuel a few years back -> most cars
work on gas, but then electric cars started to raise; it is helpful to have
130 brands of cars that extends from a general brand that have carFuel as
'gas', and Tesla (for example) that inits it to 'electric'). The example I
originally posted, and the one posted in this sidenote where intentionally
oversimplified to expose the case.

P.S. Sorry for any grammatical errors and thank you for your time.

Have a great day,
Petrescu Victor

···

On Mon, Jan 30, 2017 at 10:36 PM, Robert Widmann <devteam.codafi@gmail.com> wrote:

This seems to contradict Swift’s goal of being safe by default
<https://swift.org/about/>, no? It would make me incredibly
uncomfortable if there were a backdoor in DI, even if that backdoor emitted
traps when it fails.

On Jan 28, 2017, at 1:07 PM, Victor Petrescu via swift-evolution < > swift-evolution@swift.org> wrote:

Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the
last 10 years or so and lately I had the chance to try swift. I have a
suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please
redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being
totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

*Now... I see the use of this. It ensure that all members are initialized.
For example if A had a private variable (another strange choice here with
what private means in swift but I haven't thought on it yet so... maybe is
a cool choice), the B init could not initialize it. I also understand that
the cases when you need this minor performance gain are rather rare (but
they do still exist). So I guess the choice for the super.init() had that
reasoning.*
Still... my suggestion would be to give a warning, maybe force a key word
before the init (like iKnowWhatImDoing init() {}), THEN in case vars are
still not inited give a runtime error (afaik Objective C for example gives
a warning). That ensures everything is ok and also allows programmers that
have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before
also... If this was discussed before can you please point me to the
discussion? I like to understand the choices for the tools I use.

P.S. Please excuse any grammatical errors... English is not my first
language.

Thank you for your time and have a great day,
Petrescu Victor
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Victor Petrescu) #9

@John McCall The expense at runtime issue of course. The fact that I need
to add one more line would never bother me enough to bother a few hundreds
ppl in turn :).

···

On Tue, Jan 31, 2017 at 9:51 PM, John McCall <rjmccall@apple.com> wrote:

On Jan 28, 2017, at 1:07 PM, Victor Petrescu via swift-evolution < > swift-evolution@swift.org> wrote:
Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the
last 10 years or so and lately I had the chance to try swift. I have a
suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please
redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being
totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

*Now... I see the use of this. It ensure that all members are initialized.
For example if A had a private variable (another strange choice here with
what private means in swift but I haven't thought on it yet so... maybe is
a cool choice), the B init could not initialize it. I also understand that
the cases when you need this minor performance gain are rather rare (but
they do still exist). So I guess the choice for the super.init() had that
reasoning.*

Still... my suggestion would be to give a warning, maybe force a key word
before the init (like iKnowWhatImDoing init() {}), THEN in case vars are
still not inited give a runtime error (afaik Objective C for example gives
a warning). That ensures everything is ok and also allows programmers that
have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before
also... If this was discussed before can you please point me to the
discussion? I like to understand the choices for the tools I use.

What problem are you trying to solve here? Are you annoyed at having to
write super.init() and/or initialize your instance variables instead of
having the compiler "do the right thing" automatically, or are you worried
that calling super.init() will be a small but unnecessary expense at
runtime? Because these seem like completely different problems that should
be addressed in completely different ways.

John.

P.S. Please excuse any grammatical errors... English is not my first
language.

Thank you for your time and have a great day,
Petrescu Victor
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(John McCall) #10

@John McCall The expense at runtime issue of course. The fact that I need to add one more line would never bother me enough to bother a few hundreds ppl in turn :).

Are you under the impression that the compiler is unable to inline the super.init() call?

John.

···

On Jan 31, 2017, at 3:13 PM, Victor Petrescu <victor.petrescu13@gmail.com> wrote:

On Tue, Jan 31, 2017 at 9:51 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Jan 28, 2017, at 1:07 PM, Victor Petrescu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

My name is Victor, been a developer (C, delphi, php, java, js) for the last 10 years or so and lately I had the chance to try swift. I have a suggestion/question regarding initializers.

Sidenote: If this is not the correct mailing list for this can you please redirect me to the right place?

Consider the following 2 classes and code:

class A {
     var x:Int

     init() {
         x = 1
     }
}

class B : A {
    override init() {
         super.init() // Swift FORCES this call
         x = 2
    }
}

var a:B
for i in 0...99999999 {
    a = B() // Whatever... some code that inits B.
}

This results in 99999999 x = 1 then 99999999 x = 2... the x = 1 being totally useless in this particular case.

In this case, if you don't make the super init you get a compile error.

Now... I see the use of this. It ensure that all members are initialized. For example if A had a private variable (another strange choice here with what private means in swift but I haven't thought on it yet so... maybe is a cool choice), the B init could not initialize it. I also understand that the cases when you need this minor performance gain are rather rare (but they do still exist). So I guess the choice for the super.init() had that reasoning.

Still... my suggestion would be to give a warning, maybe force a key word before the init (like iKnowWhatImDoing init() {}), THEN in case vars are still not inited give a runtime error (afaik Objective C for example gives a warning). That ensures everything is ok and also allows programmers that have strange cases to treat them accordingly.

Anyway... that would be my suggestion. Maybe this was discussed before also... If this was discussed before can you please point me to the discussion? I like to understand the choices for the tools I use.

What problem are you trying to solve here? Are you annoyed at having to write super.init() and/or initialize your instance variables instead of having the compiler "do the right thing" automatically, or are you worried that calling super.init() will be a small but unnecessary expense at runtime? Because these seem like completely different problems that should be addressed in completely different ways.

John.

P.S. Please excuse any grammatical errors... English is not my first language.

Thank you for your time and have a great day,
Petrescu Victor
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #11

You don't need to understand generics to use implicitly-unwrapped optionals. By `T!` I was referring to the syntax used to represent them; you would write Int! or String! or whatever in your code. For your example, this would let you avoid having to invoke super.init() before resetting `x`:

class A {
     var x:Int! // Int! is nil by default
}

class B : A {
    override init() {
         x = 2 // So we can set it here w/o super.init first
    }
}

print(B().x + 1) // and we don't need to explicitly unwrap it to use it, unlike `Int?`

You're giving up the static guarantee that `x` has a value, so you'll get a runtime error if you try to use it before it's initialized, but that's the same situation you have in Java, where dereferencing an uninitialized object reference gives an NPE. Whether you want the hard guarantee that `x` is never optional from the compiler, or the convenience of leaving that up to runtime checks, is a call you have to make; Swift defaults to the strong guarantee, but implicitly-unwrapped optional types like Int! are intended to give you an out if the static model is too strict or inefficient.

-Joe

···

On Jan 31, 2017, at 3:52 AM, Victor Petrescu via swift-evolution <swift-evolution@swift.org> wrote:

4. Joe Groff says there is already a backdoor of sorts ("There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first."): I'm assuming by T you mean generics. If that is true that may already solve the problem but... generics are a new concept for me (first time I really encountered and used them is now, in swift) but to my understanding their role is to deal with cases you don't know the type. Can you please show how to use this to work around the posted issue?

Sidenote: There may be another workaround using optionals (Joe Groff answer made it pop in my mind) but... I know the type and value for the variable, it is not optional or nil. Unwrapping each time someone needs it does not look like the best solution to me.


(Rod Brown) #12

Hi Joe,

I think this comes back to the idea that a lot of people in the wider Swift community hold that Implicitly Unwrapped Optionals are “bad” and “discouraged", and therefore shouldn’t be used. There seems to have been much pushback on Implicitly Unwrapped Optionals in the Swift 3 timeframe, to try and remove them as much as possible.

I definitely see this as a valuable use for them. While an integer is an extremely lightweight example of this, when it could include creating entire object graphs multiple times due to initialiser behaviour, or because you won’t know the correct state of a variable until *after* initialisation has occurred on the superclass, this is a valuable example where IUOs are really the only alternative for performance or correctness reasons.

Perhaps this is an area where the Swift Core Team could provide guidance to the community? Do the Core Team see IUOs as “bad” outright, and destined to go away when possible, or are they a tool with specific uses that look to be supported into the future?

- Rod

···

On 4 Feb 2017, at 5:40 am, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 31, 2017, at 3:52 AM, Victor Petrescu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

4. Joe Groff says there is already a backdoor of sorts ("There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first."): I'm assuming by T you mean generics. If that is true that may already solve the problem but... generics are a new concept for me (first time I really encountered and used them is now, in swift) but to my understanding their role is to deal with cases you don't know the type. Can you please show how to use this to work around the posted issue?

Sidenote: There may be another workaround using optionals (Joe Groff answer made it pop in my mind) but... I know the type and value for the variable, it is not optional or nil. Unwrapping each time someone needs it does not look like the best solution to me.

You don't need to understand generics to use implicitly-unwrapped optionals. By `T!` I was referring to the syntax used to represent them; you would write Int! or String! or whatever in your code. For your example, this would let you avoid having to invoke super.init() before resetting `x`:

class A {
     var x:Int! // Int! is nil by default
}

class B : A {
    override init() {
         x = 2 // So we can set it here w/o super.init first
    }
}

print(B().x + 1) // and we don't need to explicitly unwrap it to use it, unlike `Int?`

You're giving up the static guarantee that `x` has a value, so you'll get a runtime error if you try to use it before it's initialized, but that's the same situation you have in Java, where dereferencing an uninitialized object reference gives an NPE. Whether you want the hard guarantee that `x` is never optional from the compiler, or the convenience of leaving that up to runtime checks, is a call you have to make; Swift defaults to the strong guarantee, but implicitly-unwrapped optional types like Int! are intended to give you an out if the static model is too strict or inefficient.

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


(Jean-Daniel) #13

Hi Joe,

I think this comes back to the idea that a lot of people in the wider Swift community hold that Implicitly Unwrapped Optionals are “bad” and “discouraged", and therefore shouldn’t be used. There seems to have been much pushback on Implicitly Unwrapped Optionals in the Swift 3 timeframe, to try and remove them as much as possible.

I definitely see this as a valuable use for them. While an integer is an extremely lightweight example of this, when it could include creating entire object graphs multiple times due to initialiser behaviour, or because you won’t know the correct state of a variable until *after* initialisation has occurred on the superclass, this is a valuable example where IUOs are really the only alternative for performance or correctness reasons.

IUO are useful to workaround poorly designed class. As already said, you example could be rewrite like follow to avoid any useless computation

class A {
  let x: Int
  init(_ x: Int = 3) {
    self.x = x
  }
}

class B : A {
  override init() {
    …
    super.init(1)
  }
}

No useless initialization of x, and no need to use IUO. Is it a suffisent reason to keep them in the language ? Anyway, as long as we need them to usefully use IBOutlet, I’m pretty sure they are not going anywhere.

···

Le 4 févr. 2017 à 16:52, Rod Brown via swift-evolution <swift-evolution@swift.org> a écrit :

Perhaps this is an area where the Swift Core Team could provide guidance to the community? Do the Core Team see IUOs as “bad” outright, and destined to go away when possible, or are they a tool with specific uses that look to be supported into the future?

- Rod

On 4 Feb 2017, at 5:40 am, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 31, 2017, at 3:52 AM, Victor Petrescu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

4. Joe Groff says there is already a backdoor of sorts ("There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first."): I'm assuming by T you mean generics. If that is true that may already solve the problem but... generics are a new concept for me (first time I really encountered and used them is now, in swift) but to my understanding their role is to deal with cases you don't know the type. Can you please show how to use this to work around the posted issue?

Sidenote: There may be another workaround using optionals (Joe Groff answer made it pop in my mind) but... I know the type and value for the variable, it is not optional or nil. Unwrapping each time someone needs it does not look like the best solution to me.

You don't need to understand generics to use implicitly-unwrapped optionals. By `T!` I was referring to the syntax used to represent them; you would write Int! or String! or whatever in your code. For your example, this would let you avoid having to invoke super.init() before resetting `x`:

class A {
     var x:Int! // Int! is nil by default
}

class B : A {
    override init() {
         x = 2 // So we can set it here w/o super.init first
    }
}

print(B().x + 1) // and we don't need to explicitly unwrap it to use it, unlike `Int?`

You're giving up the static guarantee that `x` has a value, so you'll get a runtime error if you try to use it before it's initialized, but that's the same situation you have in Java, where dereferencing an uninitialized object reference gives an NPE. Whether you want the hard guarantee that `x` is never optional from the compiler, or the convenience of leaving that up to runtime checks, is a call you have to make; Swift defaults to the strong guarantee, but implicitly-unwrapped optional types like Int! are intended to give you an out if the static model is too strict or inefficient.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Rod Brown) #14

Dependency Injection does sort out this case, you're right.

One case it doesn't fix is where your initialised value depends on something within your superclass to be created first to derive your initialising value.

class MyBaseClass {
    let myStateManager: StateManager

    init() {
        // sets up stateManager
    }
}

class MySubclass: MyBaseClass {
     var myStateDerivedProperty: Int!

     override init() {
         super.init()

         myStateDerivedProperty = // derive state from myStateManager
     }
}

In this case, the writer cannot initialise their state derived properties until the superclass has completed its initialization because it is waiting on the stateManager to derive its initial state.

This is a somewhat contrived example but I've actually found myself with similar patterns where I use other frameworks, where the default is either not defined in documentation or the object I require as part of initialising the property does not exist until after the initialisation.

Rod

···

On 5 Feb 2017, at 4:04 am, Jean-Daniel <mailing@xenonium.com> wrote:

Le 4 févr. 2017 à 16:52, Rod Brown via swift-evolution <swift-evolution@swift.org> a écrit :

Hi Joe,

I think this comes back to the idea that a lot of people in the wider Swift community hold that Implicitly Unwrapped Optionals are “bad” and “discouraged", and therefore shouldn’t be used. There seems to have been much pushback on Implicitly Unwrapped Optionals in the Swift 3 timeframe, to try and remove them as much as possible.

I definitely see this as a valuable use for them. While an integer is an extremely lightweight example of this, when it could include creating entire object graphs multiple times due to initialiser behaviour, or because you won’t know the correct state of a variable until *after* initialisation has occurred on the superclass, this is a valuable example where IUOs are really the only alternative for performance or correctness reasons.

IUO are useful to workaround poorly designed class. As already said, you example could be rewrite like follow to avoid any useless computation

class A {
  let x: Int
  init(_ x: Int = 3) {
    self.x = x
  }
}

class B : A {
  override init() {
    …
    super.init(1)
  }
}

No useless initialization of x, and no need to use IUO. Is it a suffisent reason to keep them in the language ? Anyway, as long as we need them to usefully use IBOutlet, I’m pretty sure they are not going anywhere.

Perhaps this is an area where the Swift Core Team could provide guidance to the community? Do the Core Team see IUOs as “bad” outright, and destined to go away when possible, or are they a tool with specific uses that look to be supported into the future?

- Rod

On 4 Feb 2017, at 5:40 am, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 31, 2017, at 3:52 AM, Victor Petrescu via swift-evolution <swift-evolution@swift.org> wrote:

4. Joe Groff says there is already a backdoor of sorts ("There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first."): I'm assuming by T you mean generics. If that is true that may already solve the problem but... generics are a new concept for me (first time I really encountered and used them is now, in swift) but to my understanding their role is to deal with cases you don't know the type. Can you please show how to use this to work around the posted issue?

Sidenote: There may be another workaround using optionals (Joe Groff answer made it pop in my mind) but... I know the type and value for the variable, it is not optional or nil. Unwrapping each time someone needs it does not look like the best solution to me.

You don't need to understand generics to use implicitly-unwrapped optionals. By `T!` I was referring to the syntax used to represent them; you would write Int! or String! or whatever in your code. For your example, this would let you avoid having to invoke super.init() before resetting `x`:

class A {
     var x:Int! // Int! is nil by default
}

class B : A {
    override init() {
         x = 2 // So we can set it here w/o super.init first
    }
}

print(B().x + 1) // and we don't need to explicitly unwrap it to use it, unlike `Int?`

You're giving up the static guarantee that `x` has a value, so you'll get a runtime error if you try to use it before it's initialized, but that's the same situation you have in Java, where dereferencing an uninitialized object reference gives an NPE. Whether you want the hard guarantee that `x` is never optional from the compiler, or the convenience of leaving that up to runtime checks, is a call you have to make; Swift defaults to the strong guarantee, but implicitly-unwrapped optional types like Int! are intended to give you an out if the static model is too strict or inefficient.

-Joe
_______________________________________________
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


(Charlie Monroe) #15

No, but you can declare it as:

lazy var myStateDerivedProperty: Int = self.myStateManager.property

Of course, there are still more complex scenarious that require IUOs. For example anything that gets loaded from the UI (currently marked as @IBOutlet). IUOs are definitely useful for items that will be nonnil 99% of the object's lifetime, but don't necessarily need to be 100% of the time.

···

On Feb 4, 2017, at 6:22 PM, Rod Brown via swift-evolution <swift-evolution@swift.org> wrote:

Dependency Injection does sort out this case, you're right.

One case it doesn't fix is where your initialised value depends on something within your superclass to be created first to derive your initialising value.

class MyBaseClass {
    let myStateManager: StateManager

    init() {
        // sets up stateManager
    }
}

class MySubclass: MyBaseClass {
     var myStateDerivedProperty: Int!

     override init() {
         super.init()

         myStateDerivedProperty = // derive state from myStateManager
     }
}

In this case, the writer cannot initialise their state derived properties until the superclass has completed its initialization because it is waiting on the stateManager to derive its initial state.

This is a somewhat contrived example but I've actually found myself with similar patterns where I use other frameworks, where the default is either not defined in documentation or the object I require as part of initialising the property does not exist until after the initialisation.

Rod

On 5 Feb 2017, at 4:04 am, Jean-Daniel <mailing@xenonium.com <mailto:mailing@xenonium.com>> wrote:

Le 4 févr. 2017 à 16:52, Rod Brown via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Hi Joe,

I think this comes back to the idea that a lot of people in the wider Swift community hold that Implicitly Unwrapped Optionals are “bad” and “discouraged", and therefore shouldn’t be used. There seems to have been much pushback on Implicitly Unwrapped Optionals in the Swift 3 timeframe, to try and remove them as much as possible.

I definitely see this as a valuable use for them. While an integer is an extremely lightweight example of this, when it could include creating entire object graphs multiple times due to initialiser behaviour, or because you won’t know the correct state of a variable until *after* initialisation has occurred on the superclass, this is a valuable example where IUOs are really the only alternative for performance or correctness reasons.

IUO are useful to workaround poorly designed class. As already said, you example could be rewrite like follow to avoid any useless computation

class A {
  let x: Int
  init(_ x: Int = 3) {
    self.x = x
  }
}

class B : A {
  override init() {
    …
    super.init(1)
  }
}

No useless initialization of x, and no need to use IUO. Is it a suffisent reason to keep them in the language ? Anyway, as long as we need them to usefully use IBOutlet, I’m pretty sure they are not going anywhere.

Perhaps this is an area where the Swift Core Team could provide guidance to the community? Do the Core Team see IUOs as “bad” outright, and destined to go away when possible, or are they a tool with specific uses that look to be supported into the future?

- Rod

On 4 Feb 2017, at 5:40 am, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 31, 2017, at 3:52 AM, Victor Petrescu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

4. Joe Groff says there is already a backdoor of sorts ("There already is a backdoor of sorts. This is one of the intended use cases for implicitly-unwrapped optionals. If you don't want to be hassled by DI, declare a property as T! type, and it will be implicitly initialized to nil, and trap if you try to use it as an unwrapped T without initializing it first."): I'm assuming by T you mean generics. If that is true that may already solve the problem but... generics are a new concept for me (first time I really encountered and used them is now, in swift) but to my understanding their role is to deal with cases you don't know the type. Can you please show how to use this to work around the posted issue?

Sidenote: There may be another workaround using optionals (Joe Groff answer made it pop in my mind) but... I know the type and value for the variable, it is not optional or nil. Unwrapping each time someone needs it does not look like the best solution to me.

You don't need to understand generics to use implicitly-unwrapped optionals. By `T!` I was referring to the syntax used to represent them; you would write Int! or String! or whatever in your code. For your example, this would let you avoid having to invoke super.init() before resetting `x`:

class A {
     var x:Int! // Int! is nil by default
}

class B : A {
    override init() {
         x = 2 // So we can set it here w/o super.init first
    }
}

print(B().x + 1) // and we don't need to explicitly unwrap it to use it, unlike `Int?`

You're giving up the static guarantee that `x` has a value, so you'll get a runtime error if you try to use it before it's initialized, but that's the same situation you have in Java, where dereferencing an uninitialized object reference gives an NPE. Whether you want the hard guarantee that `x` is never optional from the compiler, or the convenience of leaving that up to runtime checks, is a call you have to make; Swift defaults to the strong guarantee, but implicitly-unwrapped optional types like Int! are intended to give you an out if the static model is too strict or inefficient.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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