Proposal: label-only constructors


(Drew Crawford) #1

Oftentimes I want to have multiple parameterless constructors. In the immediate case, I want a Key for various different cryptographic algorithms:

    let a = Key(forRSA: true) //2048-bits
    let b = Key(forCurve25519: true) //256-bits
    let c = Key(forAES: true) //128-bits

There is no "parameter" to pass here; in particular the user should not be expected to know off the top of their head what the key size for Curve25519 is.

With the current limits of the language, I am generally forced to vend a parameter and associated label (I typically use type Bool) and pass a "dontcare" value in, e.g. `true` in the above.

I propose to eliminate this, so I can write

    Key {
        init(forRSA) { /* */ }
    }
    let a = Key(forRSA)

This eliminates the parameter, and the associated mystery about what happens if you pass `false` to one of these constructors.

FAQ:

Q: Can't you have one constructor that takes an enum parameter?

···

A: Enum parameters cannot have cases with distinct access modifiers, as constructors often are. Also, combining unrelated code into one constructor makes me sad.

Q: Can't you create subclasses RSAKey, Curve25519Key etc. with distinct constructors?
A: Well first of all, Key is probably a `struct`, so no, you can't create subclasses of it. Also, the only thing differentiating them is the constructor, not e.g. other overridden methods or variables, so subclassing feels an unnecessarily heavy abstraction.

Q: Can we extend this to support arbitrary labels e.g. `init(random length: 2000)` vs `init(zeroed length: 2000)`, `mkdir(path, creatingIntermediateDirectoriesIfRequired)` and many more?
A: Yes, although these are probably more controversial proposals than simply supporting multiple parameterless constructors.


(ilya) #2

(1) Isn't using a class function just one more symbol?

let a = Key.forRSA()

(2) Wouldn't this syntax be more logical:
Key {
init(forRSA: Void) { /* */ }
}

Key(forRSA:)
The only change compared to what we have now would be auto-generation of
().

···

On Sun, Dec 13, 2015 at 15:50 Drew Crawford via swift-evolution < swift-evolution@swift.org> wrote:

Oftentimes I want to have multiple parameterless constructors. In the
immediate case, I want a Key for various different cryptographic algorithms:

    let a = Key(forRSA: true) //2048-bits
    let b = Key(forCurve25519: true) //256-bits
    let c = Key(forAES: true) //128-bits

There is no "parameter" to pass here; in particular the user should not be
expected to know off the top of their head what the key size for Curve25519
is.

With the current limits of the language, I am generally forced to vend a
parameter and associated label (I typically use type Bool) and pass a
"dontcare" value in, e.g. `true` in the above.

I propose to eliminate this, so I can write

    Key {
        init(forRSA) { /* */ }
    }
    let a = Key(forRSA)

This eliminates the parameter, and the associated mystery about what
happens if you pass `false` to one of these constructors.

FAQ:

Q: Can't you have one constructor that takes an enum parameter?
A: Enum parameters cannot have cases with distinct access modifiers, as
constructors often are. Also, combining unrelated code into one
constructor makes me sad.

Q: Can't you create subclasses RSAKey, Curve25519Key etc. with distinct
constructors?
A: Well first of all, Key is probably a `struct`, so no, you can't create
subclasses of it. Also, the only thing differentiating them is the
constructor, not e.g. other overridden methods or variables, so subclassing
feels an unnecessarily heavy abstraction.

Q: Can we extend this to support arbitrary labels e.g. `init(random
length: 2000)` vs `init(zeroed length: 2000)`, `mkdir(path,
creatingIntermediateDirectoriesIfRequired)` and many more?
A: Yes, although these are probably more controversial proposals than
simply supporting multiple parameterless constructors.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #3

Oftentimes I want to have multiple parameterless constructors. In the immediate case, I want a Key for various different cryptographic algorithms:

   let a = Key(forRSA: true) //2048-bits
   let b = Key(forCurve25519: true) //256-bits
   let c = Key(forAES: true) //128-bits

There is no "parameter" to pass here; in particular the user should not be expected to know off the top of their head what the key size for Curve25519 is.

With the current limits of the language, I am generally forced to vend a parameter and associated label (I typically use type Bool) and pass a "dontcare" value in, e.g. `true` in the above.

I propose to eliminate this, so I can write

   Key {
       init(forRSA) { /* */ }
   }
   let a = Key(forRSA)

This eliminates the parameter, and the associated mystery about what happens if you pass `false` to one of these constructors.

FAQ:

Q: Can't you have one constructor that takes an enum parameter?
A: Enum parameters cannot have cases with distinct access modifiers, as constructors often are. Also, combining unrelated code into one constructor makes me sad.

Doesn't this work?

struct Key {
  enum RSA_ { case RSA }
  init(_: RSA_) { ... }

  enum AES_ { case AES }
  init(_: AES_) { ... }

  // etc.
}

It's admittedly awkward at the declaration site but it still looks good at the use-site:

  Key(.RSA)
  Key(.AES)

etc.

Q: Can't you create subclasses RSAKey, Curve25519Key etc. with distinct constructors?
A: Well first of all, Key is probably a `struct`, so no, you can't create subclasses of it. Also, the only thing differentiating them is the constructor, not e.g. other overridden methods or variables, so subclassing feels an unnecessarily heavy abstraction.

Q: Can we extend this to support arbitrary labels e.g. `init(random length: 2000)` vs `init(zeroed length: 2000)`, `mkdir(path, creatingIntermediateDirectoriesIfRequired)` and many more?
A: Yes, although these are probably more controversial proposals than simply supporting multiple parameterless constructors.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

-Dave

···

On Dec 13, 2015, at 4:49 AM, Drew Crawford via swift-evolution <swift-evolution@swift.org> wrote:


(Drew Crawford) #4

(1) Isn't using a class function just one more symbol?

No, a class/static function is not the same as an initializer. e.g., a class function cannot assign to a let ivar.

(2) Wouldn't this syntax be more logical:
Key {
init(forRSA: Void) { /* */ }
}

Key(forRSA:)

Maybe. The trailing colon gives me some anxiety; I feel like it wants something to follow it.

···

On Dec 13, 2015, at 7:03 AM, ilya <ilya.nikokoshev@gmail.com> wrote:


(ilya) #5

There is no "parameter" to pass here; in particular the user should not

be expected to know off the top of their head what the key size for
Curve25519 is.

You can easily call a private parametrized init from a class function
though.

The trailing colon gives me some anxiety; I feel like it wants something

to follow it.

Sure, it's not the most beautiful construct, but it unambiguously
identifies the preceding token as a label name.

···

On Sun, Dec 13, 2015 at 16:09 Drew Crawford <drew@sealedabstract.com> wrote:

On Dec 13, 2015, at 7:03 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

(1) Isn't using a class function just one more symbol?

No, a class/static function is not the same as an initializer. e.g., a
class function cannot assign to a let ivar.

(2) Wouldn't this syntax be more logical:
Key {
init(forRSA: Void) { /* */ }
}

Key(forRSA:)

Maybe. The trailing colon gives me some anxiety; I feel like it wants
something to follow it.


(Drew Crawford) #6

Sure, but we're just shuffling the deck. We've gone from a bad public API to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad public API. There is a reason that NSData.dataWithData(...) is a Swift compile error.

The (ab)use of class functions as constructors is a holdover from ObjC times. If you want to make an instance in Swift, you should type ClassName( and see what autocomplete suggests; you should not have to read through the documentation of class functions to see if they are secretly constructors that have been filed at the wrong shelf in the library.

···

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

You can easily call a private parametrized init from a class function though.


(Marc Knaup) #7

Using a static/class function would make subclassing difficult

   - you cannot hide them in subclasses (they're always inherited unlike
   initializers)
   - you can't call them from subclass initializers to properly initialize
   superclasses

···

On Sun, Dec 13, 2015 at 2:21 PM, Drew Crawford via swift-evolution < swift-evolution@swift.org> wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

You can easily call a private parametrized init from a class function
though.

Sure, but we're just shuffling the deck. We've gone from a bad public API
to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad
public API. There is a reason that NSData.dataWithData(...) is a Swift
compile error.

The (ab)use of class functions as constructors is a holdover from ObjC
times. If you want to make an instance in Swift, you should type
ClassName( and see what autocomplete suggests; you should not have to read
through the documentation of class functions to see if they are secretly
constructors that have been filed at the wrong shelf in the library.

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


(ilya) #8

Good point on that. I still think the best solution is to take the existing
syntax of

struct Key {
    init(forRSA:Void) { /* */ }
    init(forCurve25519:Void) { /* */ }
    init(forAES:Void) { /* */ }
}

let a = Key(forRSA: ())

or

let empty: Void = ()
let c = Key(forAES: empty)

and make it somewhat easier to read. Perhaps

let b = Key(forCurve25519: _ )

I think many people will read Key(forAES) as Key.init(_: forAES), so that
may be not the best expression here.

···

On Sun, Dec 13, 2015 at 4:21 PM, Drew Crawford <drew@sealedabstract.com> wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

You can easily call a private parametrized init from a class function
though.

Sure, but we're just shuffling the deck. We've gone from a bad public API
to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad
public API. There is a reason that NSData.dataWithData(...) is a Swift
compile error.

The (ab)use of class functions as constructors is a holdover from ObjC
times. If you want to make an instance in Swift, you should type
ClassName( and see what autocomplete suggests; you should not have to read
through the documentation of class functions to see if they are secretly
constructors that have been filed at the wrong shelf in the library.


(Sean Heber) #9

In this particular example, perhaps Key should be an enum instead of a struct.

l8r
Sean

···

Sent from my iPad

On Dec 13, 2015, at 10:07 AM, ilya via swift-evolution <swift-evolution@swift.org> wrote:

Good point on that. I still think the best solution is to take the existing syntax of

struct Key {
    init(forRSA:Void) { /* */ }
    init(forCurve25519:Void) { /* */ }
    init(forAES:Void) { /* */ }
}

let a = Key(forRSA: ())

or

let empty: Void = ()
let c = Key(forAES: empty)

and make it somewhat easier to read. Perhaps

let b = Key(forCurve25519: _ )

I think many people will read Key(forAES) as Key.init(_: forAES), so that may be not the best expression here.

On Sun, Dec 13, 2015 at 4:21 PM, Drew Crawford <drew@sealedabstract.com> wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

You can easily call a private parametrized init from a class function though.

Sure, but we're just shuffling the deck. We've gone from a bad public API to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad public API. There is a reason that NSData.dataWithData(...) is a Swift compile error.

The (ab)use of class functions as constructors is a holdover from ObjC times. If you want to make an instance in Swift, you should type ClassName( and see what autocomplete suggests; you should not have to read through the documentation of class functions to see if they are secretly constructors that have been filed at the wrong shelf in the library.

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


(Harlan Haskins) #10

Also I think it’d be cleaner to just accept an enum in one initializer

enum KeyType {
    case RSA
    case Curve25519
    case AES
}

Then you get that semantic niceness of:

init(keyType: .RSA)
init(keyType: .Curve25519)
init(keyType: .AES)

— Harlan

···

On Dec 13, 2015, at 11:41 AM, Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:

In this particular example, perhaps Key should be an enum instead of a struct.

l8r
Sean

Sent from my iPad

On Dec 13, 2015, at 10:07 AM, ilya via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Good point on that. I still think the best solution is to take the existing syntax of

struct Key {
    init(forRSA:Void) { /* */ }
    init(forCurve25519:Void) { /* */ }
    init(forAES:Void) { /* */ }
}

let a = Key(forRSA: ())

or

let empty: Void = ()
let c = Key(forAES: empty)

and make it somewhat easier to read. Perhaps

let b = Key(forCurve25519: _ )

I think many people will read Key(forAES) as Key.init(_: forAES), so that may be not the best expression here.

On Sun, Dec 13, 2015 at 4:21 PM, Drew Crawford <drew@sealedabstract.com <mailto:drew@sealedabstract.com>> wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com <mailto:ilya.nikokoshev@gmail.com>> wrote:

You can easily call a private parametrized init from a class function though.

Sure, but we're just shuffling the deck. We've gone from a bad public API to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad public API. There is a reason that NSData.dataWithData(...) is a Swift compile error.

The (ab)use of class functions as constructors is a holdover from ObjC times. If you want to make an instance in Swift, you should type ClassName( and see what autocomplete suggests; you should not have to read through the documentation of class functions to see if they are secretly constructors that have been filed at the wrong shelf in the library.

_______________________________________________
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


(David Owens II) #11

Agreed. It's also likely that you'll be setting some internal flag with this information already.

···

Sent from my iPhone

On Dec 13, 2015, at 8:55 AM, Harlan Haskins via swift-evolution <swift-evolution@swift.org> wrote:

Also I think it’d be cleaner to just accept an enum in one initializer

enum KeyType {
    case RSA
    case Curve25519
    case AES
}

Then you get that semantic niceness of:

init(keyType: .RSA)
init(keyType: .Curve25519)
init(keyType: .AES)

— Harlan

On Dec 13, 2015, at 11:41 AM, Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:

In this particular example, perhaps Key should be an enum instead of a struct.

l8r
Sean

Sent from my iPad

On Dec 13, 2015, at 10:07 AM, ilya via swift-evolution <swift-evolution@swift.org> wrote:

Good point on that. I still think the best solution is to take the existing syntax of

struct Key {
    init(forRSA:Void) { /* */ }
    init(forCurve25519:Void) { /* */ }
    init(forAES:Void) { /* */ }
}

let a = Key(forRSA: ())

or

let empty: Void = ()
let c = Key(forAES: empty)

and make it somewhat easier to read. Perhaps

let b = Key(forCurve25519: _ )

I think many people will read Key(forAES) as Key.init(_: forAES), so that may be not the best expression here.

On Sun, Dec 13, 2015 at 4:21 PM, Drew Crawford <drew@sealedabstract.com> wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

You can easily call a private parametrized init from a class function though.

Sure, but we're just shuffling the deck. We've gone from a bad public API to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad public API. There is a reason that NSData.dataWithData(...) is a Swift compile error.

The (ab)use of class functions as constructors is a holdover from ObjC times. If you want to make an instance in Swift, you should type ClassName( and see what autocomplete suggests; you should not have to read through the documentation of class functions to see if they are secretly constructors that have been filed at the wrong shelf in the library.

_______________________________________________
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

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


(Drew Crawford) #12

The problems with enums as parameters were explained in the proposal. I don't see how these responses address any of the concerns that were initially raised.

···

On Dec 13, 2015, at 2:25 PM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

Agreed. It's also likely that you'll be setting some internal flag with this information already.

Sent from my iPhone

On Dec 13, 2015, at 8:55 AM, Harlan Haskins via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Also I think it’d be cleaner to just accept an enum in one initializer

enum KeyType {
    case RSA
    case Curve25519
    case AES
}

Then you get that semantic niceness of:

init(keyType: .RSA)
init(keyType: .Curve25519)
init(keyType: .AES)

— Harlan

On Dec 13, 2015, at 11:41 AM, Sean Heber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

In this particular example, perhaps Key should be an enum instead of a struct.

l8r
Sean

Sent from my iPad

On Dec 13, 2015, at 10:07 AM, ilya via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Good point on that. I still think the best solution is to take the existing syntax of

struct Key {
    init(forRSA:Void) { /* */ }
    init(forCurve25519:Void) { /* */ }
    init(forAES:Void) { /* */ }
}

let a = Key(forRSA: ())

or

let empty: Void = ()
let c = Key(forAES: empty)

and make it somewhat easier to read. Perhaps

let b = Key(forCurve25519: _ )

I think many people will read Key(forAES) as Key.init(_: forAES), so that may be not the best expression here.

On Sun, Dec 13, 2015 at 4:21 PM, Drew Crawford <drew@sealedabstract.com <mailto:drew@sealedabstract.com>> wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com <mailto:ilya.nikokoshev@gmail.com>> wrote:

You can easily call a private parametrized init from a class function though.

Sure, but we're just shuffling the deck. We've gone from a bad public API to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a bad public API. There is a reason that NSData.dataWithData(...) is a Swift compile error.

The (ab)use of class functions as constructors is a holdover from ObjC times. If you want to make an instance in Swift, you should type ClassName( and see what autocomplete suggests; you should not have to read through the documentation of class functions to see if they are secretly constructors that have been filed at the wrong shelf in the library.

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


(Jason Dusek) #13

Is this equivalent to having "flags" for functions? Like `--rsa`, `--aes`?

···

On Sun, 13 Dec 2015 at 13:56, Drew Crawford via swift-evolution < swift-evolution@swift.org> wrote:

The problems with enums as parameters were explained in the proposal. I
don't see how these responses address any of the concerns that were
initially raised.

On Dec 13, 2015, at 2:25 PM, David Owens II via swift-evolution < > swift-evolution@swift.org> wrote:

Agreed. It's also likely that you'll be setting some internal flag with
this information already.

Sent from my iPhone

On Dec 13, 2015, at 8:55 AM, Harlan Haskins via swift-evolution < > swift-evolution@swift.org> wrote:

Also I think it’d be cleaner to just accept an enum in one initializer

enum KeyType {
    case RSA
    case Curve25519
    case AES
}

Then you get that semantic niceness of:

init(keyType: .RSA)
init(keyType: .Curve25519)
init(keyType: .AES)

— Harlan

On Dec 13, 2015, at 11:41 AM, Sean Heber via swift-evolution < > swift-evolution@swift.org> wrote:

In this particular example, perhaps Key should be an enum instead of a
struct.

l8r
Sean

Sent from my iPad

On Dec 13, 2015, at 10:07 AM, ilya via swift-evolution < > swift-evolution@swift.org> wrote:

Good point on that. I still think the best solution is to take the
existing syntax of

struct Key {
    init(forRSA:Void) { /* */ }
    init(forCurve25519:Void) { /* */ }
    init(forAES:Void) { /* */ }
}

let a = Key(forRSA: ())

or

let empty: Void = ()
let c = Key(forAES: empty)

and make it somewhat easier to read. Perhaps

let b = Key(forCurve25519: _ )

I think many people will read Key(forAES) as Key.init(_: forAES), so that
may be not the best expression here.

On Sun, Dec 13, 2015 at 4:21 PM, Drew Crawford <drew@sealedabstract.com> > wrote:

On Dec 13, 2015, at 7:13 AM, ilya <ilya.nikokoshev@gmail.com> wrote:

You can easily call a private parametrized init from a class function
though.

Sure, but we're just shuffling the deck. We've gone from a bad public
API to a bad private API.

Actually, it's worse, because we now have BOTH a bad private API AND a
bad public API. There is a reason that NSData.dataWithData(...) is a Swift
compile error.

The (ab)use of class functions as constructors is a holdover from ObjC
times. If you want to make an instance in Swift, you should type
ClassName( and see what autocomplete suggests; you should not have to read
through the documentation of class functions to see if they are secretly
constructors that have been filed at the wrong shelf in the library.

_______________________________________________
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

_______________________________________________
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

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


(David Owens II) #14

The problems with enums as parameters were explained in the proposal. I don't see how these responses address any of the concerns that were initially raised.

Granted. I think it’s just sadly one of those things that are lost when we combine the allocation and the initialization phase. I don’t like the labels as you’ve proposed because they are yet another special thing about initialization. For example, to solve this problem with functions, we could simply change the name of them.

Your problem also reminds me of the cluster cluster problem. While they are not quite the same, they share many of the same concerns. It’s not a stretch to return different types from the Key initializer so that you don’t need to waste 1024bits with a 128bit key is all that’s needed. Of course, this requires sized arrays that Swift doesn’t have yet or some other construct to get a fixed size, but I think the point is clear.

Unfortunately, I think Dave’s workaround is probably the best for your specific use case.

struct Key {
enum RSA_ { case RSA }
init(_: RSA_) { ... }

enum AES_ { case AES }
init(_: AES_) { ... }
}

Key(.RSA)
Key(.AES)

Then you have this:

Q: Can we extend this to support arbitrary labels e.g. `init(random length: 2000)` vs `init(zeroed length: 2000)`, `mkdir(path, creatingIntermediateDirectoriesIfRequired)` and many more?
A: Yes, although these are probably more controversial proposals than simply supporting multiple parameterless constructors.

I’m not sure this really applies generally. What if I want a mkdir() that doesn’t create the directories if required? This seems to fall right into the strong house of default parameters.

-David

···

On Dec 13, 2015, at 1:56 PM, Drew Crawford <drew@sealedabstract.com> wrote:


(Andrew Bennett) #15

Interesting suggestion :slight_smile:
Perhaps, try doing the work outside the constructor, then the static
function suggestions work:

struct Key {
    public static func createRSA() {
        var data: String
        // calculate RSA
        ...
        return Key(bitLength: 2048, data: data)
    }
    private init(bitLength: Int, data: String) {
        self.bitLength = bitLength
        self.data = data
    }
}

var myKey = Key.createRSA()

In my opinion this is much less ambiguous to the compiler and programmer. I
personally wouldn't be sure which of these 'Key(withRSA)' was:

let withRSA: Int
init(_ something: Int)

Or:

init(withRSA _ _)

···

On Mon, Dec 14, 2015 at 6:22 PM, David Owens II via swift-evolution < swift-evolution@swift.org> wrote:

> On Dec 13, 2015, at 1:56 PM, Drew Crawford <drew@sealedabstract.com> > wrote:
>
> The problems with enums as parameters were explained in the proposal. I
don't see how these responses address any of the concerns that were
initially raised.

Granted. I think it’s just sadly one of those things that are lost when we
combine the allocation and the initialization phase. I don’t like the
labels as you’ve proposed because they are yet another special thing about
initialization. For example, to solve this problem with functions, we could
simply change the name of them.

Your problem also reminds me of the cluster cluster problem. While they
are not quite the same, they share many of the same concerns. It’s not a
stretch to return different types from the Key initializer so that you
don’t need to waste 1024bits with a 128bit key is all that’s needed. Of
course, this requires sized arrays that Swift doesn’t have yet or some
other construct to get a fixed size, but I think the point is clear.

Unfortunately, I think Dave’s workaround is probably the best for your
specific use case.

> struct Key {
> enum RSA_ { case RSA }
> init(_: RSA_) { ... }
>
> enum AES_ { case AES }
> init(_: AES_) { ... }
> }
>
> Key(.RSA)
> Key(.AES)

Then you have this:

> Q: Can we extend this to support arbitrary labels e.g. `init(random
length: 2000)` vs `init(zeroed length: 2000)`, `mkdir(path,
creatingIntermediateDirectoriesIfRequired)` and many more?
> A: Yes, although these are probably more controversial proposals than
simply supporting multiple parameterless constructors.

I’m not sure this really applies generally. What if I want a mkdir() that
doesn’t create the directories if required? This seems to fall right into
the strong house of default parameters.

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