MathGroup Archive 2003

[Date Index] [Thread Index] [Author Index]

Search the Archive

RE: Re: Part assignment

  • To: mathgroup at smc.vnet.net
  • Subject: [mg45080] RE: [mg45051] Re: Part assignment
  • From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>
  • Date: Tue, 16 Dec 2003 06:21:06 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

>-----Original Message-----
>From: Maxim [mailto:dontsendhere@.]
To: mathgroup at smc.vnet.net
>Sent: Sunday, December 14, 2003 12:23 PM
>To: mathgroup at smc.vnet.net
>Subject: [mg45080] [mg45051] Re: Part assignment
>
>
>
>
>"Wolf, Hartmut" wrote:
>
>> >-----Original Message-----
>> >From: Maxim [mailto:dontsendhere@.]
To: mathgroup at smc.vnet.net
>To: mathgroup at smc.vnet.net
>> >Sent: Thursday, December 11, 2003 11:28 AM
>> >To: mathgroup at smc.vnet.net
>> >Subject: [mg45080] [mg45051]  Part assignment
>> >
>> >
>> >Consider
>> >
>> >In[1]:=
>> >Module[
>> >  {L={0,0}},
>> >  L[[1]]=Sequence[1,1];
>> >  L[[2]]=2;
>> >  L[[2]]
>> >]
>> >
>> >Out[1]=
>> >1
>> >
>> >The first part assignment constructs a list 
>{Sequence[1,1],0}. Then an
>> >interesting thing happens: part extraction functions (Part 
>and others)
>> >think that the second element of this list is 1, while part 
>assignment
>> >(Set) decides that the second element is 0.
>> >
>> >Maxim Rytin
>> >m.r at prontomail.com
>> >
>> >
>>
>> Maxim,
>>
>> obviously you like to live on the edge. Unless you complain, 
>this is a bold
>> way to learn. Observe:
>>
>> In[32]:= L = {0, 0};
>>          L[[1]] = Sequence[1, 1];
>>          L[[2]] = 2;
>>          L[[2]]
>> Out[35]= 1
>>
>> In[36]:= ?L
>>
>>          Global`L
>>
>>          L = {Sequence[1, 1], 2}
>>
>> In[48]:= Attributes[Set]
>> Out[48]= {HoldFirst, Protected, SequenceHold}
>>
>> (Look up what SequenceHold means!)
>>
>> As mostly, you do have alternatives:
>>
>> In[38]:= L = {0, 0};
>>          L = ReplacePart[L, Unevaluated[Sequence[1, 1]], 1];
>>          L[[2]] = 2;
>>          L[[2]]
>>
>> Out[41]= 2
>>
>> In[42]:= ?L
>>
>>          Global`L
>>
>>          L = {1, 2, 0}
>>
>> --
>> Hartmut Wolf
>
>So you think SequenceHold is the explanation? Let's see if it 
>has any relation
>to my example.
>

Well, yes, I thought so, and still do.  Proceeding analytically, let's just
make a more simple example, a model, which has less complications than the
operational semantics of Set.

For that I define some "pseudoSet" with an operator that is free for user
definition, but has the same grouping properties as Set, I take RightTee:

 
In[16]:= Clear[a, b, c]
In[17]:=
Attributes[RightTee] = {HoldFirst, SequenceHold};

In[18]:= RightTee[a_, b_, c___] := 
      Print["lhs: ", HoldComplete[a], " \[RightTee] rhs: ", 
      HoldComplete[b], ", " HoldComplete[c]]


In[19]:= a \[RightTee] Sequence[b, c]
>From In[19]:=
  lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[Sequence[b, c]],
HoldComplete[]


In[20]:= a \[RightTee] b \[RightTee] c
>From In[20]:=
  lhs: HoldComplete[b] \[RightTee] rhs: HoldComplete[c], HoldComplete[]
>From In[20]:=
  lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[Null], HoldComplete[]

This is a consequence of the grouping properties (right associative) the
result of the rightmost "assignment" ("value of b" Null) is "assigned to" a

In[21]:= Sequence[a, b] \[RightTee] c
>From In[21]:=
  lhs: HoldComplete[Sequence[a, b]] \[RightTee] rhs: HoldComplete[c],
HoldComplete[]

In[55]:= RightTee[a, b, c]
>From In[55]:=
  lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[b], HoldComplete[c]

Here you see clearly see how slots are filled and SequenceHold is in fact
responsible (for the "pseudoassigment" of Sequence[b, c] in FromIn[19]).



Now we clear the SequenceHold attribute:

In[22]:= ClearAttributes[RightTee, SequenceHold]

In[23]:=  a \[RightTee] Sequence[b, c]
>From In[23]:=
  lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[b], HoldComplete[c]

In[24]:= Sequence[a, b] \[RightTee] c
>From In[24]:=
  lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[b], HoldComplete[c]

This is the same as the previous result, such also quite different from the
corresponding expression with the SequenceHold attribute.

(I continue below)



>First assignment: L[[1]]=Sequence[1,1], or 
>Set[Part[L,1],Sequence[1,1]].
>SequenceHold simply determines that it is not converted to 
>Set[Part[L,1],1,1].
>Curiously enough, in this case it doesn't make any difference, 
>since the latter
>evaluates exactly the same way.
>
>Second assignment: L[[2]]=2, or Set[Part[L,2],2]. Here L is 
>not evaluated
>(because assigment treats Part in a special way -- if there 
>were another
>non-holding function instead of Part, L would be evaluated), 
>so there's simply
>no Sequence objects here and SequenceHold can't have any effect.
>
>So references to SequenceHold here are just fancy words -- remove the
>SequenceHold attribute of Set and verify that the result will 
>be exactly the
>same.
>
>The evaluation rules just don't say anything explicitly about 
>how assignments
>should be performed for parts of lists like {Sequence[1,1],0} 
>(that is, after I
>assign a Sequence object to one of the list elements). The 
>current approach has
>its logic too, but it can be misleading, for example, 
>L[[Length@L]]=elem may
>result in an error.
>
>Maxim Rytin
>m.r at prontomail.com
>
>

This of course is not all of Set. Just repeated:

In[37]:= Clear[a, b, c]
In[38]:= a = Sequence[b, c]
Out[38]= Sequence[b, c]


In[39]:= ?a
  Global`a
  a = Sequence[b, c]

In[40]:= ?b
  Global`b


In[41]:= Clear[a, b, c]
In[42]:= a = b = c
Out[42]= c

In[43]:= ?a
  Global`a
  a = c

In[44]:= ?b
  Global`b
  b = c

In[45]:= Clear[a, b, c]

In[46]:= Sequence[a, b] = c
>From In[46]:=
Set::write: Tag Sequence in HoldForm[a, b] is Protected.
Out[46]= c

In[47]:= ?a
  Global`a


Now

In[49]:= Clear[a, b, c]

In[50]:= Set[a, b, c]
Out[50]= Sequence[b, c]

This result clearly has nothing to do with SequenceHold, and (as you might
see from the "pseudoassignment" this is *not* reached as intermediary from
In[38], it just happens to give the same result).

Now, anyways, Set is "a proper form" of the language, and certainly lies at
the heart of the implementation, and certainly it must be performance
optimized. From a programming language perspective, In[50], as contrary to
In[38] and In[42], has no semantics. Instead of an error, it shows this
behaviour, "is tolerant", but you have to ask the implementor (God himself),
why this is so. (My guess is: just to bypass parts from the evaluation loop
for Set, hence in reality the were no attributes for Set, as there are no
(explicit) UpValues for Part, all this presumably would be "hardwired" at a
low level. Perhaps)

In[51]:= ?a
  Global`a
  a = Sequence[b, c]

In[52]:= ?b
  Global`b


Let's look again at your first question:

>> In[32]:= L = {0, 0};
>>          L[[1]] = Sequence[1, 1];
>>          L[[2]] = 2;
>>          L[[2]]
>> Out[35]= 1
>>
>> In[36]:= ?L
>>
>>          Global`L
>>
>>          L = {Sequence[1, 1], 2}


We certainly agree that after the second assignment L[[1]]= Sequence[1,1]
has the value {Sequence[1,1], 0}, (it would have the same value after the
assignment Set[L[[1]],1,1], but that is, as shown, a different story). Now
why does L[[2]] = 2, overwrite that 0, and not the second 1 from
Sequence[1,1]?  This simply is because of the HoldFirst property of Set
(such L ist *not* evaluated, does *not* result to {1, 1, 0}[[2]] at lhs, and
as a special form behaves "like an Upvalue for Part" just redefining the
second slot, and leaving everthing else untouched (of course, we might say),
hence the result.

Contrary to that, L = L evaluates L at rhs to {1, 1, 0}, this then is
assigned to the symbol L completely overwriting its previous value.
Thereafter L[[2]]=2 of course results in {1, 2, 0}

Whereas in L[[2]], when evaluated, L first results in {1,1,2}, and
{1,1,2}[[2]] then in turn gives 1 (and not 2).


You may detect more (seemingly) strange behaviour for Set, as (if e.g.
matrix A is properly set up)

  A[[1, 1]] = something 

gives a correct assignment, whereas 

  A[[1]][[1]] = something

doesn't. This also is due to HoldFirst and the "UpValue" behaviour for Part.


All this, after you respect the Attributes (you always have to), and
consider the needs for an efficient implementation, is not very surprising.
Perhaps we may regret that WRI is a bit reserved on these and similar
questions, but this should not become a problem of usage. My advice was, and
is: avoid that! (because, as said, it's outside of the programming language
specification and semantics).

--
Hartmut Wolf



  • Prev by Date: Re: Compile
  • Next by Date: Re: Date and Time - Functions-Bug!?
  • Previous by thread: Re: Part assignment
  • Next by thread: Re: Part assignment