Convenience initializers in structs?


(Jens Persson) #1

Start a command line project in Xcode 9 beta 3 and copy paste this single
line of code into main.swift

let _ = UInt8.init(extendingOrTruncating: UInt64(123456))

Now look at Quick Help while placing the cursor on `init` and then on
`extendingOrTruncating`.

Note that (and how) the documentation for the initializer differs depending
on where you place the cursor.

If the cursor is on `init`, the initializer is shown to be a convenience(!)
initializer even though structs (such as UInt8) cannot have convenience
initializers, right?

Even the official documentation for this and several other initializer like
eg:
https://developer.apple.com/documentation/swift/int/2885075-init
clearly shows convenience initializers in structs.

By the way, .init(extendingOrTruncating:) doesn't show in the list of
completions for "UInt8.init" but it does for "UInt8(".

Can anyone explain what's going on?

Are these known issues that will go away in time for Xcode 9 GM?

/Jens


(Slava Pestov) #2

Hi Jens,

While I’m not familiar with the integer API in the standard library, structs and enums certainly can have convenience initializers. They must delegate to another initializer (either convenience or designated) rather than initializing the fields of the type one by one.

Slava

···

On Jul 18, 2017, at 6:46 AM, Jens Persson via swift-users <swift-users@swift.org> wrote:

Start a command line project in Xcode 9 beta 3 and copy paste this single line of code into main.swift

let _ = UInt8.init(extendingOrTruncating: UInt64(123456))

Now look at Quick Help while placing the cursor on `init` and then on `extendingOrTruncating`.

Note that (and how) the documentation for the initializer differs depending on where you place the cursor.

If the cursor is on `init`, the initializer is shown to be a convenience(!) initializer even though structs (such as UInt8) cannot have convenience initializers, right?

Even the official documentation for this and several other initializer like eg:
https://developer.apple.com/documentation/swift/int/2885075-init
clearly shows convenience initializers in structs.

By the way, .init(extendingOrTruncating:) doesn't show in the list of completions for "UInt8.init" but it does for "UInt8(".

Can anyone explain what's going on?

Are these known issues that will go away in time for Xcode 9 GM?

/Jens

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


(Jens Persson) #3

That is not true. Structs can have delegating initializers but they cannot
be marked with `convenience` (only the initializers of class types can).

This is very clear from both the documentation and the compiler:

(1) The Swift Programming language (Swift 4):
"Swift defines two kinds of initializers for *class* types to help ensure
all stored properties receive an initial value. These are known as
designated initializers and convenience initializers."

(2) The compiler:

struct S {
    var a, b: Int
    init(_ a: Int, _ b: Int) {
        self.a = a
        self.b = b
    }
    convenience init(_ ab: Int) { // <-- Error
        self.init(ab, ab)
    }
}
The error message is:
Delegating initializers in structs are not marked with 'convenience'
The suggested fix is to remove the word convenience.

Please reread my previous post, perform the steps I describe (looking at
Quick Help, also try jump to definition for that `init` and you'll see it
is marked with `convenience` even though it is in a struct), also look at
the link to the documentation for the Int init, it too is marked with
convenience, even though Int is a struct.

/Jens

···

On Tue, Jul 18, 2017 at 9:46 PM, Slava Pestov <spestov@apple.com> wrote:

Hi Jens,

While I’m not familiar with the integer API in the standard library,
structs and enums certainly can have convenience initializers. They must
delegate to another initializer (either convenience or designated) rather
than initializing the fields of the type one by one.

Slava

On Jul 18, 2017, at 6:46 AM, Jens Persson via swift-users < > swift-users@swift.org> wrote:

Start a command line project in Xcode 9 beta 3 and copy paste this single
line of code into main.swift

let _ = UInt8.init(extendingOrTruncating: UInt64(123456))

Now look at Quick Help while placing the cursor on `init` and then on
`extendingOrTruncating`.

Note that (and how) the documentation for the initializer differs
depending on where you place the cursor.

If the cursor is on `init`, the initializer is shown to be a
convenience(!) initializer even though structs (such as UInt8) cannot have
convenience initializers, right?

Even the official documentation for this and several other initializer
like eg:
https://developer.apple.com/documentation/swift/int/2885075-init
clearly shows convenience initializers in structs.

By the way, .init(extendingOrTruncating:) doesn't show in the list of
completions for "UInt8.init" but it does for "UInt8(".

Can anyone explain what's going on?

Are these known issues that will go away in time for Xcode 9 GM?

/Jens

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


(Slava Pestov) #4

Was it ever explained why the syntax is different?

Oh. I think convenience initializers on classes are marked as such explicitly because convenience vs designated has an effect on the ABI of an initializer, for the purposes of inheritance. With a value type, it doesn’t change anything about how the initializer is used externally.

Yeah, probably the AST printer should not print the ‘convenience’ keyword on non-class initializers.

Slava

···

On Jul 18, 2017, at 3:54 PM, Chris McIntyre <nothingwasdelivered@gmail.com> wrote:

--
Chris McIntyre

On Jul 18, 2017, at 6:46 PM, Jens Persson via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

That is not true. Structs can have delegating initializers but they cannot be marked with `convenience` (only the initializers of class types can).

This is very clear from both the documentation and the compiler:

(1) The Swift Programming language (Swift 4):
"Swift defines two kinds of initializers for *class* types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers."

(2) The compiler:

struct S {
    var a, b: Int
    init(_ a: Int, _ b: Int) {
        self.a = a
        self.b = b
    }
    convenience init(_ ab: Int) { // <-- Error
        self.init(ab, ab)
    }
}
The error message is:
Delegating initializers in structs are not marked with 'convenience'
The suggested fix is to remove the word convenience.

Please reread my previous post, perform the steps I describe (looking at Quick Help, also try jump to definition for that `init` and you'll see it is marked with `convenience` even though it is in a struct), also look at the link to the documentation for the Int init, it too is marked with convenience, even though Int is a struct.

/Jens

On Tue, Jul 18, 2017 at 9:46 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:
Hi Jens,

While I’m not familiar with the integer API in the standard library, structs and enums certainly can have convenience initializers. They must delegate to another initializer (either convenience or designated) rather than initializing the fields of the type one by one.

Slava

On Jul 18, 2017, at 6:46 AM, Jens Persson via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Start a command line project in Xcode 9 beta 3 and copy paste this single line of code into main.swift

let _ = UInt8.init(extendingOrTruncating: UInt64(123456))

Now look at Quick Help while placing the cursor on `init` and then on `extendingOrTruncating`.

Note that (and how) the documentation for the initializer differs depending on where you place the cursor.

If the cursor is on `init`, the initializer is shown to be a convenience(!) initializer even though structs (such as UInt8) cannot have convenience initializers, right?

Even the official documentation for this and several other initializer like eg:
https://developer.apple.com/documentation/swift/int/2885075-init
clearly shows convenience initializers in structs.

By the way, .init(extendingOrTruncating:) doesn't show in the list of completions for "UInt8.init" but it does for "UInt8(".

Can anyone explain what's going on?

Are these known issues that will go away in time for Xcode 9 GM?

/Jens

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

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


(Jordan Rose) #5

FWIW I tried to stop doing this in the actual AST representation and it caused problems (https://github.com/apple/swift/pull/8540/commits/4f6e88b009ad07edd35343c2c9b758f03029a731 <https://github.com/apple/swift/pull/8540>). That's probably the right way for us to go for real, though, not just hiding the kind in the printer.

Jordan

···

On Jul 18, 2017, at 15:56, Slava Pestov via swift-users <swift-users@swift.org> wrote:

On Jul 18, 2017, at 3:54 PM, Chris McIntyre <nothingwasdelivered@gmail.com <mailto:nothingwasdelivered@gmail.com>> wrote:

Was it ever explained why the syntax is different?

Oh. I think convenience initializers on classes are marked as such explicitly because convenience vs designated has an effect on the ABI of an initializer, for the purposes of inheritance. With a value type, it doesn’t change anything about how the initializer is used externally.

Yeah, probably the AST printer should not print the ‘convenience’ keyword on non-class initializers.


(Chris McIntyre) #6

Was it ever explained why the syntax is different?

···

--
Chris McIntyre

On Jul 18, 2017, at 6:46 PM, Jens Persson via swift-users <swift-users@swift.org> wrote:

That is not true. Structs can have delegating initializers but they cannot be marked with `convenience` (only the initializers of class types can).

This is very clear from both the documentation and the compiler:

(1) The Swift Programming language (Swift 4):
"Swift defines two kinds of initializers for *class* types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers."

(2) The compiler:

struct S {
    var a, b: Int
    init(_ a: Int, _ b: Int) {
        self.a = a
        self.b = b
    }
    convenience init(_ ab: Int) { // <-- Error
        self.init(ab, ab)
    }
}
The error message is:
Delegating initializers in structs are not marked with 'convenience'
The suggested fix is to remove the word convenience.

Please reread my previous post, perform the steps I describe (looking at Quick Help, also try jump to definition for that `init` and you'll see it is marked with `convenience` even though it is in a struct), also look at the link to the documentation for the Int init, it too is marked with convenience, even though Int is a struct.

/Jens

On Tue, Jul 18, 2017 at 9:46 PM, Slava Pestov <spestov@apple.com> wrote:
Hi Jens,

While I’m not familiar with the integer API in the standard library, structs and enums certainly can have convenience initializers. They must delegate to another initializer (either convenience or designated) rather than initializing the fields of the type one by one.

Slava

On Jul 18, 2017, at 6:46 AM, Jens Persson via swift-users <swift-users@swift.org> wrote:

Start a command line project in Xcode 9 beta 3 and copy paste this single line of code into main.swift

let _ = UInt8.init(extendingOrTruncating: UInt64(123456))

Now look at Quick Help while placing the cursor on `init` and then on `extendingOrTruncating`.

Note that (and how) the documentation for the initializer differs depending on where you place the cursor.

If the cursor is on `init`, the initializer is shown to be a convenience(!) initializer even though structs (such as UInt8) cannot have convenience initializers, right?

Even the official documentation for this and several other initializer like eg:
https://developer.apple.com/documentation/swift/int/2885075-init
clearly shows convenience initializers in structs.

By the way, .init(extendingOrTruncating:) doesn't show in the list of completions for "UInt8.init" but it does for "UInt8(".

Can anyone explain what's going on?

Are these known issues that will go away in time for Xcode 9 GM?

/Jens

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

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