viernes, 28 de diciembre de 2018
Desde que apareció Roslyn, C# ha ido evolucionando a pasos agigantados. Tanto es así que es frecuente encontrar desarrolladores que, aunque lo usan a diario, desconocen todo su potencial porque la velocidad de introducción de cambios en el lenguaje es mayor que la de asimilación de novedades por parte de los profesionales que nos dedicamos a esto.
Por ejemplo, en las consultorías técnicas que realizo en empresas es frecuente encontrar equipos de trabajo en los que aún no está generalizado el uso de construcciones tan útiles como el null coalescing operator (
Sin embargo, creo que el rey de los desconocidos es el operador virgulilla "~" de C#. Introducido con C#7 es probablemente uno de los operadores menos utilizados y, sin embargo, de los más potentes ofrecidos por el lenguaje.
Básicamente, el operador virgulilla retorna un valor booleano resultado de evaluar una comparación entre dos objetos o valores, pero, a diferencia de las comparaciones "tradicionales", utilizando criterios basados en lógica borrosa y aprendizaje automático o machine learning.
Creo que la mejor forma de entender rápidamente en qué consiste es viendo código, así que vamos con el primer ejemplo:
Para ajustar en cada escenario el nivel de precisión que deseamos aplicar a las operaciones de comparación, C# permite encadenar hasta tres virgulillas para indicar que queremos aplicar un grado mayor de precisión en la evaluación de similitud:
Pues subamos la apuesta ;) La comparación de similitud ofrecida por el operador también está integrada con los sistemas NLP (procesamiento de lenguaje natural) incluidos en el compilador. Observad en el siguiente ejemplo, donde evaluamos la similitud de cadenas de caracteres y enteros utilizando comparación semántica:
Para conseguirlo en Visual Studio 2017, basta con acudir a las propiedades del proyecto, pestaña "Build", clicar el botón "Avanzado" y asegurarse de que está marcado Enable similarity operator, como se muestra en la siguiente captura de pantalla:
Si no utilizamos Visual Studio, también podemos acudir al archivo .csproj del proyecto e insertar manualmente las siguientes líneas (es posible que requiera reiniciar VS tras hacerlo):
Pero en cualquier caso, sin duda, el operador virgulilla es una de las incorporaciones al lenguaje C# más interesantes de los últimos años, pues nos abre la puerta a la construcción de sistemas más fiables, inteligentes y flexibles.
El operador virgulilla es a la inteligencia artificial lo que LINQ fue en su momento a las bases de datos: una integración dentro del lenguaje de funcionalidades que tradicionalmente pertenecían a un mundo aparte. De ahí que podamos considerarlo como una herramienta totalmente disruptiva para los desarrolladores.
Publicado en ~Varible not fund.
Por ejemplo, en las consultorías técnicas que realizo en empresas es frecuente encontrar equipos de trabajo en los que aún no está generalizado el uso de construcciones tan útiles como el null coalescing operator (
fullName ?? "Anonymous"
), safe navigation operator (person?.Address?.Street
), el at object operator (Address@person
), o características tan potentes como las funciones locales, interpolación de cadenas, tuplas o muchas otras.Sin embargo, creo que el rey de los desconocidos es el operador virgulilla "~" de C#. Introducido con C#7 es probablemente uno de los operadores menos utilizados y, sin embargo, de los más potentes ofrecidos por el lenguaje.
Nota de traducción: el nombre original del operador es "tilde operator", y como he encontrado poca literatura al respecto en nuestro idioma, me he tomado la libertad de traducirlo como operador virgulilla (¡sí, esa palabra existe!). También, en entornos más informales lo encontraréis con el nombre "wormy operator" (operador gusanillo) o como "soft similarity operator" (que podríamos traducir como operador de similitud relajada).
El operador virgulilla
Originalmente el carácter "~" ya era utilizado desde los comienzos de C# para realizar la operación de complemento bit a bit, pero, dado su poco uso, en C#7 reescribieron el operador para alinear el lenguaje con las nuevas corrientes de popularización de los sistemas basados en inteligencia artificial.Básicamente, el operador virgulilla retorna un valor booleano resultado de evaluar una comparación entre dos objetos o valores, pero, a diferencia de las comparaciones "tradicionales", utilizando criterios basados en lógica borrosa y aprendizaje automático o machine learning.
Creo que la mejor forma de entender rápidamente en qué consiste es viendo código, así que vamos con el primer ejemplo:
var n1 = 987654320;
var n2 = 987654321;
Console.WriteLine(n1 == n2); // n1 equals n2? --> false
Console.WriteLine(n1 ~ n2); // n1 is similar to n2? --> true!
Efectivamente, como podéis suponer, el operador ~
comprueba si los dos operandos son similares, retornando true
en caso afirmativo.Para ajustar en cada escenario el nivel de precisión que deseamos aplicar a las operaciones de comparación, C# permite encadenar hasta tres virgulillas para indicar que queremos aplicar un grado mayor de precisión en la evaluación de similitud:
var n1 = 987654320;
var n2 = 987654321;
Console.WriteLine(n1 == n2); // n1 is equals to n2? --> false
Console.WriteLine(n1 ~ n2); // n1 is similar to n2? --> true
Console.WriteLine(n1 ~~ n2); // n1 is very similar to n2? --> true
Console.WriteLine(n1 ~~~ n2); // n1 is very very similar to n2? --> false!
Observad que en muchos escenarios puede librarnos del típico off by one, uno de los errores más habituales en el mundo de la programación.Los ejemplos anteriores pueden verse más o menos claros porque estamos comparando números. Pero la cosa va más allá; veamos otro ejemplo, usando la sobrecarga del operador para tipos
string
:string s1 = "Hello, what is your name?";
string s2 = "Hello, wat is your name?";
Console.WriteLine(s1 == s2); // s1 equals s2? --> false
Console.WriteLine(s1 ~ s2); // s1 is similar to s2? --> true
Empleando bien esta característica podemos simplificar bastante las comparaciones de cadenas y, sobre todo, el tratamiento de valores nulos, vacíos o blancos, como en el siguiente ejemplo:string strNull = null;
string strEmpty = "";
string strSpaces = " ";
Console.WriteLine(strNull == strEmpty); // false
Console.WriteLine(strNull ~ strEmpty); // true
Console.WriteLine(strNull ~ strSpaces); // true
Console.WriteLine(strSpaces ~ null); // true: Bye bye, string.IsNullOrEmpty()!
Y como operador completo que es, también podemos utilizar composición de gusanillos para expresar comprobaciones complejas de forma más concisa:Console.WriteLine(strNull ~ strEmpty ~ strSpaces); // true
Comparaciones AI-Based
Este operador también tiene la capacidad de comparar valores de distinto tipo, y es donde encontramos probablemente su utilidad más espectacular porque con ello se ponen en marcha los mecanismos de inteligencia artificial integrados en el compilador. Fijaos en esto:string strRed = "red";
string strRgbRed = "ff0000";
Color colorRed = Color.Red;
int intRgbRed = 0xff0000;
Console.WriteLine(strRed ~ strRgbRed ~ colorRed ~ intRgbRed); // true!!
Internamente, el sistema es capaz de detectar la similitud gracias a la siguiente cadena de decisiones:- Sabe que
Color.Red
es un miembro de un enum con un valor entero equivalente a0xff0000
. - Por esta razón, sabe que
colorRed ~ intRgbRed
. - También sabe que "ff0000" es la representación textual de
0xff0000
, y teniendo en cuenta los pasos anteriores, deduce questrRgbRed ~ colorRed ~ intRgbRed
. - El texto "red" se encuentra en el nombre de la constante
Color.Red
, por lo que ya puede concluir questrRed ~ strRgbRed ~ colorRed ~ intRgbRed
.
Pues subamos la apuesta ;) La comparación de similitud ofrecida por el operador también está integrada con los sistemas NLP (procesamiento de lenguaje natural) incluidos en el compilador. Observad en el siguiente ejemplo, donde evaluamos la similitud de cadenas de caracteres y enteros utilizando comparación semántica:
using Microsoft.Extensions.Operators.Tilde.Nlp;
...
int numberTen = 10;
string strDiez = "diez";
string strDecena = "una decena";
string strDecimoDeCien = "la décima parte de cien";
Console.WriteLine(strDiez ~ numberTen ~ strDecena ~ strDecimoDeCien); // true!
Nota: para que esto funcione correctamente es necesario incluir el espacio de nombres Microsoft.Extensions.Operators.Tilde.Nlp
.
Incluso podemos sacar partido fácilmente a la traducción en tiempo de compilación a distintos locales. Fijaos que en este caso son dos los namespaces los que debemos utilizar:using Microsoft.Extensions.Operators.Tilde.Nlp;
using Microsoft.Extensions.Operators.Tilde.Nlp.I18N;
...
string strTen = "ten";
string strDiez = "diez";
Console.WriteLine(strTen ~ strDiez); // true; usando auto-locale
Console.WriteLine(strDiez ~en-us~ strTen); // true; forzando el locale en-us
Console.WriteLine(strDiez ~fr-fr~ strTen); // false (el locale forzado es incorrecto)
Activación en Visual Studio 2017 u otros IDE
Sin duda, este operador es uno de los grandes desconocidos por la controvertida decisión de Microsoft de hacer que éste sólo esté disponible cuando es habilitado explícitamente en el entorno de desarrollo. Es decir, no podemos utilizarlo en nuestro código hasta que lo activemos expresamente en el proyecto.Para conseguirlo en Visual Studio 2017, basta con acudir a las propiedades del proyecto, pestaña "Build", clicar el botón "Avanzado" y asegurarse de que está marcado Enable similarity operator, como se muestra en la siguiente captura de pantalla:
Si no utilizamos Visual Studio, también podemos acudir al archivo .csproj del proyecto e insertar manualmente las siguientes líneas (es posible que requiera reiniciar VS tras hacerlo):
<PropertyGroup>
<LanguageVersion>Latest</AssemblyName>
<EnableSimilarityOperator>true</EnableSimilarityOperator>
</PropertyGroup>
¿Y está disponible este operador en Visual Basic .NET?
Nota: Este punto no estaba inicialmente en el post, pero lo he actualizado para responder a la pregunta que me hacía @visualbutnotbasic vía Twitter nada más publicarlo.Pues aún no, pero lo estará pronto. Según Victor Bellino, principal program manager en Redmond, se está trabajando duro para llevar este operador a Visual Basic, aunque probablemente bajo otra denominación para alinearlo sintácticamente con las construcciones habituales de este lenguaje:
If x Is Similar To y And Similar To z Then
...
End If
En conclusión
Desconozco las razones que han llevado a Microsoft a mantener el operador virgulilla semioculto tras opciones de compilación, y a no haberlo publicitado más. Probablemente existan reticencias por que, como todo gran poder, su uso exige una gran responsabilidad y es posible que piensen que los desarrolladores no estamos aún preparados para asumirla.Pero en cualquier caso, sin duda, el operador virgulilla es una de las incorporaciones al lenguaje C# más interesantes de los últimos años, pues nos abre la puerta a la construcción de sistemas más fiables, inteligentes y flexibles.
El operador virgulilla es a la inteligencia artificial lo que LINQ fue en su momento a las bases de datos: una integración dentro del lenguaje de funcionalidades que tradicionalmente pertenecían a un mundo aparte. De ahí que podamos considerarlo como una herramienta totalmente disruptiva para los desarrolladores.
Nota para despistados: lamentablemente (o afortunadamente, no estoy seguro), el operador virgulilla no es real, se trata sólo de una broma del Día de los Inocentes (28-dic). Pero si os gusta la idea y pensáis que podría ser una aportación interesante a C#, siempre podéis proponerlo en el repositorio oficial del lenguaje y quién sabe, quizás algún día podamos disfrutarlo ;)
Publicado en ~Varible not fund.
13 Comentarios:
Me parece genial 😃 ¿Sabes si tambien estara disponible en F#?
Buenísimo artículo
Muy bueno, es probable que lo utilice en mi proyecto para la comparación de matrículas, ya que las lecturas de los LPR aveces no son exactas.
Great!
Yo también pienso usarlo en mi aplicación bancaria porque muchas veces la gente se equivoca al introducir mal los números de cuenta cuando hacen transferencias. Con este operador podré lanzar las transferencias aunque el número no sea del todo correcto.
¡Felices fiestas!
Peter
He probado con varios proyectos en Visual Studio 2017 Enterprise y no encuentro dicha habilitación.
He probado también agregarlo al .csproj y tampoco me lo reconoce.
Funciona con algún tipo de proyecto en particular?
Desde ya, muchas gracias y felices fiestas.
Saludos,
Estuvo muy bueno, Feliz día de los inocentes.
Hola, a mi me pasó lo mismo. Para que aparezca en mi Visual Studio he tenido que usar un combo con la siguiente combinación de teclas:
Izquierda-Abajo-Derecha-Derecha-(mientras pulso el botón izquierdo y derecho del ratón)
Hay que hacerlo cuatro veces.
Feliz día ;D
Ya esperaba tu post de los inocentes, imaginativo el nombre del operador jajaja
Siento desilusionaros pero sí que existe el operador virgulilla:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-complement-operator
Hola!
Sí, se comenta en el post. Lo sorprendente que contábamos aquí es es que había sido reescrito para darle otra utilidad más inteligente ;D
Saludos!
Cordial saludo
Que significa este operador en la siguiente expresión?
var path = Server.MapPath("~/App_Data");
Hola,
Server.MapPath("~/App_Data") retornará la ruta física de la carpeta "/App_Data" situada en la raíz del sitio web.
Pero ojo, esto no es gracias al operador virgulilla de C# y sus mecanismos de inteligencia artificial ;) Es simplemente que ese carácter, situado al comienzo de una ruta lógica, se traduce como la raíz del sitio.
Saludos!
gracias
Enviar un nuevo comentario