<div dir="ltr"><div dir="ltr">Hi Eliot,</div><div dir="ltr"><br></div><div>Thanks for the great explanation!  Quick question:  Will a become: cause the handler to be called on all referencing objects?</div><br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div>Can  ModificationForbidden be resumed?  I certainly hope so. <br></div></div></div></blockquote><div><br></div><div>Indeed its can.  Use in database write barriers is one major use case.  However, the framework for convenient use has yet to be designed and implemented.  We have lots of experience with this barrier in VisualWorks and some experience in Pharo, so designing the right support should not be hard at all. </div></div></div></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div>Magma's own WriteBarrier has one place where it dynamically compiles a literal in a method for the sole purpose of providing one extra reference slot needed for the framework.  This is a useful feature in a general sense, something I'd hate to see lost.  Yes, I understand it's "bad code" to modify a literal, just like using "become:" (which it also uses), but for frameworks that need to work slightly under the hood, these hacks can be very useful when one knows what they're doing.</div></div></div></blockquote><div><br></div><div>If you *do* have to modify a literal, then all you have to do is send beWritableObject to the literal in question and you'll be able to modify it (there is no recursive protection against setting read-only objects to writable).</div></div></div></div></div></div></blockquote><div><br></div><div>Oh, good.  :)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div>Unfortunately, I don't think the VM-based WriteBarrier can work for Magma due to its "global" nature.<br></div></div></div></blockquote><div><br></div><div>I'm willing to bet you that it can.  For example,e, it works in Gemstone on VisualWorks. The solution is to provide a policy registry hat on a per-object basis specifies how modifications to objects are to be handled.  This registry typically/best exists in the exception class (ModificationForbidden), and maps an object to a MessageSend or block. This registry tags specific instances with a retry policy, so e.g. Magma can put all objects it fetches from the database that it wants to be write-through into the registry </div></div></div></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div> and sets them to be read-only.  Then on an attempted modification the ModificationForbidden exception looks up the object in the registry, and if its there runs whatever code the registry specifies.  This would be some method in Magma that would</div><div>- set the object as writable</div><div>- ask the exception to retry the modification</div><div>- write the changed object through to the database</div><div>- set the object back to read-only</div><div>- resume the exception with a suitable value</div></div></div></div></div></div></blockquote><div><br></div><div><div>For this step, above:</div><div><br></div><div><div>      - write the changed object through to the database</div><div><br></div></div><div><div>I need a reference to the particular MagmaSession which the object belongs, so I can tell it, </div><div><br></div><div>       mySession modified: forbiddenException object</div><div><br></div><div>and why I use the compiled literal to hold that reference.  How would this be accomplished under this model?  IIRC, GemBuilder had the luxury / restriction of assuming there was only one backend Stone, so was able to go through a global...</div></div><div> <br></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div>Specific classes might implement a message the exception could send rather than require the registry is used.  But that's a space-saving optimization.<br></div></div></div></div></div></div></blockquote><div><br></div><div>Good, since the registration/unregistration cost would make merely reading objects from the database considerably more expensive than simply changing their class via primChangeClassTo:.</div><div></div><div><br></div><div>But I still need that reference to the Session anyway...</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div></div><div><br></div><div>Such a framework allows several orthogonal clients to share the framework, potentially on the same objects because the registry can be engineered to have more than one action per object.</div><div><br></div><div>(BTW, this is how VisualWorks does things, IIRC)</div><div><br></div><div>Does that instill more confidence?</div></div></div></div></div></div></blockquote><div><br></div><div>More, yes.  All the way there?  I'm not sure. I do also have need of #abort -- <i>restore all changed objects to their state as read from the database</i>.  This means all WriteBarrier handlers for objects read from that Session need to be temporarily suspended, since restoring the variables of an object require it to once again undergo modification back to its original state.  With Avi's / Magma's WriteBarrier, this is just flipping a boolean switch on the Session, but for this, would I have to</div><div><br></div><div>  - unregister all dirty objects, <br></div><div>  - then do the #abort function (restore all the dirty objects to their former state)</div><div>  - re-register those above objects, no longer dirty, but ready to track further updates</div><div><br></div><div>?</div><div>_______</div><div><br></div><div>It's okay.  With all on my plate, I doubt I'll ever have time to switch out Magma's WriteBarrier.  The ability to keep running Avi's working will be important for Magma in 6.0+, but thankfully sounds like a non-issue with a minor update.<br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>When we added read-only object support to VisualWorks some of the engineering staff were of the opinion that insulating customers from the change was a necessary thing, and so we implemented a preference to allow automatic mutating of read-only literals so that customers whose code did modify literals could set the preference rather than fix their code.  I *really* don't ant to do this.  It is a lot of complication for little gain; the right fix is just to rewrite the code not to write to literals.  Note that that's as easy as:</div></div></div></div></div></div></blockquote><div><br></div><div></div><div>I don't think we need a global preference as much as just let it be #isResumable.  Can we do that?</div></div></div></blockquote><div><br></div><div>Yes, it is, but doing so loses the modification:</div><div><br></div><div><div>| l |</div><div>[(l := #(1 2 3)) at: 2 put: 'nevermore']</div><div><span style="white-space:pre-wrap">        </span>on: ModificationForbidden</div><div><span style="white-space:pre-wrap">        </span>do: [:ex| ex resume].</div><div>l => #(1 2 3)</div></div><div><br></div><div>whereas one often wants to do something more like this:</div><div><br></div><div><div>| lit result |</div><div>result := [(lit := #(1 2 3)) at: 2 put: 'nevermore']</div><div><span style="white-space:pre-wrap">      </span>on: ModificationForbidden</div><div><span style="white-space:pre-wrap">        </span>do: [:ex| ex object beWritableObject. ex retryModification].</div><div>lit -> result #(1 'nevermore' 3)->'nevermore'</div></div></div></div></div></div></div></blockquote><div><br></div><div>I think I will prefer to take care of it as early as possible, on compilation, as in:</div><div><br></div><div>    class<br>        compileSilently: 'writeBarrier<br>    ^ #(size) first first'<br>        classified: 'access'.<br>    ((class methodDictionary at: #writeBarrier) literalAt: 2)</div><div>        <b>beWritableObject ;</b>           <b><font color="#0000ff">"<----- can I simply add in this line?"</font></b><br>        at: 1<br>        put: (WeakArray with: mySession)<br></div><div><br></div><div>and then not worry about ModifiedForbidden at all.</div><div><br></div><div>Best,</div><div>   Chris</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
</blockquote></div></div>