In JavaScript/TypeScript, we have this pattern that is often used in libraries where you have one optional parameter as the last function argument which defaults to some default configuration.
It looks like this:
const smth = someLibrary("requiredParameter", {
someOptionalProperty: true,
// ...other options available, but not required to be provided here.
});
On the library side it would look something like this:
export const someLibrary = (requiredParameter: string, options?: Options) => {
const opts = { ...defaultOptions, ...options };
// Here `opts` will have the default properties merged with the ones that you provided.
}
Now, in Swift, from what my 2-3 year experience has told me, if you want to do something similar you have to make a struct with all the configuration parameters and then mutate the defaults after instantiating the struct. This would look something like the following:
struct Options {
var option1: Double = 2.0
var option2: Int = 1
// ...etc
}
public func someLibrary(_ requiredParameter: String, options: Options?) {
// ...
}
let opts = Options()
opts.someParameter = "Overriding the values here"
let result = someLibrary("requiredParameter", options: )
The problem
There are a couple of problems with the Swift implementation that JavaScript does very well:
- Default options override, but just the fields that were changed – I haven’t been able to replicate this in swift with a solution that is at least close in elegance.
- Partial override of the options – the approach in Swift that I was using is to have an initializer for the struct with all optional parameters, but the initializers become huge for big configurations.
The question
Now the question is – how close can I get to the JavaScript version using Swift?
Maybe there’s a pattern or a function that I’m missing that would do that for me?
The goal for me is to not have huge boilerplate to make my library customisable.
2
Answers
Here a sample example :
This is a base that may help you, Here the subscript are an nice way go get values.
EDIT : added non typed access
EDIT 2 : added Float for type accuracy
You said:
No, you can also set the overrides when you initialize the
Options
, e.g.,No hairy “boilerplate hell” required.
So, yes, you can initialize it as a separate object and pass it as a parameter:
But you can also do it inline if you only have one or two overrides:
or
Theoretically, moving the defaults into the initializer is a tad more efficient:
I know you have dismissed this option as “boilerplate hell”, but sometimes it is the right approach (especially if any of these properties are computationally expensive or if you needed it to be a reference type, for example).
FWIW, Xcode also has “Editor” » “Refactor” » “Generate Memberwise Initializer” to simplify the generation of this initializer. Or, Xcode’s “multiple cursor” support (see Paul Hudson’s demonstration on YouTube) makes it pretty easy, too.