1
\$\begingroup\$

Trying to simply my code below:

for (index, point) in enumerate(self.points){
        let pointButton = UIButton()
        pointButton.frame = point.bounds
        self.view.addSubview(pointButton)
    }

Is there a better way to accomplish this through .map .filter or .reduce ?

\$\endgroup\$
7
  • 1
    \$\begingroup\$ you could, but honestly, having self.view.addSubview() removes any point of doing so because that is a side-effect. I don't know enough Swift to write this out, but you would want to use map over the self.points collection and have it return your pointButton, and then the mapped array as subviews. \$\endgroup\$
    – Dan
    Jul 10, 2015 at 23:59
  • \$\begingroup\$ Thanks. Can you please elaborate on the side-effect? \$\endgroup\$ Jul 11, 2015 at 0:01
  • 1
    \$\begingroup\$ I'll try; basically, in FP, you generally strive to create 'pure functions' - they only operate on the arguments they are passed in, only interact with other pure functions, always return a value and they don't modify existing values/outside world. By having self.view.addSubview() in the function, you are causing a side effect because you are modifying the outside world (self.view.addSubview() stores state). Obviously every useful program uses state, but using map "just because" doesn't make it FP because of the reasons I've mentioned. \$\endgroup\$
    – Dan
    Jul 11, 2015 at 0:04
  • 1
    \$\begingroup\$ In reality there's likely a nicer way to write this using map, but you're going to have to separate this out into multiple functions and I just don't know enough swift (any) to do that. Maybe someone else will, I think we have a few swift users here \$\endgroup\$
    – Dan
    Jul 11, 2015 at 0:09
  • 1
    \$\begingroup\$ Why are you using enumerateif you're not using the index? \$\endgroup\$
    – Veedrac
    Jul 11, 2015 at 0:59

1 Answer 1

3
\$\begingroup\$

The index is not used at all, therefore you do not need enumerate():

for point in self.points { ... }

(You mentioned in a comment that the index is used somewhere else, but we can review only the code that is shown in your question.)

let pointButton = UIButton()
pointButton.frame = point.bounds

can be simplified to

let pointButton = UIButton(frame: point.bounds)

and then you could get rid of the intermediate variable:

for point in self.points {
    self.view.addSubview(UIButton(frame: point.bounds))
}

and this looks like the best solution in your case to me.

You could use map() for that purpose:

self.points.map {
    self.view.addSubview(UIButton(frame: $0.bounds))
}

But using map() for its side effects is frowned-upon, see for example Higher order function: “Cannot invoke 'map' with an argument list of type '((_) -> _)'”, where an explicit foreach method is offered as an alternative:

extension Array {
    func foreach(function: T -> ()) {
        for elem in self {
            function(elem)
        }
    }
}

which can be used as

self.points.foreach {
    self.view.addSubview(UIButton(frame: $0.bounds))
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.