I find this amusing more than anything. I\'ve fixed it, but I\'m wondering about the cause. Here is the error: DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
. Why is it complaining? It seems like one of the most simple expressions possible.
The compiler points to the columns + \");\";
section
func tableName() -> String { return(\"users\"); }
func createTableStatement(schema: [String]) -> String {
var schema = schema;
schema.append(\"id string\");
schema.append(\"created integer\");
schema.append(\"updated integer\");
schema.append(\"model blob\");
var columns: String = \",\".join(schema);
var statement = \"create table if not exists \" + self.tableName() + \"(\" + columns + \");\";
return(statement);
}
the fix is:
var statement = \"create table if not exists \" + self.tableName();
statement += \"(\" + columns + \");\";
this also works (via @efischency) but I don\'t like it as much because I think the (
get lost:
var statement = \"create table if not exists \\(self.tableName()) (\\(columns))\"
I am not an expert on compilers - I don\'t know if this answer will \"change how you think in a meaningful way,\" but my understanding of the problem is this:
It has to do with type inference. Each time you use the +
operator, Swift has to search through all of the possible overloads for +
and infer which version of +
you are using. I counted just under 30 overloads for the +
operator. That\'s a lot of possibilities, and when you chain 4 or 5 +
operations together and ask the compiler to infer all of the arguments, you are asking a lot more than it might appear at first glance.
That inference can get complicated - for example, if you add a UInt8
and an Int
using +
, the output will be an Int
, but there\'s some work that goes into evaluating the rules for mixing types with operators.
And when you are using literals, like the String
literals in your example, the compiler doing the work of converting the String
literal to a String
, and then doing the work of infering the argument and return types for the +
operator, etc.
If an expression is sufficiently complex - i.e., it requires the compiler to make too many inferences about the arguments and the operators - it quits and tells you that it quit.
Having the compiler quit once an expression reaches a certain level of complexity is intentional. The alternative is to let the compiler try and do it, and see if it can, but that is risky - the compiler could go on trying forever, bog down, or just crash. So my understanding is that there is a static threshold for the complexity of an expression that the compiler will not go beyond.
My understanding is that the Swift team is working on compiler optimizations that will make these errors less common. You can learn a little bit about it on the Apple Developer forums by clicking on this link.
On the Dev forums, Chris Lattner has asked people to file these errors as radar reports, because they are actively working on fixing them.
That is how I understand it after reading a number of posts here and on the Dev forum about it, but my understanding of compilers is naive, and I am hoping that someone with a deeper knowledge of how they handle these tasks will expand on what I have written here.
This is almost same as the accepted answer but with some added dialogue (I had with Rob Napier and another friend from a Cocoahead meetup) and links.
See the comments in this discussion. The gist of it is:
The +
operator is heavily overloaded, as of now it has 27 different functions so if you are concatenating 4 strings ie you have 3 +
operators the compiler has to check between 27 operators each time, so that\'s 27^3 times. But that\'s not it.
There is also a check to see if the lhs
and rhs
of the +
functions are both valid if they are it calls through to core the append
called. There you can see there are a number of somewhat intensive checks that can occur. If the string is stored non-contiguously, which appears to be the case if the string you’re dealing with is actually bridged to NSString. Swift then has to re-assemble all the byte array buffers into a single contiguous buffer and which requires creating new buffers along the way. and then you eventually get one buffer that contains the string you’re attempting to concatenate together.
In a nutshell there is 3 clusters of compiler checks that will slow you down and therefore concatenating strings with interpolation ie using \" My fullName is \\(firstName) \\(LastName)\"
is much better than \"My firstName is\" + firstName + LastName
since interpolation doesn\'t have any overloading
Swift 3 has made some improvements. For more information read How to merge multiple Arrays without slowing the compiler down?
This is quite ridiculous no matter what you say! :)
But this gets passed easily
return \"\\(year) \\(month) \\(dayString) \\(hour) \\(min) \\(weekDay)\"
I had similar issue:
expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
In Xcode 9.3 line goes like this:
let media = entities.filter { (entity) -> Bool in
After changing it into something like this:
let media = entities.filter { (entity: Entity) -> Bool in
everything worked out.
Probably it has something to do with Swift compiler trying to infer data type from code around.