Error del comstackdor Swift: “Expresión demasiado compleja” en una cadena de concatenación

Esto me parece divertido más que nada. Lo arreglé, pero me pregunto por la causa. Aquí está el error: DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions . ¿Por qué se queja? Parece una de las expresiones más simples posibles.

El comstackdor apunta a las columns + ");"; sección

 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); } 

la solución es:

 var statement = "create table if not exists " + self.tableName(); statement += "(" + columns + ");"; 

esto también funciona (a través de @efischency) pero no me gusta tanto porque creo que ( perderse:

var statement = "create table if not exists \(self.tableName()) (\(columns))"

No soy un experto en comstackdores: no sé si esta respuesta “cambiará tu forma de pensar de una manera significativa”, pero mi comprensión del problema es la siguiente:

Tiene que ver con la inferencia de tipo. Cada vez que utiliza el operador + , Swift tiene que buscar entre todas las posibles sobrecargas para + e inferir qué versión de + está usando. Conté un poco menos de 30 sobrecargas para el operador + . Esas son muchas posibilidades, y cuando encadenas 4 o 5 + operaciones juntas y le pides al comstackdor que infiera todos los argumentos, estás pidiendo mucho más de lo que podría parecer a primera vista.

Esa inferencia puede ser complicada, por ejemplo, si agrega un UInt8 y un Int usando + , la salida será un Int , pero hay un trabajo que se dedica a evaluar las reglas para los tipos de mezcla con los operadores.

Y cuando usa literales, como los literales String en su ejemplo, el comstackdor realiza el trabajo de convertir el String literal en String y luego realiza el trabajo de inferir el argumento y los tipos de retorno para el operador + , etc.

Si una expresión es suficientemente compleja, es decir, requiere que el comstackdor haga demasiadas inferencias sobre los argumentos y los operadores, se cierra y le dice que la abandone.

Hacer que el comstackdor abandone una vez que una expresión alcanza un cierto nivel de complejidad es intencional. La alternativa es dejar que el comstackdor intente y lo haga, y ver si puede, pero eso es arriesgado: el comstackdor podría seguir intentándolo para siempre, atascarse o simplemente bloquearse. Entonces, entiendo que existe un umbral estático para la complejidad de una expresión que el comstackdor no irá más allá.

Según tengo entendido, el equipo de Swift está trabajando en optimizaciones de comstackdores que harán que estos errores sean menos comunes. Puede aprender un poco al respecto en los foros de desarrolladores de Apple haciendo clic en este enlace .

En los foros de Dev, Chris Lattner ha pedido a las personas que presenten estos errores como informes de radar, porque están trabajando activamente para solucionarlos.

Así es como lo entiendo después de leer una serie de publicaciones aquí y en el foro de Dev al respecto, pero mi comprensión de los comstackdores es ingenua, y espero que alguien con un conocimiento más profundo de cómo manejan estas tareas se expanda en lo que he escrito aquí.

Esto es casi lo mismo que la respuesta aceptada, pero con algunos diálogos añadidos (tuve con Rob Napier y otro amigo de una reunión de Cocoahead) y enlaces.

Ver los comentarios en esta discusión. La esencia de esto es:

El operador + está muy sobrecargado, a partir de ahora tiene 27 funciones diferentes, por lo que si está concatenando 4 cadenas, es decir, tiene 3 operadores + , el comstackdor tiene que verificar entre 27 operadores cada vez, entonces eso es 27 ^ 3 veces. Pero eso no es todo.

También hay una comprobación para ver si las funciones lhs y rhs de + son ambas válidas si son llamadas a través de core the append called. Allí se puede ver que hay una serie de controles algo intensivos que pueden ocurrir. Si la cadena se almacena de forma no contigua, lo que parece ser el caso si la cadena con la que está tratando está realmente enlazada a NSString. Swift luego tiene que volver a ensamblar todos los búferes de matriz de bytes en un único búfer contiguo y que requiere la creación de nuevos búferes en el camino. y luego finalmente obtienes un buffer que contiene la cadena que estás intentando concatenar juntos.

En pocas palabras, hay 3 grupos de comprobaciones del comstackdor que lo desacelerarán y, por lo tanto, concatenando cadenas con interpolación, es decir, utilizando " My fullName is \(firstName) \(LastName)" es mucho mejor que "My firstName is" + firstName + LastName desde la interpolación no tiene ninguna sobrecarga

Swift 3 ha realizado algunas mejoras. Para obtener más información, lea ¿Cómo combinar varias matrices sin ralentizar el comstackdor?

¡Esto es bastante ridículo sin importar lo que diga! 🙂

enter image description here

Pero esto se pasa fácilmente

 return "\(year) \(month) \(dayString) \(hour) \(min) \(weekDay)" 

Tuve un problema similar:

 expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions 

En Xcode 9.3 la línea es así:

 let media = entities.filter { (entity) -> Bool in 

Después de cambiarlo a algo como esto:

 let media = entities.filter { (entity: Entity) -> Bool in 

todo funcionó.

Probablemente tiene algo que ver con el comstackdor de Swift tratando de inferir el tipo de datos del código.