Estaba probando algunas cosas en el REPL de Julia (1.2) y me quedé pensando en algo que no entiendo sobre el envío.
Primero probé esto que funciona de la manera que esperaba:
f(a::T) where {T <: Int} = "Test"
Llamar a f (3) funciona desde
Int <: Int == true
Llamar a f ("Hola") produce un error "MethodError: no hay coincidencia de método" desde
String <: Int == false
Luego, probé este método, y no entiendo por qué llamarlo funciona en algunos casos:
f(a::T, b::U) where {T, U <: T} = "Another Test"
Llamar a f (3, 3) funciona (como esperaba)
PERO f (3, "Hola") también funciona y no arroja un "MethodError: ¿no coincide el método"?
¿Pensé que (ya que T se convierte en Int y U en String) String <: Int == false
???
Supongo que me estoy perdiendo algo bastante sencillo aquí, pero no puedo encontrarlo ... Así que esta es mi pregunta, ¿por qué funciona f (3, "Hola")?
Además, probé este fragmento de código (intenté recrear la segunda firma del método) y falla correctamente como esperaba:
Test = Tuple{T, U} where {T, U <: T}
Test{Int, String}
(esto falla como esperaba con "TypeError: in Type, en U, esperado U <: Int64, tengo Type {String}")
Int64,String,false
. Es posible que deba reiniciar Julia si agrega métodos a las funciones. Simplemente use un nuevo personaje, por ejemplo,h
para una nueva prueba. A su pregunta: Parece que el sistema intenta encontrar alguna solución a la restricción de tipo, yT=Any, U=Any where U:<T
es una. Si introduce un tipo concreto como en su tercer ejemplo, funciona como se esperaba. Las personas con un conocimiento más sólido del sistema tipo Julia pronto darán una respuesta adecuada a esto.Respuestas:
Lo que sucede aquí es que
T
puede ser un tipo de datos yU
puede ser cualquier supertipo de cadena. Esto se cumplen las condiciones. Lo que te estaba tropezando con una cadena que no es un subtipo de int es un arenque rojo, ya que ningún tipo concreto es el subtipo de ningún otro.fuente
Ok, gracias a laborg parece que ahora entiendo lo que estaba pasando. Si tomamos este método:
f(a::T, b::U) where {T, U <: T} = "Another Test"
'U' es el "UnionAll", también conocido como "Unión iterada" de todos los tipos posibles de 'b' que son subtipos de 'T'
Lo que estaba malentendiendo era el hecho de que si (ejemplo) a :: Int, entonces T puede tomar un tipo abstracto padre de typeof (a). Como Int <: Any, entonces T = Any es una solución válida para el envío.
Así que ahora tenemos U <: T que se resuelve en Any <: Any == true, ¡y se llama al método!
Espero haberlo entendido :)
fuente