Re: Assigning part of indexed object
- To: mathgroup at smc.vnet.net
- Subject: [mg119844] Re: Assigning part of indexed object
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Sat, 25 Jun 2011 05:28:10 -0400 (EDT)
- References: <itsjn7$8u7$1@smc.vnet.net>
Hi Fabrice, My guess is that the reasons are efficiency and immutability of expressions in Mtahematica. By restricting Set to variables or array elements, one can connect it directly to the internal memory layout for that element. Note that all proposed solutions are based on ReplacePart, which copies the entire list to modify a single element. OTOH, constructs like indexed variables are serviced by hash-tables internally. Even if the value stored in the hash table is a pointer to some array, that array will likely be immutable. Whether it would be a good idea to make it mutable I don't know, but the general ideology is that expressions are immutable in Mathematica. In other words, I don't think that the case of indexed variables was overlooked when designing Set - my guess is that the restriction to symbols is quite intentional. Regarding the "fix", I'd consider this not a fix but a recipe for disaster, because modifying Set in such a fashion is dangerous, not to mention that it will often be completely unacceptable performance-wise. Let us say you store a large array in a symbol and use a For loop with array indexing. Suddenly all your array element assignments become O(n) time, where n is the list size, or even worse for higher dimensional tensors, not to mention increased memory consumption. Here is an illustration: In[18]:= a = Range[10000]; In[19]:= Unprotect[Set]; Set[sym_[[part_]], val_] := sym = ReplacePart[sym, part -> val]; Protect[Set]; In[27]:= Do[a[[i]] = a[[i]]^2, {i, Length[a]}] // Timing Out[27]= {1.156, Null} In[28]:= Unprotect[Set]; Clear[Set]; Protect[Set]; In[31]:= Do[a[[i]] = a[[i]]^2, {i, Length[a]}] // Timing Out[31]= {0.047, Null} You may do this for yourself if you wish (although I'd avoid even that), but I'd strongly advise against such modifications in production code or any code someone else will be using. Set is one of the most fundamental operations, and its modifications may have very far- reaching and hard to predict consequences. It may, for example, corrupt the system in very subtle ways, which you may never be able to identify. Unfortunately, the standard mechanism of "soft" system symbols overloading via UpValues does not quite work with Set (or at least I don't know of a way to make it work) because Set holds its argument and UpValues can only be defined for tags not deeper than level 1 in an expression. In this post: http://stackoverflow.com/questions/5886066/overloading-seta-b-a-b/5886322#5886322 I demonstrated a method, which I also don't like, but which is at least safer because it tests for a specific data type. Generally, the still safer way is to create your own data type and introduce your own assignment operator(s) - in this way, you don't have to modify Set at all. Regards, Leonid On Fri, Jun 24, 2011 at 3:46 PM, Fabrice P. Laussy < fabrice.laussy at n0spam-gmail.com> wrote: > Dear all, > > Thanks for the solution. Supplemented with Oleksandr Rasputinov's fix: > > > Unprotect[Set]; > > Set[sym_[[part_]], val_] := sym = ReplacePart[sym, part -> val]; > > Protect[Set]; > > it works splendidly. > > In "some elements of Mathematica Design (1992)" [http://goo.gl/nm1tT], > Stephan Wolfram makes a point where one should resist the temptation to > design functions to do things that look natural for them to do, as they > could break dramatically later on. > > Here we have a clear case where Set seems it ought to work as redesigned by > Oleksandr. Is there any reason for this not being the default behaviour? > >