Missing declaration with default argument

Is this code wrong, or is this a known issue?

final class Foo {
    //@inlinable @inline(_always)
    static func bar(_ first: String = "default", _ second: Int) {
        print(first,second)
    }
}

Foo.bar(2)

Will result:

1 Like

My understanding is that the compiler fills in arguments “greedily”, by matching argument labels. It will freely skip any parameter whose label does not match, as long as it has a default value. But it doesn’t try to type-check the expression until after it has figured out what arguments are being passed in for which parameters.

The Language Guide does say “Place parameters that don’t have default values at the beginning of a function’s parameter list, before the parameters that have default values.”

Moreover, as a general rule of thumb, any parameter with a default value should also have an argument label (unless the function only takes one argument).

2 Likes

@Nevin is right, you need to place your arguments without a default value at the beginning.

If you want to omit argument labels, this will work:

final class Foo {
    //@inlinable @inline(_always)
    static func bar(_ first: Int, _ second: String = "default") {
        print(first, second)
    }
}

Foo.bar(2)

But if you can live with them, the following will also work:

final class Foo {
    //@inlinable @inline(_always)
    static func bar(first: String = "default", second: Int) {
        print(first,second)
    }
}

Foo.bar(second: 2)
1 Like

Even if there are general rules of thumb and recommendations (about putting parameters with default arguments last and not leaving out their labels unless they are the only parameter), there is still a question of whether this is intended behavior or a bug.

With the compiler's current behavior, there is no way to call this function that uses the default argument:

func bar(_ first: String = "default", _ second: Int) {
    print(first, second)
}
bar(2) // ERROR: Missing argument for parameter #2 in call

If this is intended behavior, then why isn't the error at the function declaration and its unusable default argument?

Also, implementing it like this does work:

func bar(_ first: String, _ second: Int) {
    print(first, second)
}
func bar(_ second: Int) {
    print("default", second)
}
bar(2) // Prints default 2

so why couldn't the first example also be made to work?

2 Likes

@Jens This is what i wanted to say, you spoke my heart. thank you

It probably could technically be made to work, but I think it would require heroic effort from the type checker in all but the simplest cases (e.g. trying all possible combinations of mappings of arguments to parameters, something like generating a large overload set in your manual expansion terms). It should probably be a warning at the definition point, though.