When to use nested-types?

Suppose the following model: You want to create a client-server program.
Where, the client would make no sense without the server.

Is that a good reason to make the client a nested-type of the server?:

struct Server {
   ....
  struct Client {
      ...
  }
}

Also, another advantage I see, you can have so private methods in the server, that the client can access , but no one else can.

However, is this a good reason? Are there any drawbacks to this approach? Someone mentioned testability, that the client is now not testable. Not sure if that's true.

Structuring code is very subjective, personally I just do this when a type is unquestionably directly related to another.

For example if I had a type or extension with an initializer/method that allows choosing something with an enum, I will write that enum in the type to avoid having it show up in unrelated suggestions:

extension String {

    enum  ColorType { case foreground, background }

    enum Color {
        case black
        case red
        case green
        case yellow
        case blue
        case magenta
        case cyan
        case white
        case `default`
    }

    mutating func color(_ color: Color, _ type: ColorType = .foreground) { ... }
    ...
}

This makes sense because I can just use String.Color which makes it obvious what kind of Color it is and avoids colliding with other types. (You would have to name it StringColor anyway)

I probably wouldn't put the Client in the Server, because now you will have to initialise it like this: Server.Client() which to me at least feels a little weird in Swift :slight_smile:
Client doesn't feel like a part of a Server, they're both equally important and serve no purpose without the other.

What I also started doing recently is "namespace" types by writing them in an empty enum, so MyProject.Server and MyProject.Client
This way you can have a top level protocol named Client and multiple Client implementations of the same name in different namespaces, avoiding naming conventions like "ClientProtocol"


As far as I know there shouldn't be any drawbacks. It's as if you had Client written separately, it just changes how you access the type and its initializers in your code.
I don't see how this would impact tests in any way.

3 Likes

Any time you have the name of a type in front of another type, the latter should be nested. String.Color.Type unfortunately doesn't work; .Type is the exception.

1 Like