SwiftUI.withAnimation(_:_:): first param has default value so why withAnimation(doIt) doesn't compile?

public func withAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result

see the first parameter has default value but this doesn't compile:

// Function produces expected type '()'; did you mean to call it with '()'?
// Missing argument for parameter #1 in call
withAnimation(doIt)

it's fine with trailing closure syntax, or explicitly passing in the first parameter:

Button("Toggle 1")  {
    withAnimation {
        doIt()
    }
}

// or

Button("Toggle 3")  {
    withAnimation(.default, doIt)   // this works!
}
Sample Code
import SwiftUI

// public func withAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result

struct WithAnimationBlock: View {
    @State var flag = false

    func doIt() {
        flag.toggle()
    }

    var body: some View {
        VStack {
            Circle()
                .frame(width: flag ? 100 : 200)
            Button("Toggle 1")  {
                withAnimation {
                    doIt()
                }
            }
            Button("Toggle 2")  {
                // Function produces expected type '()'; did you mean to call it with '()'?
                // Missing argument for parameter #1 in call
                withAnimation(doIt)
            }
            Button("Toggle 3")  {
                withAnimation(.default, doIt)   // this works!
            }
        }
    }
}

struct WithAnimationBlock_Previews: PreviewProvider {
    static var previews: some View {
        WithAnimationBlock()
    }
}

Your question is too specific. The problem arises with any function that has unlabeled parameters, with anything but the last one having a default.

It's a compiler bug. See if it's logged already, and if not, do it!

func ƒ(_: Int = 0, _: Bool) { }
ƒ(false)  // Missing argument for parameter #1 in call

I did a search for "unlabeled parameter" and did not see any bug report related to this. So I created:

SR-14005: Omit any leading unlabeled function parameters with default cause "error: missing argument for parameter #n in call"

2 Likes

My bug report was closed "nothing to fix, intended behavior". It referenced this:

The language guide recommends:

Place parameters that don’t have default values at the beginning of a function’s parameter list, before the parameters that have default values.

but you can totally go against this recommendation if the func can be called with trailing closure syntax:

func f(_ a: Int = 1, _ b: Int = 2, zzz: () -> Void, xxx: () -> Void) {
    print("You call f, a: \(a), b: \(b)")
    zzz()
    xxx()
}

print("\n1111")
// okay
f {
    print("In closure 1111")
}
xxx: {
    print("In closure 2222")
}

print("\n2222")
// okay a assigned with 111, b take default
f(111) {
    print("In closure 1111")
}
xxx: {
    print("In closure 2222")
}

print("\n3333")
// okay a and b overridden
f(111, 222) {
    print("In closure 1111")
}
xxx: {
    print("In closure 2222")
}

// you can even have non-closure params with no defaults follow params with defaults!!!
func g(_ a: Int = 1, _ b: Int = 2, c: Int, d: Int, zzz: () -> Void, xxx: () -> Void) {
    print("You call g, a: \(a), b: \(b), c: \(c), d: \(d)")
    zzz()
    xxx()
}

print("\n4444")
// ok
g(c: 555, d: 666) {
    print("In closure 1111")
}
xxx: {
    print("In closure 2222")
}

print("\n5555")
// ok 111 assigned to a, b is default
g(111, c: 555, d: 666) {
    print("In closure 1111")
}
xxx: {
    print("In closure 2222")
}

print("\n6666")
// ok a and b overridden
g(111, 222, c: 555, d: 666) {
    print("In closure 1111")
}
xxx: {
    print("In closure 2222")
}

My guess is because trailing closure calling syntax is processed differently? Maybe parameters are match in reverse so it's okay to have params with defaults at the beginning?

It seems trailing closure calling syntax contradicts that recommendation: the ordering rule is reversed in fact.

Because of this, I think the compiler should reject any func with params with defaults precede params with no default unless this func can be called with trailing closure syntax.

And then if this func is not called with trailing closure syntax, the compile error should say params with defaults must be explicitly specified at call site, or change calling to trailing closure syntax. This would totally clear up my original confusion. Don't just show this:

Missing argument for parameter #1 in call

1 Like
Terms of Service

Privacy Policy

Cookie Policy