1

I'm working on a package that has many custom parameters with default values. Given that there are so many potential initializers it can quickly become confusing to properly order everything when you change many parameters.

I have a two part question:

  1. Is there a way to remove the ordering requirement from initialization?
  2. If not – is there a better way to structure custom parameters for this package? What do other developers recommend?

I considered using view modifiers but unsure how effectively that'd work given this package structure.

Struct initialization & utilization are below.

public struct LineChart: View {
    public var data: [Double]
    public var title: String?
    public var subtitle: String?
    public var floatingPointNumberFormat: String
    public var cursorColor: Color
    public var curvedLines: Bool
    public var displayChartStats: Bool
    public var minWidth: CGFloat
    public var minHeight: CGFloat
    public var maxWidth: CGFloat
    public var maxHeight: CGFloat
    
    public var titleFont: Font
    public var subtitleFont: Font
    public var priceFont: Font
    public var fullScreen: Bool
    
    private var chartStyle: ChartStyle = Styles.lineChartStyleOne
    
    public init (data: [Double],
                 title: String? = nil,
                 subtitle: String? = nil,
                 style: LineChartStyle? = .primary,
                 curvedLines: Bool = true,
                 cursorColor: Color = Colors.IndicatorKnob,
                 displayChartStats: Bool = false,
                 minWidth: CGFloat = 0,
                 minHeight: CGFloat = 0,
                 maxWidth: CGFloat = .infinity,
                 maxHeight: CGFloat = .infinity,
                 titleFont: Font = .system(size: 30, weight: .regular, design: .rounded),
                 subtitleFont: Font = .system(size: 14, weight: .light, design: .rounded),
                 dataFont: Font = .system(size: 16, weight: .bold, design: .monospaced),
                 floatingPointNumberFormat: String = "%.1f",
                 fullScreen: Bool = false) {
        
        // Assign data
        self.data = data
        self.title = title
        self.subtitle = subtitle
        self.floatingPointNumberFormat = floatingPointNumberFormat
        self.cursorColor = cursorColor
        self.curvedLines = curvedLines
        self.displayChartStats = displayChartStats
        self.minHeight = minHeight
        self.minWidth = minWidth
        self.maxHeight = maxHeight
        self.maxWidth = maxWidth
        self.subtitleFont = subtitleFont
        self.titleFont = titleFont
        self.priceFont = dataFont
        self.fullScreen = fullScreen
        
        switch style {
        case .custom(let customStyle): self.chartStyle = customStyle
        case .primary: self.chartStyle = Styles.lineChartStyleTwo
        case .secondary: self.chartStyle = Styles.lineChartStyleThree
        case .tertiary: self.chartStyle = Styles.lineChartStyleFour
        default: self.chartStyle = Styles.lineChartStyleOne
        }
    }
    
    
    public var body: some View {
        LineChartView(data: self.data, title: self.title, legend: self.subtitle, style: self.chartStyle,  valueSpecifier: self.floatingPointNumberFormat, cursorColor: self.cursorColor, curvedLines: self.curvedLines, displayChartStats: self.displayChartStats, minWidth: self.minWidth, minHeight: self.minHeight, maxWidth: self.maxWidth, maxHeight: maxHeight, titleFont: self.titleFont, subtitleFont: self.subtitleFont, priceFont: self.priceFont)
    }
}
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
Alex Fine
  • 139
  • 1
  • 9
  • "Is there a way to remove the ordering requirement from initialization?" No. The existence of explicit parameter labels and/or default values does not change the rule that parameters must be supplied in the same order at the call site. I don't like it either, but that's Swift. – matt Oct 02 '20 at 19:22
  • "is there a better way" Please don't ask opinion-based questions on Stack Overflow. You can declare more than one initializer if you want the caller to be able to put things in a different order, but that is _not_ the usual way things are done and is likely to be more confusing. What you have is clear and unambiguous, and, remember, no one is ever going to type this stuff out by hand; code completion will take care of it. – matt Oct 02 '20 at 19:24
  • 1
    "is there a better way" could be interpreted as "my code does not work as desired how can I fix this code" – which falls into the purview of Stack Overflow. How do other developers solve this problem? I agree multiple initializers would be more confusing, especially p! initializers (where p is the number of parameters). Has the Swift community simply accepted the suckiness of this use case? – Alex Fine Oct 02 '20 at 19:38
  • Your code _does_ work, so it's not quite fair to pretend it doesn't. And as I already said, Swift doesn't permit the parameters to be reordered at the call site, and that's that. Take a look at something like https://developer.apple.com/documentation/uikit/uiaction/3358590-init. Very parallel to yours (i.e. the first param is nonoptional and the rest have default values). It's not really a matter of "use case", it's just that these are the rules. No, we haven't "accepted it" - there are alternate proposals - but this is the situation currently, so we do suck it up. – matt Oct 02 '20 at 19:50
  • 1
    Also, given that (as I said earlier) autocompletion lays the whole thing out on a silver platter for you, I do not see what the user is going to find "confusing" about this. Annoying, maybe, but not confusing. – matt Oct 02 '20 at 19:52
  • Wild that Apple hasn't addressed this – hopefully they release a solution in a future Swift build. Is there any intrinsic reason ordering must be strict or is it simply for semantic consistency? – Alex Fine Oct 02 '20 at 21:13

0 Answers0