Type of expression is ambiguous without more context error

14,338

Solution 1

The Type of expression is ambiguous without more context error is stemming from two facts:

  1. Swift doesn't know how to add a DispatchTime and an Int.
  2. Because of fact 1, Swift doesn't know how to interpret .now().

Swift doesn't know how to add a DispatchTime and an Int

This can be demonstrated with:

let t = DispatchTime.now() + Int(5)

Binary operator '+' cannot be applied to operands of type 'DispatchTime' and 'Int'

but Swift does know how to add a DispatchTime and a Double:

let t = DispatchTime.now() + Double(5)

This compiles fine with no errors.

So why does DispatchQueue.main.asyncAfter(deadline: .now() + 5) work?

In this case, Swift is interpreting the integer literal 5 as a Double. Type Double conforms to the protocol ExpressibleByIntegerLiteral which is what allows you to do:

let d: Double = 5

So in this case, it works because 5 isn't an Int, it's a Double.

Because of fact 1, Swift doesn't know how to interpret .now()

When you tried to add an Int to .now():

DispatchQueue.main.asyncAfter(deadline: .now() + int)

the Swift type inference system got confused. Swift knows that it wants to pass a DispatchTime to asyncAfter(deadline:), but it no longer could figure out what .now() is because there is no way to add a DispatchTime and an Int to get a DispatchTime, it decided that .now() was not a DispatchTime but some other unknown type. So the ambiguous error message is coming from Swift's inability to determine what .now() is.

If you make that explicit by saying DispatchTime.now(), then you get a more sensible error:

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + int)

Binary operator '+' cannot be applied to operands of type 'DispatchTime' and 'Int'

As further evidence of this theory, if you provide Swift a way to add a DispatchTime and an Int, Swift is happy with your original code:

func +(_ lhs: DispatchTime, _ rhs: Int) -> DispatchTime {
    return lhs + .seconds(rhs)
}

So what is this .seconds() stuff? And how does it help solve the error?

There is a related enum type DispatchTimeInterval that has cases microseconds(Int), milliseconds(Int), nanoseconds(Int), seconds(Int) and never. Swift knows how to add a DispatchTime and a DispatchTimeInterval, so Swift is able to interpret .seconds(int) as a DispatchTimeInterval which then allows it to interpret .now() as a DispatchTime.

Why did the Swift designers choose to let you add a Double to a DispatchTime and not an Int?

You'd have to ask them. I suspect they chose the Double out of convenience (allowing literal values such as 2.5 to be used) and because it allows you to specify time intervals smaller than one second. The Int doesn't give you any extra capabilities (except of course for eliminating this very confusing error message).

Conclusion

The error is coming from the fact that you confused Swift's type inference system by trying to add an Int to a DispatchTime.

The fixes as the other answers suggested:

  1. Use a Double.

    or

  2. Use the DispatchTimeInterval enum to explicitly note what your Int represents. In your case .seconds(int).

Solution 2

You need to use a double variable to add to the .now().

var delay: Double = 0
while delay < 100 {
        DispatchQueue.main.asyncAfter(deadline: .now() + delay) { // change 2 to desired number of seconds
            // do stuff
        }
        int += 1
}

Solution 3

You can do DispatchTime math with literals

DispatchQueue.main.asyncAfter(deadline: .now() + 2)

but not with an Int variable, that's the ambiguity. There is a DispatchTimeInterval enum to be able to pass an Int variable

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(int))
Share:
14,338
D-A UK
Author by

D-A UK

Updated on July 28, 2022

Comments

  • D-A UK
    D-A UK almost 2 years

    How do I fix this code so it doesn't give the error: Type of expression is ambiguous without more context?

    var int = 0
    while int < 100 {
            DispatchQueue.main.asyncAfter(deadline: .now() + int) { // change 2 to desired number of seconds
                // do stuff
            }
            int += 1
    }
    

    The code is being run in dispatch queue in applicationDidEnterBackground, in an attempt to make text to speech work in the background.

  • Rakesha Shastri
    Rakesha Shastri almost 6 years
    Hi. I was actually waiting for someone more experienced to answer :D. Why can you add a Double variable to DispatchTime?
  • vadian
    vadian almost 6 years
    Good question, next question 😉. I have no idea particularly the raw value of DispatchTime is even UInt64
  • Rakesha Shastri
    Rakesha Shastri almost 6 years
    Thanks a bunch for this!