La razón de lo que se observa es que la declaración Off[t::shdw]
desactiva un mensaje de duplicación para el símbolo t
que se encuentra actualmente en el $ContextPath
, pero no para otro t
, creado durante la carga de otro paquete. Debe desactivar el mensaje de sombreado para ese segundo t
, si no desea verlo. Aquí hay un ejemplo:
In[1]:= Off[Test1`a::shdw]
In[2]:=
BeginPackage["Test`"]
a
EndPackage[]
Out[2]= Test`
Out[3]= a
In[5]:= BeginPackage["Test1`"]
a
EndPackage[]
Out[5]= Test1`
Out[6]= a
Aquí, no se ha generado ningún mensaje.
En general, sin embargo, no me gustaría desactivar los mensajes ocultos, ya que el sombreado es un problema grave. Sombrear simplemente significa que actualmente hay más de un contexto en la ruta de búsqueda de símbolos ($ContextPath
), que contiene símbolos con el mismo nombre (corto). Básicamente, si el símbolo está sombreado, y se refiere a él por su nombre corto (es decir, símbolo sin su paquete contenedor), no tiene garantía de cuál de los varios símbolos con el mismo nombre corto realmente se utilizará. Entonces, la forma correcta de lidiar con esto es evitar el sombreado por completo, lo que siempre es posible, si no siempre conveniente.
La forma más sencilla de evitar el sombreado es cargar el paquete que necesita en la sección privada de su paquete, que comienza después de la línea Begin["`Private`"]
. Lo haces llamando al Needs[your-package]
, como siempre. De esta forma, el contexto del paquete cargado no permanece en el $ContextPath
junto con el contexto de su paquete. El peor caso es cuando necesita cargar dos paquetes con símbolos en conflicto. Una forma de salir es construir un paquete contenedor para uno de ellos, que cargaría ese en privado y cambiaría el nombre de los símbolos en conflicto. Sin embargo, esto puede ser un inconveniente, ya que tendría que cambiar el nombre de todas las funciones en un paquete, incluso aquellas que no entran en conflicto. Este es un ejemplo de una variante más flexible:
primer paquete:
BeginPackage["Test`"];
g[x_?NumericQ] := x^2;
EndPackage[];
segundo paquete:
BeginPackage["Test1`"];
g[x_?NumericQ] := x^3;
EndPackage[]
paquete principal:
BeginPackage["Main`"];
f::usage = "A test function of a single argument";
Begin["`Private`"];
Block[{$ContextPath = $ContextPath},
Needs["Test`"];
(* Define first delegate private function *)
g1 = Symbol["g"]];
Block[{$ContextPath = $ContextPath},
Needs["Test1`"];
(* Define second delegate private function *)
g2 = Symbol["g"];
];
f[x_] := g1[x]*g2[x]
End[]
EndPackage[]
Ahora, con la condición de que el sistema de sabe dónde encontrar sus paquetes:
In[2]:= Needs["Main`"]
In[3]:= f[x]
Out[3]= Test`g[x] Test1`g[x]
In[4]:= f[2]
Out[4]= 32
Y usamos dos símbolos en conflicto para la misma función pública. El uso de Block
anterior sirvió para localizar el código donde se usa la primera o segunda definición de g
. Tenga en cuenta que hay algunos inconvenientes con este método en el sentido de que necesitamos usar Symbol["your-symbol-name"]
, para retrasar el análisis hasta el tiempo de ejecución.
Un método mucho más simple es simplemente referirse a los símbolos por sus largos nombres. En lo anterior, podríamos simplemente usar Test`g
y Test1`g
y luego no hay necesidad de maquinaria pesada.Sin embargo, esto es algo menos flexible, ya que tiene que "codificar" el contexto del símbolo en el código.
+1 Estaba escribiendo (casi) exactamente la misma respuesta ... Un comentario: si phantomas realmente quiere apagar todos los mensajes de sombreado, debería usar 'Off [General :: shdw]' – Simon
@Leonid, Escapé de la tumba (') marcas. – rcollyer
@rcollyer ¡Gracias! ¡Finalmente debería aprender a hacerlo! :) –