Help me be DRY...for same set of let's inside multiple func's from the same func param

Please see comments inside my code:

func bodyVersionA(_ proxy: Double) {
    // many of these let's, scale from input param
    let spacing = proxy / 77
    let largeInset = proxy / 3
    let mediumInset = proxy / 8
    // many more of these etc, etc

    // go on to make the view in VersionA style, we just do print as example
    print(spacing, largeInset, mediumInset, separator: ",    ")
}

func bodyVersionB(_ proxy: Double) {
    // the exact same set of let's as in bodyVersionA(), must be sync'ed
    // how to be DRY?
    let spacing = proxy / 77
    let largeInset = proxy / 3
    let mediumInset = proxy / 8
    // many more of these etc, etc

    // go on to make the view in VersionB style, we just do print as example
    print(spacing, largeInset, mediumInset, separator: ",    ")
}

// so the same set of let's above are repeated, must kept in sync'ed on both

// How about I do it this way? is this a good idea?
// one func to compute all these parameters
func computeParameters(_ proxy: Double) -> (spacing: Double, largeInset: Double, mediumInset: Double) {
    // turns out this can be in any order and result is still the same tuple, good...
    return (
        // purposely in differnt order and it's no problem, good...
        largeInset: proxy / 3,
        spacing: proxy / 77,
        mediumInset: proxy / 8
    )
}

func bodyVersionA_DRY_UP(_ proxy: Double) {
    // now it's one let, computation is not repeated, but... one tiny problem unfortunately
    // if the order here is wrong, the wrong value is assigned, bad...
    // is there anyway to enforce the right order?
    let (spacing, largeInset, mediumInset) = computeParameters(proxy)

    // go on to make the view in VersionA style, we just do print as example
    print(spacing, largeInset, mediumInset, separator: ",    ")
}

func bodyVersionB_DRY_UP(_ proxy: Double) {
    // same as above, now computation is inside one place...
    let (spacing, largeInset, mediumInset) = computeParameters(proxy)

    // go on to make the view in VersionB style, we just do print as example
    print(spacing, largeInset, mediumInset, separator: ",    ")
}

bodyVersionA(100)
bodyVersionB(100)
bodyVersionA_DRY_UP(100)
bodyVersionB_DRY_UP(100)

Obvious answer here is to define a struct ViewMetrics or whatever, that declares the fields. Then, you can never screw up and use the wrong one. Tuples as multi-return values get confusing, fast.

If you do want to use a tuple, the other formulation would be to write let metrics = computeParameters(proxy) and then refer to the elements of the tuple by their named labels metrics.spacing, metrics.largeInset, metrics.mediumInset etcetera.

1 Like

As an option, you could also have the said struct storage be tuple,

struct ViewMetrics {
  var values: (spacing: Double, largeInset: Double, medium: Double)
}

Should you decide that you want to get them into local variables for most use cases:

let (spacing, largeInset, _) = proxy.value
1 Like

I see both options now...for my current case, must use a member func because the compute is dependent on the View's properties.

:pray:

That’s fine, do your logic in the member function and return a struct with your values.

1 Like