Swift Type Inference and Type Checking Issue

Swift type inference and type checking issue

In your b case, let value = param bridges value to an NSNumber type. For NSNumber, value is Int will always be true.

For unbridged values:

a is Int // always true, AnyObject bridges to NSNumber here
b is Int // false, cast from Float to Int always fails
c is Int // false, cast from Double to Int always fails

This answer assumes Foundation has been imported. Without Foundation, your assignments will fail.

Type inference issue with Swift's Double initializer for shifted integer parameters

This looks like a bug in the compiler. As @Hamish said, the latest master has this problem fixed, I can confirm that as I have the toolchains for Swift 4.2 and Swift 5.0 installed:

  • with the Swift 4.2 toolchain the behaviour is as you described: the first print outputs 0.0, while the second one outputs 65536.0
  • while if using the latest Swift 5.0 toolchain, both calls print 65536.0

Swift Type Checking Takes Too Long on Very Short Function

I think it's the ternary operator.

I had similar results in Xcode 11 (~93ms) but the compile time decreases to ~23ms with:

func someKey(_ sectionType: SectionType, row: Int) -> String {

var suffix = "top"

if row != 0 {
suffix = "content"
}

return "\(sectionType)_\(suffix)"
}

By changing the logic on this line, I think we can prove it's the ternary logic because the method reduces to ~1ms. I've just made row a Boolean.

func someKey(_ sectionType: SectionType, row: Bool) -> String {
let suffix = row ? "top" : "content"
return "\(sectionType)_\(suffix)"
}

Equally (no pun intended) changing the ternary logic to let suffix = row != 0 ? "top" : "content" halves the compile time. Which is comparable to my first code block. != is faster for Swift to understand than ==.

The compiler is unable to type-check this expression swift 4?

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

This error appears when swift compiler finds the expression calculation lengthy. For more details check here

To resolve this, you just need to break your expression into smaller parts. Just like:

let cutOutxOrigin = 3 * cutOutViewX.constant / 2
let actualPadding = (options.textWidth + padding * 2) / 2

let spaceFromRightSide = cutOutxOrigin + actualPadding

Swift type inference in methods that can throw and cannot

Obviously you should never, ever write code like this. It's has way too many ways it can bite you, and as you see, it is. But let's see why.

First, try is just a decoration in Swift. It's not for the compiler. It's for you. The compiler works out all the types, and then determines whether a try was necessary. It doesn't use try to figure out the types. You can see this in practice here:

class X {
func x() throws -> X {
return self
}
}

let y = try X().x().x()

You only need try one time, even though there are multiple throwing calls in the chain. Imagine how this would work if you'd created overloads on x() based on throws vs non-throws. The answer is "it doesn't matter" because the compiler doesn't care about the try.

Next there's the issue of type inference vs type coercion. This is type inference:

let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'

Swift will never infer an ambiguous type. This could be Any or it could beInt`, so it gives up.

This is not type inference (the type is known):

let result1: Int = myClass.fun1() // OK

This also has a known, unambiguous type (note no ?):

let x : Any = try myClass.fun1()

But this requires type coercion (much like your print example)

let x : Any = try? myClass.fun1() // Expression implicitly coerced from `Int?` to `Any`
// No calls to throwing function occur within 'try' expression

Why does this call the Int version? try? return an Optional (which is an Any). So Swift has the option here of an expression that returns Int? and coercing that to Any or Any? and coercing that to Any. Swift pretty much always prefers real types to Any (and it properly hates Any?). This is one of the many reasons to avoid Any in your code. It interacts with Optional in bizarre ways. It's arguable that this should be an error instead, but Any is such a squirrelly type that it's very hard to nail down all its corner cases.

So how does this apply to print? The parameter of print is Any, so this is like the let x: Any =... example rather than like the let x =... example.

A few automatic coercions to keep in mind when thinking about these things:

  • Every T can be trivially coerced to T?
  • Every T can be explicitly coerced to Any
  • Every T? can also be explicitly coerce to Any

    • Any can be trivially coerced to Any? (also Any??, Any???, and Any????, etc)
    • Any? (Any??, Any???, etc) can be explicitly coerced to Any
  • Every non-throwing function can be trivially coerced to a throwing version

    • So overloading purely on "throws" is dangerous

So mixing throws/non-throws conversions with Any/Any? conversions, and throwing try? into the mix (which promotes everything into an optional), you've created a perfect storm of confusion.

Obviously you should never, ever write code like this.

How does type inference (automatic type detection) works in swift?

The compiler does its job in steps and type inference is one step in this process.

Step 1: Lexical analysis

Typically, as a first step, the compiler does a lexical analysis in which it splits input file bytes to units like numbers and strings (note: not yet string in the same meaning that you are referring) and throws away whitespace and comments.

For example, it splits the input stream in the example to var, str, =, ", string, ".

Step 2: Syntax analysis

The second step is a syntax analysis or parsing, in which compiler constructs and verifies an abstract syntax tree based on the grammar of the language.

In this case it would construct an abstract syntax tree representing a variable declaration statement (see Declaration statements in the language reference) of the form:

var variable_name = expression

in which expression is a string literal:

var variable_name = string_literal

Step 3: Semantic analysis (with type inference)

The third step is semantic analysis and type inference happens in this step. In this case, type inference infers that the type of string literal is String and because there is no other information about the variable str, it will infer that str must be a String, because the expression, the right hand side of the variable declaration, is of type String.

There are more steps after this step. As next steps, the compiler typically generates intermediate code, then optimizes the intermediate code, and finally generates assembly code. After that the tool chain outside of the compiler usually has at least a linking phase that produces the final executable.

why does guard break type inference?

TLDR; single line closure compilation is different from multi line

Long answer: Let’s forget single line closures for sometime. When we write generic function accepting a generic as argument type and then call this function, compiler needs to know at time of invocation about what’s the type of function needed i.e. the type of its argument. Now consider this argument is a closure. Again compiler needs to know what’s the type of closure (function signature) at time of invocation. This info should be available in the signature of the closure (i.e. argument and return type), compiler doesn’t worry (and rightly so) about the body of the closure. So Service A is behaving perfectly as expected from compiler i.e. the closure signature doesn’t give any clue of its type.

Now comes in single line closure. Swift compiler has a built in type inference optimisation for single line closures only. When you write single line closure, compiler first kicks in its type inference and try to figure out about the closure including its return type etc from its only single line of body . This type inference kicks in for single line closures (with or without the context of generics).
This type inference is the reason that your service B works

So I’ll rephrase the question as “Why does the type inference works for single line closures?” because that’s an extra feature provided by Swift for single line closures only. As soon as you move to multi line closure (its not guard statement specific, same will happen if you put print(“hello world”) as well), this type inference is no more available. Though there may be other type inference checks available for multi line closures.

What you can do is just provide the Type info in closure signature
i.e (result: Response< Model >)



Related Topics



Leave a reply



Submit