Splitting swift files into multiple files without the use of extensions

First of all I searched if there are similar discussions like this but I didn't find any but feel free to point me in the right direction :slight_smile:

Situation: Imagine you write a class and as time passes you add more and more functionality. At some point the class is so large that it has over 500 or more lines of code. Wouldn't it be more organized if you could split your class into multiple files to separate functionality i.e upload functionality in one file and download functionality in the other file... You get the idea.

Current workaround: Create a second file like so -> Filename+Upload.swift and use extensions. Thats all nice and good but there are certain limitations. For example you can't override a func declared in an extension. See this post

Solution: Give the developer the option to split classes into multiple files without the use of extensions.

I have no idea how that would be implemented so... :man_shrugging:

4 Likes

Well yes there are indeed many cases where breaking up the functionality into multiple classes is the better solution but that's not always suitable. In addition it would give us more flexibility.

From my understanding, part of the limitation with this is the way files are compiled, and how incremental compilation works. If we can’t be sure storage is built when the single file is compiled, then the compiler needs to gain the skills to look across multiple files even in debug builds, which has impacts on incremental builds.

Overrides are a limitation I remember being discussed as being allowed in extensions in the same module as the declaration, which would solve this difficulty.

I’m going to say I don’t think you’re really asking for “extensions without extensions”. Extension is just the idea of a declaration not in the main body. What you’re really asking for is confusing limitations to be lifted so you can do things that seem logical using extensions across multiple files.

Some of these have valid technical reasons which may be somewhat difficult to work around, others are legacy limitations that could be lifted. I too would like to see the extensions limitations lifted wherever possible.

In general when you have classes that get too big refactoring into several classes is the correct solution.

How do other languages address this issue?

The only syntax I can imagine is another keyword that's the same as extension but has similar but not the same rules. OP hasn't really proposed what that would be.

When I run into this issue I either refactor or have a big class file. Swiftlint complains but I don't care.

C# has the ability to split files using the partial keyword like so:

SomeClass1.cs

public partial class SomeClass { 
    public SomeClass(string name, int age) 
    { 
        //...
    } 
} 

SomeClass2.cs

public partial class SomeClass { 
    public void DoStuffff() 
    { 
        //...
    } 
} 
2 Likes

I would like to add another use case to the discussion. While I'm not completely sold on the advantages of splitting a file within a project, I think splitting up files would definitely make sense for Swift scripting. At the moment, when you write a script in Swift (without a project around it) to run some tasks and that script gets a little bigger and you want to organize it, you have to create a project instead.

While some may say that this is by design, I think it is holding back many cool Swift scripts and is an unnecessary limitation staying in the way of "world domination" or even the goals for Swift 6 to become a more attractive language for cross-platform usage – people from other scripting languages take a possibility to import other Swift files for granted as it's a very common and flexibly useful feature.

You may be interested in these related discussions:

One of the many reasons I use extensions is to in fact split / group related logic into a separate file. Isolating related code into their own file not only helps reduce and group related clutter, but prevents accidental edits / changes. Often times it's just quicker to find and open a MyClass+DragAndDrop.swift file than to look for and edit any "drag and drop" related functionality within that class.

1 Like

i feel the idea is worth considering but it needs to be thought through. can you put stored variables in different files, or shall it be like in C++? there are pros and cons to that from usability standpoint.

reminded me of the thread: continuations - "extensions on steroids" idea

+1 from my side. I really need this ability for classes in Swift. Even if the class is 500 lines, it would still be useful.

Currently when segregating the functionality, we write conforming protocol methods in a separate extension. If the extension methods are a little big (e.g UITableViewDataSource), then I'd like to see this in a separate file where I declare the class as partial.

Another advantage we get from partial classes is that we can use private functions and properties defined in the initial declaration. Again taking the UITableView delegate as an example, if I declare the delegate methods in a separate file as an extension, then I wouldn't be able to use private functions/properties. I am forced to declare these without any modifiers (internal by default). Otherwise, I have to define all the extensions and methods in the same source file. This doesn't make any sense.

For those who say that logic has to be segregated, in many cases it's almost impossible or we end up writing unnecessary extra code. Let's take a scenario. I have page in mobile app, that has a table view and a collection view with different sections. The page also has extension methods to pick an image, document, date pickers, camera.

In this case all of the delegate methods have to be defined in the same source file even though I define these in respective extensions in the same source, the class looks much bigger. The reason of not being able to use or call private functions and properties limits my ability put these extensions in separate files. I cannot blame the UX designer to split the UI into multiple pages.

To minimize the no. of lines of code in a single view controller, I need to write content views and define the delegate and properties and these result in additional code where I need to assign the right data and handle UI flows. Here I end up writing multiple content views and view controllers plus view models.

All we have to do here is to allow the developers to have an option to keep the class declaration with methods and properties in multiple sources. The code reviewers will take care of the scattered classes in different folders. For individual developers I presume they study a lot and definitely be/become aware of best practices in the language they use.

Even with all good features and guidelines, we always find bad developers writing/misusing a lot of language features.

Adding partial classes is really a good option for mindful developers.

I've been using C# in my day job for almost 15 years, and the last time I saw the partial keyword being used was around about 14 years ago. In my experience it has always been considered a code smell that was better solved by splitting functionality into other classes, and its use only made code less readable and harder to organize.

The only exception to this that I've come across is auto-generated code, where part of the class is generated by a tool, and the 'human maintainable' part is in a separate file. I could see this as a good use case, but there might be better solutions to that problem.

1 Like

Using extension for classes incurs your methods can’t be overridden. Therefore, I support this idea

1 Like

We are autogenerating some swift code from an API design specification and an associated c-api that implements the business logic for that API. The autogenerated code ends up being types (structs, classes, protocols) that call into the associated c-api.

Partial classes would definitely help us to implement things that aren't generated quite correctly, or exactly how we want the Swift API to ultimately look.