How to avoid the duplication of a function in order to simplify code

Consider this code:

struct Element1 {
    var sky: Int
    var bird: [Int]
    var point: [[Double]]
    var weight: [Double]
}

struct Element2 {
    var ocean: Int
    var whale: [Int]
    var point: [Double]
    var weight: [Double]
}

func someFunction1(_ arg1: Int, _ arg2: Int, _ element: Element1) {
    // do something... and then call:
    someFunction2(element.point, element.weight)
    // then continue doing more stuff...
}

func someFunction1(_ arg1: Int, _ arg2: Int, _ element: Element2) {
    // do something... and then call:
    someFunction2(element.point, element.weight)
    // then continue doing more stuff...
}

func someFunction2(_ point: [Double], _ weight: [Double]) { // e.g.
    print(point, weight)
}

func someFunction2(_ point: [[Double]], _ weight: [Double]) { // e.g.
    for i in 0 ..< point.count {
        print(point[i], weight)
    }
}

How can I avoid the duplication of someFunction1 if the only thing that changes is the definition of the third argument?

PS: Forgot to mention that someFunction1 does not use the other properties of Element1 or Element2; only the point and weight properties.

Thank you,
Ricardo

I note that your point properties aren't the same, the first is an array of arrays of Double, and the second is an simple array of Double. Is that intentional?

Yes, that was intentional. That is the reason why I need to duplicate someFunction1 (because it seems that I cannot use a protocol). Any ideas about how to avoid the duplication?

Thank you,
Ricardo

Maybe something like

func theFunction(_ arg1: Int, _ arg2: Int, _ element: Any) {
    if element is Element1 {
        //some code
    } else if element is Element2 {
        //some other code
    }
}

This does have the disadvantage of needing to be extra vigilant about handling bad inputs, so maybe not worth it, but it might work.

Why is it that you cannot use a protocol? It would seem an ideal way to solve your issue

I also thought protocol is an ideal way to solve that problem. For instance

protocol WeightPoint {
  var points: [[Double]] { get }
  var weight: [Double] { get }
}

In that particular case, the type of “point” is different, but they are easy to differentiate. You could have:

struct Element1: WeightPoint {
    var sky: Int
    var bird: [Int]
    var points: [[Double]]
    var weight: [Double]
}

struct Element2: WeightPoint {
    var ocean: Int
    var whale: [Int]
    var point: [Double]
    var weight: [Double]
    // adding computed property just to do have an attribute of the same type; if you can’t change the definition, you could try an extension method
    var points: [[Double]] {
      return [point]
    }
}

Then you write your function as usual:

func someFunction1(_ arg1: Int, _ arg2: Int, _ element: WeightPoint) {
  // TODO
  someFunction2(element)
  // TODO
}
func someFunction2(_ weightPoint: WeightPoint) {
  // TODO
}

Davide, I thought that I could not use a protocol because the type of point happens to be distinct in both structs. However, as suggested by Ataias, the second struct can be modified to include a dummy variable called points so that both structs share the same variable name and type.

I will go ahead and test Hacksaw's and Ataias' approach and see which one fits better in my code. Thank you for all the ideas.

Ricardo

It seems like the only reason why your functions aren't generic is because point can be either [Double] or [[Double]] depending on its enclosing type.

One potential solution is to create a wrapping enum that's able to represent both Array and Array<Array>>. I've done something similar in one of my project.

Remember that “protocols are not bags of syntax”. You want to put the semantics you care about in the protocol.
To me it looks like the semantics you care about in this case are not the properties, but someFunction1. If you put that as the requirement you can have each type define it’s own and then have a single someFunction2