# Access control for enum case initializers

**URL:** <https://forums.swift.org/t/access-control-for-enum-case-initializers/22663>\
**Category:** Pitches\
**Created:** [April 5, 2019, 12:46am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663 "2019-04-05T00:46:54Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [April 5, 2019, 12:46am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/1 "2019-04-05T00:46:55Z")

</div>

Enum cases serve as both factory functions and patterns for use in pattern matching. All cases in an enum are currently visible at the same level as the enum itself _for both of these uses_.

I have run into a number of times where an enum is the right tool for the job but I did not wish to expose and initializer for some (or all) cases outside a library. There is no good way out of this design problem. If an enum is not used, users of the library lose the ability to pattern match and destructure the value.

Following the parameterized access control syntax we use for properties, I think we should allow the visibility of the _case initializer_ portion of an enum case to be modified.

```swift
public enum Foo {
    // this case may only be initialized by `Foo` itself within the declaring file
    private(init) case bar

    // this case may only be initialized within the declaring file
    fileprivate(init) case baz

    // this case may only be initialized within the declaring module
    internal(init) case fizz

    // this case may be initialized anywhere
    // by default cases initializers still have the same visibility as the type itself
    case buzz
}

```

Note: this pitch **does not** introduce the ability to hide a case for the purpose of pattern matching. Unparameterized access control on a case would be rejected by the compiler. That may be a viable future direction but I believe it is a much larger change to the language and is not necessary to solve the library design issues caused by the inability to restrict enum value initialization.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [April 5, 2019, 12:59am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/2 "2019-04-05T00:59:58Z")

</div>

Infrequently requested—the Radar for it, rdar://problem/22891351, has no dups, but that could be us Apple folks not consolidating properly—but a reasonable feature in my mind. I like your spelling for it, too.

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [April 5, 2019, 1:02am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/3 "2019-04-05T01:02:47Z")

</div>

+1 I've always wanted this for SwiftPM's `PackageDescription` library!

---

<div class="post-metadata">

**Author:** ![Alejandro](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alejandro/32/46197_2.png) [@Alejandro](https://forums.swift.org/u/Alejandro)\
**Post date:** [April 5, 2019, 1:29am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/4 "2019-04-05T01:29:25Z")

</div>

I'd be curious to hear what you think when it comes to something like `CaseIterable`. I imagine this only uses public cases, but what if I _really_ want to iterate over all of my cases inside the declaring enum?

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [April 5, 2019, 1:35am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/5 "2019-04-05T01:35:03Z")

</div>

> [@Alejandro](#):
>
> I'd be curious to hear what you think when it comes to something like `CaseIterable` . I imagine this only uses public cases, but what if I _really_ want to iterate over all of my cases inside the declaring enum?

I think when this is used `CaseIterable` synthesis would have to be disabled. The semantics break if you don’t include all cases. Manual conformance would still be possible if desired but would be inadvisable given the semantic conflict.

---

<div class="post-metadata">

**Author:** ![griotspeak](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/griotspeak/32/1966_2.png) [@griotspeak](https://forums.swift.org/u/griotspeak)\
**Post date:** [April 5, 2019, 1:44am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/6 "2019-04-05T01:44:24Z")

</div>

I never filed a bug for this because I assumed it just wouldn't ever be allowed. I wasn't sure that the asymmetry of being able to switch over something that you couldn't construct would be accepted.

I have wanted the ability to do this since day 1.

one use case is projecting enums for pattern matching from a class (that should be a class because caching or some other reason)

---

<div class="post-metadata">

**Author:** ![hartbit](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hartbit/32/738_2.png) [@hartbit](https://forums.swift.org/u/hartbit)\
**Post date:** [April 5, 2019, 5:45am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/7 "2019-04-05T05:45:09Z")

</div>

> [@Aciid](#):
>
> +1 I've always wanted this for SwiftPM's `PackageDescription` library!

That would definitely be useful!

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 6:24am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/8 "2019-04-05T06:24:38Z")

</div>

As there are bugs open which suggest that we also should allow static members to kind of fake enum cases, would it rather make sense to call it `private(call)` instead of using `init` which would be only limitted to enum cases? I know that I probably suggest a bigger feature here, but I think it might be worth pointing out that `access_level(call)` can limit the call of a type member to its type while the actual member itself is exposed due to other reasons.

```swift
enum AnimationDuration {
  case never
  private(call) case value(Double)

  static var oneSecond: AnimationDuration {
    return .value(1)
  }

  private(call) static var indefinitely: AnimationDuration {
    return .value(.nan)
  }
}

```

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 6:48am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/9 "2019-04-05T06:48:19Z")

</div>

Can you explain why there is a conflict? I think if you would implement the protocol in the type declaring body even your `private(init)` would not prevent you from generating the case for the collection. That said, I only see `CaseIterable` limited in the way where an enum conforms to the protocol. (Kind of similar to the synthetization rules for `Hashable/Equatable`.) So if you can move the conformance close to the enum, you should be fine.

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [April 5, 2019, 7:12am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/10 "2019-04-05T07:12:57Z")

</div>

Would you be able to obtain the private(init) case in this way? If not, which part would be forbidden? (It errors out with "Enum case 'privateCase' is not a member of type 'PatternHijacker'", but I don't think it should. I'll make a bug report later)

```swift
enum MyCoolEnum {
    private(init) case privateCase
    case publicCase
}
class PatternHijacker {
    var pattern: MyCoolEnum?
    init() { }
}

func ~=(pattern: MyCoolEnum, value: PatternHijacker) -> Bool {
    value.pattern = pattern
    return true
}

var hijacker = PatternHijacker()
switch hijacker {
case MyCoolEnum.privateCase:
    break
default:
    break
}

let valueThatIShouldntBeAbleToObtain = hijacker.pattern!

```

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 7:38am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/11 "2019-04-05T07:38:01Z")

</div>

With the current access control rules this will error out and you will need to change it to `fileprivate(init)`. Feel free to correct me if I'm wrong.

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [April 5, 2019, 7:54am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/12 "2019-04-05T07:54:58Z")

</div>

Which line will error out? What would be the error?

If the line is `case MyCoolEnum.privateCase:` then the sentence " Note: this pitch **does not** introduce the ability to hide a case for the purpose of pattern matching." is kinda misleading, because it hides it for non-compiler-generated pattern match operators

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 8:01am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/13 "2019-04-05T08:01:22Z")

</div>

That is exactly the line that will error out, because you still need to initialize the enum case to be able to pattern match it. The compiler will likely say something like:

```swift
Call to `MyCoolEnum.privateCase` is inaccessible due to `private(init)` protection level

```

The sentence says, in other words, this pitch does not introduce `private` cases - or cases that can be hidden from greater access levels. It is however true that some can misinterpret what the sentence really means.

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [April 5, 2019, 8:11am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/14 "2019-04-05T08:11:47Z")

</div>

I am confused. Would this be possible?

```swift
enum MyCoolEnum {
    private(init) case privateCase
    case publicCase
}

let foo = MyCoolEnum.publicCase
switch foo {
case .privateCase:
    break
case .publicCase:
    break
}

```

How about this?

```swift
enum MyCoolEnum {
    private(init) case privateCase
    case publicCase
}

let foo = MyCoolEnum.publicCase
switch foo {
case MyCoolEnum.privateCase:
    break
case MyCoolEnum.publicCase:
    break
}

```

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 8:19am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/15 "2019-04-05T08:19:51Z")

</div>

I'd say none of these are possible until you use `fileprivate(init)` or `internal(init)`. Here an example with a alternate `access_level(call)` option.

```swift
// file A
struct Test {
  private func foo() {}
  internal private(call) func bar() {
    foo() // fine
  }

  internal fileprivate(call) func baz() {
    bar() // fine
  }
}

// still file A
let test = Test()

// `foo` is not visible by autocompletion at all
// error: 'foo' is inaccessible due to 'private' protection level
test.foo() 

// `bar` is visible by autocompletion
// error: 'bar' is inaccessible due to 'private(call)' protection level
test.bar()

// `baz` is visible by autocompletion
test.baz() // okay as we're in the same file

// file B
test.foo() // same error as above
test.bar() // same error as above

// error: 'baz' is inaccessible due to 'fileprivate(call)' protection level
test.baz() 

```

This kind of the same for pitched `access_level(init)`. I would prefer `access_level(call)` as it is would not be exclusive to enum cases, which would be really odd.

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [April 5, 2019, 8:32am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/16 "2019-04-05T08:32:48Z")

</div>

> [@anandabits](#):
>
> Note: this pitch **does not** introduce the ability to hide a case for the purpose of pattern matching.

What does pattern matching means in swift if not `switch`?

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 8:38am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/17 "2019-04-05T08:38:45Z")

</div>

A simple example if the future direction mentioned in the pitch was accepted and implemented.

```swift
enum E {
  case a
  case b
  private case c
}

let e = E.c
swtich e {
case .a:
  break
case .b:
  break
case .c: // would error out as `.c` is not visible
  ...
default:
  /* we can end up here because `e` can be the hidden `.c` case */
}

```

The nearest feature to `private(init)` is `private(set)`. Pattern matching is not magic. Most of the time we compare for equality of two values there the second value is initialized by the switch statement when comparing each new case. The only case I'm not quite sure about is when you destructure the case and extract the payload from it. (Please correct me if I'm wrong.)

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [April 5, 2019, 8:41am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/18 "2019-04-05T08:41:39Z")

</div>

> [@DevAndArtist](#):
>
> case .c: // would error out as `.c` is not visible

According to you it would also error out if `.c` is private(init). I don't see the difference.

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 5, 2019, 8:49am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/19 "2019-04-05T08:49:12Z")

</div>

In your original example you had a `~=` overload which explicitly requires you to provide an instance of `MyCoolEnum` that will be stored inside `pattern` argument. For that to work you still have to initialize that case. In your example you do it using a switch statement, which won't be possible for a case marked as `private(init)` from a `switch` that lives outside the any `MyCoolEnum` (extension) body in the current file. Mark it as `fileprivate(init)` and it will work.

```swift
// Module A
public enum MyEnum {
  case a
  internal(init) case b

  // in the future
  internal case c
}

// in module A
_ = MyEnum.b // okay
_ = MyEnum.c // okay

// in module B
import A
// `MyEnum.b` is exposed and visible to the user but he cannot initialize it
_ = MyEnum.b // error due to `internal(init)` protection level

// `MyEnum.c` is not visible to the module user
_ = MyEnum.c // error `MyEnum` has no member `c`

```

To be clear, I'm trying to make you understand how I see the current situation. If I'm wrong about anything I said so far, I apologize in advance, so please anyone feel free to correct me.

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [April 5, 2019, 8:55am UTC](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663/20 "2019-04-05T08:55:44Z")

</div>

I'll ask again. Would this be possible? Notice how there is no `~=` overload here

```swift
enum MyCoolEnum {
    private(init) case privateCase
    case publicCase
}

let foo = MyCoolEnum.publicCase
switch foo {
case .privateCase:
    break
case .publicCase:
    break
}

```

How about this?

```swift
enum MyCoolEnum {
    private(init) case privateCase
    case publicCase
}

let foo = MyCoolEnum.publicCase
switch foo {
case MyCoolEnum.privateCase:
    break
case MyCoolEnum.publicCase:
    break
}

```

If your answer is still "none of these are possible", then I think that having two attributes that behave exactly the same, just with different messages is dumb.

[Next page](https://forums.swift.org/t/access-control-for-enum-case-initializers/22663.md?page=2)
