Especificidades de uso e trabalho interno de * Definir * funções

Acabei de notar um recurso não documentado do trabalho interno de*Set* funções em Mathematica.

Considerar

In[1]:= a := (Print["!"]; a =.; 5);
a[b] = 2;
DownValues[a]

During evaluation of In[1]:= !

Out[3]= {HoldPattern[a[b]] :> 2}

ma

In[4]:= a := (Print["!"]; a =.; 5);
a[1] = 2;
DownValues[a]

During evaluation of In[4]:= !

During evaluation of In[4]:= Set::write: Tag Integer in 5[1] is Protected. >>

Out[6]= {HoldPattern[a[b]] :> 2}

Qual é o motivo dessa diferença? Por quêa é avaliado emboraSet tem atributoHoldFirst? Para que fins esse comportamento é útil?

E observe também este caso:

In[7]:= a := (Print["!"]; a =.; 5)
a[b] ^= 2
UpValues[b]
a[b]

During evaluation of In[7]:= !

Out[8]= 2

Out[9]= {HoldPattern[5[b]] :> 2}

Out[10]= 2

Como você vê, obtemos a definição de trabalho para5[b] evitandoProtected atributo da tagInteger que causa erro em casos habituais:

In[13]:= 5[b] = 1

During evaluation of In[13]:= Set::write: Tag Integer in 5[b] is Protected. >>

Out[13]= 1

A outra maneira de evitar esse erro é usarTagSet*:

In[15]:= b /: 5[b] = 1
UpValues[b]

Out[15]= 1

Out[16]= {HoldPattern[5[b]] :> 1}

Por que esses recursos?

Quanto à minha pergunta por que podemos escrevera := (a =.; 5); a[b] = 2 enquanto não pudera := (a =.; 5); a[1] = 2. Em realmente em Mathematica 5 não podemos escrevera := (a =.; 5); a[b] = 2 também

In[1]:=
a:=(a=.;5);a[b]=2
From In[1]:= Set::write: Tag Integer in 5[b] is Protected. More...
Out[1]=
2

(O acima foi copiado de Mathematica 5.2)

Podemos ver o que acontece internamente em novas versões do Mathematica quando avaliamosa := (a =.; 5); a[b] = 2:

In[1]:= a:=(a=.;5);
Trace[a[b]=2,TraceOriginal->True]
Out[2]= {a[b]=2,{Set},{2},a[b]=2,{With[{JLink`Private`obj$=a},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[JLink`Private`obj$[b],2]]],Head[JLink`Private`obj$]===Symbol&&StringMatchQ[Context[JLink`Private`obj$],JLink`Objects`*]]],{With},With[{JLink`Private`obj$=a},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[JLink`Private`obj$[b],2]]],Head[JLink`Private`obj$]===Symbol&&StringMatchQ[Context[JLink`Private`obj$],JLink`Objects`*]]],{a,a=.;5,{CompoundExpression},a=.;5,{a=.,{Unset},a=.,Null},{5},5},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[5[b],2]]],Head[5]===Symbol&&StringMatchQ[Context[5],JLink`Objects`*]],{RuleCondition},{Head[5]===Symbol&&StringMatchQ[Context[5],JLink`Objects`*],{And},Head[5]===Symbol&&a,mp;StringMatchQ[Context[5],JLink`Objects`*],{Head[5]===Symbol,{SameQ},{Head[5],{Head},{5},Head[5],Integer},{Symbol},Integer===Symbol,False},False},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[5[b],2]]],False],Fail},a[b]=2,{a[b],{a},{b},a[b]},2}

Fiquei muito surpreso ao ver chamadas para Java em uma operação tão pura relacionada à linguagem como atribuir um valor a uma variável. É razoável usar Java para essas operaçõe

Todd Gayley (Pesquisa Wolfram)tem explicado esse comportamento

No início, deixe-me salientar que no Mathematica 8, o J / Link não sobrecarrega mais o Set. Foi criado um mecanismo interno do kernel que, entre outras coisas, permite ao J / Link evitar a necessidade de "truques" especiais com o Set.

@ J / Link sobrecarregou o Set desde o início, quase doze anos atrás. Isso permite suportar esta sintaxe para atribuir um valor a um campo Java:

 javaObject@field = value

A definição sobrecarregada de Set causa uma desaceleração nas atribuições do formulário

 _Symbol[_Symbol] = value

Certamente, a atribuição é uma operação rápida, portanto a desaceleração é pequena em termos reais. Somente tipos de programas altamente especializados provavelmente serão significativamente afetado

A sobrecarga do conjunto nnã causar uma chamada para Java em atribuições que não envolvem objetos Java (isso seria muito caro). Isso pode ser verificado com um simples uso do TracePrint no seu a [b] = c.

Faz, como você observa, fazer uma ligeira alteração no comportamento das atribuições que correspondem a _Symbol [_Symbol] = value. Especificamente, em f [_Symbol] = value, f é avaliado duas vezes. Isso pode causar problemas no código com o seguinte formato (altamente incomum):

 f := SomeProgramWithSideEffects[]
 f[x] = 42

Não me lembro de ter visto um código "real" como esse ou de um problema relatado por um usuári

gora está tudo discutido no 8.

questionAnswers(2)

yourAnswerToTheQuestion