Splitting Information Elements

I want to split my information elements, but it is not possible.

For example, neither this (in single file):

// Foo.swift
//
class Foo {
    var x : Int;
    
    init ();
    init (v: Int);
    
    func bar () -> Int;
    func bar (u:Int, v:Int) -> Int;
}

extension Foo {
    init () {
        ...
    }
    
    init (v: Int) {
        ...
    }
}

extension Foo {
    func bar () -> Int {
        ...
    }
    
    func bar (u:Int, v:Int) -> Int {
        ...
    }
}

Nor this (in multiple files):

// Foo.swift
//
class Foo {
    var x : Int;
    
    init ();
    init (v: Int);
    
    func bar () -> Int;
    func bar (u:Int, v:Int) -> Int;
}

// Foo-init.swift
//
extension Foo {
    init () {
        ...
    }
    
    init (v: Int) {
        ...
    }
}

// Foo-bar.swift
//
extension Foo {
    func bar () -> Int {
        ...
    }
    
    func bar (u:Int, v:Int) -> Int {
        ...
    }
}

Is there any reason for why this is not possible?

I guess, based on the code you posted, that you are trying to “forward-declare” your init and bar methods.

There are no forward declarations in Swift.

Because Foo is a class, it can have two kinds of init: “designated” and “convenience”. All designated inits need to be defined in the main body of Foo, and you must have at least one designated init. You can put convenience inits and other methods in extensions. For example:

class Foo {
    var x: Int
    
    // Note that this is a designated init because it doesn't have the
    // `convenience` keyword.
    init() {
        x = 0
    }
}

extension Foo {
    convenience init(v: Int) {
        self.init()
        x = v
    }
}

extension Foo {
    func bar() -> Int {
        return x
    }
    
    func bar(u:Int, v:Int) -> Int {
        return x + u + v
    }
}
2 Likes

Thank you for explaining the distinction between designated and convenience intialisers.

My intention is simply to present all the key information in a manner which makes it easier to digest, without showing any implementation details.

// Foo.swift
//
class Foo {
    var x : Int;
    
    init ();
    init (v: Int);
    
    func bar () -> Int;
    func bar (u:Int, v:Int) -> Int;
}

Is there a technical reason that this can't be done in Swift?

It is kind of sad that this is not possible today in Swift, a modern programming language.

This has to do with access control; basically, an init has to initialise all the storage of a type, including private properties. Since private properties aren't visible from a different file, the init has to be in the same file. Moreover, because extensions can be "many", while the type definition is "one", requiring a designated init in the type declaration eliminates potential collisions, where multiple extensions try to write the same init. This is important for classes, because all that class's subclasses need to know which of its inits are designated so that they can call super.init on them.

Otherwise, the lack of forward declarations is actually a manifestation of a modern language, since the code duplication due to forward declarations and headers was (is) quite an annoyance in the older C-like languages.

4 Likes

If you're using Xcode, open the assistant pane (control + option + command + enter) and select "generated interface" up top

1 Like

That seems like a job for the text editor/IDE level. It's also duplicating information, so you have to jump back and forth to keep it all in sync. Why waste human effort to generate interfaces for presentation like this, when a machine can prepare it automatically?

Ironically, the split header+implementation structure of C/C++ programs is often cited as one of the biggest factors that make them feel "old".

1 Like