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 outputs65536.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 be
Int`, 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
Is There Any Difference at All Between Suffix(From:) and Dropfirst(_:)
Cannot Convert Value of Type 'X' to Expected Argument Type 'X'
Which Optimization Level Should I Choose for Release
A Concise Way to Not Execute a Loop Now That C-Style for Loops Are Going to Be Removed from Swift 3
Performseguewithidentifier Not Working If Called from Viewdidload
How to Put View on Top of All Other Views in Swiftui
Viewwilllayoutsubviews in Swift
Scrolltoitem at Indexpath at .Top Hides Cell Under Header When Sectionheaderspintovisiblebounds
Swift Navigation Bar Item Not Calling Action
Implement Protocol with Different Associated Type
Why I Can Not Use Setvalue for Dictionary
How to Define a Variable in a Swift If Statement
Filtering Realm Objects with Swift
Keyboard Height Change Observer Swift
How to Get The Push Notifications Displayed in The Notification Center
Swift Nwlistener Listen, Cancel, and Relisten Successfully
Access Parent Project Other_Swift_Flags from Pod
Get Applicationdidfinishlaunching Call in a View Controller. Parse Not Initialized Yet