Xcode 8 :function types cannot have argument label breaking my build
Asked Answered
J

5

80

It seems that for some reason Swift have chosen to make coding in it less readable by forcing users to remove completion handler parameter labels. I have read the Swift discussion and still think it's a mistake. At least they could have made it optional.

When building using Xcode 8 - is there a way to force the compiler to use Swift 2.3 so I don't get these errors anymore? I have updated the option to use legacy Swift (under build settings) legacy support in xcode but I still seem to get this error:

Function types cannot have argument label 'isloggedIn'; use '_' instead

error Xcode 8

How can I keep my labels in my completion handlers?

Janie answered 21/9, 2016 at 9:56 Comment(12)
It looks like it's just saying you can't have the parameter named 'error', not that you can't give it a name. Have you tried renaming 'error' to something else?Maracanda
Yes it still doesn't workJanie
did you find a solution?Halona
@Maracanda Swift 3 explicitly prohibits using argument labels in function types. Questionable choice, very frustrating.Halona
Frustrating and annoying. I am ripping out good code to make it less readable and prone to errorsJanie
@Halona do you have a link to where this is documented? I'm having trouble finding any reference to this change.Crosseye
@sjwarner yes could not find the SO answer which mentioned it, but found the swift evolution discussion and posted as answerHalona
Can you guys share link? Maybe we should present a revised version for swift 3.1Janie
I am absolutely hating this change.Janie
It seems like Swift 3 is trying to be too philosophically impeccable, and human history tells us it's not the most efficient way to go about things. Absolutely hate a lot of the changes in Swift 3Marchesa
This is totally BS change which lead to a lot lot of confusions in coding with closure, either have to go to the function/type declaration to see, or all you got is meaningless (Int, String, Error,....), it doesnt even making any sense, Objective-C block is way better because its autocomplete already give you the arguments nameHerein
I agree ! - we should follow up with the status ..I assume it wasn’t in swift 4Janie
H
109

The Swift designers decided to prohibit argument labels for function types.

The reasoning is explained here: https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md

This is a frustrating and questionable choice, as prohibiting argument labels makes it much easier to incorrectly invoke closures, which seems more important than simplifying the language's type system.

Usability > ideology.

Halona answered 27/9, 2016 at 6:35 Comment(8)
I Agree with this - but its not really a solution. I will suggest we work to put a proposal in to potentially make this optional.Janie
Have added this as the current solution as its really well explainedJanie
Still no sign of the solution I suggested in Swift 3.1 - here's hoping we get it before swift 4.. hate this change soo much!!Janie
@Halona But so how one can get arguments passed through those functions?!Envelop
@matterGoal what do you mean?Janie
@Envelop Of course you can use the unnamed argument names -- $0 etc. -- or you can used the named arguments. You're just not allow to enforce that the caller uses a name, but from inside the function the arguments can be named.Microcline
this is not right, I might not be wrong in saying we all have loved this feature, it makes for easier readability, less looking at the documentation and more knowledge regarding what each param is about. If used correctly it can even be used to complement the function call and describe it. I really wish for it to be put back in. This is a step backwards.Courtenay
Until then, typealias to the rescue. if (isSuccess:Bool) -> Void is not allowed due to the label, then we can have typealias IsSuccess = Bool and use (IsSuccess) -> VoidMouseear
C
30

A workaround to consider. You can't do:

func doStuff(completion: (foo: Int, bar: String) -> Void) {
    ...
    completion(foo: 0, bar: "")
}

... but you can do:

func doStuff(completion: ((foo: Int, bar: String)) -> Void) {
    ...
    completion((foo: 0, bar: ""))
}

i.e. have a single unnamed argument to your closure which is a tuple, in this case (foo: Int, bar: String).

It's ugly in its own way, but at least you retain the argument labels.

Crosseye answered 28/9, 2016 at 4:16 Comment(3)
any idea how to make this work with typealias public typealias ImageDataCompletion = (((imgData imgData: Data?, _ err: MYGR8TErrorClass?)) -> Void) gives: ... Tuple element cannot have two labels!!!! wtf????Doradorado
@AntonTropashko: (((imgData imgData: Data?, _ err: MYGR8TErrorClass?)) -> Void) should be (((imgData: Data?, err: MYGR8TErrorClass?)) -> Void). You're trying to label your tuple elements twiceCrosseye
A limitation of this solution is tuples cannot have a single value.Conduction
J
14

Based on the information above - it appears that the only way to really fix this and ensure that its performant is to raise a proposal to Make argument labels optional with a view to :

  1. improving the speed of development ( without argument labels it requires us to scroll up to the top of the method each time we put in the completion handler.
  2. Reduce Errors : ( I have already had several errors caused due to incorrect completion handler entries especially with those that expect boolean values)
  3. Make code more readable across team members. Not everyone has only one team member and thus being able to easily pick up other peoples code is a must have.
  4. Lastly good programming practice means that the solution should look as much like the actual item being developed. completionhandler: (newvalues, nil) looks less like the item being managed than completionhandler(results: newValue, error:nil)

I would love for people reading this to share their feedback/ comments on this below before I submit it so I can show there are others that support this.

Edit: I have submitted the pitch here : https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161010/028083.html which appears to have been agreed. It looks like its going to happen, however the discussion is whether this is submitted as a Swift 4 improvement ( highly probable)

Janie answered 13/10, 2016 at 9:29 Comment(5)
Okay, since you asked for it let me vent: won't be the first time when opensource monkeys have screwed something (useable before their valuable contribution),. Amen.Doradorado
@AntonTropashko upvote for venting on stack overflow - hope you feel better ??Janie
upvoted the answer too! what a relief! seriously: noDoradorado
@MobileBloke what's the status of this? I don't see that it got in the language...Radburn
Nope - looks like its been deprioritized. Its still so annoying.Janie
B
9

You have to use _ to make your parameters unnamed, and that is unfortunate. Instead of tacking _ on to each parameter and then blindly calling your function I would suggest making a wrapper object.

Since losing named parameters for function types introduces more risk that you will call the function with the wrong values, I would suggest wrapping the parameters in a struct and having that be the one and only parameter to your function.

This way the fields of you struct are named, and there is only one type of value to pass into your function. It is more cumbersome than if we were able to name the parameters of the function, but we can't. At least this way you'll be safer and you'll feel less dirty.

struct LineNoteCellState {

    var lineNoteText: String?
    var printOnInvoice = false
    var printOnLabel = false
}

Here is an example of it being used:

cell.configure(editCallback: { (_ state: LineNoteCellState) in

    self.lineNoteText = state.lineNoteText
    self.printOnInvoice = state.printOnInvoice
    self.printOnLabel = state.printOnLabel
})
Black answered 3/1, 2017 at 16:26 Comment(0)
L
6

Semi-workaround, note the _

completion: (_ success: Bool) -> Void
Lakia answered 9/11, 2016 at 10:59 Comment(2)
This doesn't seem to autocomplete for me - Whats the function of the underscore before the success param?Janie
How does this work? How can i access success in this case?Wintry

© 2022 - 2024 — McMap. All rights reserved.