Revision: 4180 http://vexi.svn.sourceforge.net/vexi/?rev=4180&view=rev Author: clrg Date: 2011-07-08 01:45:36 +0000 (Fri, 08 Jul 2011)
Log Message: ----------- Fix. Cloning documentation was all wrong. Modified Paths: -------------- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp 2011-07-06 17:24:17 UTC (rev 4179) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp 2011-07-08 01:45:36 UTC (rev 4180) @@ -154,25 +154,83 @@ /*@PAGE(concept=Cloning) * * <p>A clone is an object that shares the properties of the object from which it was cloned, but - * can be modified using traps that do not impact upon the original object.</p> + * is modified independently from the original object, with changes made to the clone never + * affecting the original.</p> * - * <p>Clones can be created using the <code>vexi.js.clone()</code> function.</p> + * <p>A clone of an object is essentially a JS object wrapping the original object — the + * clonee. The clone is initially identical to the clonee but is not the same object. Traps + * cascade to traps on the clonee, puts act on the clone, and reads fallback to the clonee only + * when the property is not in the keyset of the clone.</p> * + * <h3>Creating Clones</h3> + * + * <p>Clones are created using the <code>vexi.js.clone()</code> function.</p> + * * <p>You may get the original object using <code>vexi.js.unclone()</code> function. It will * always get the original object and never return a clone.</p> * + * <p>You may created multiple clones of an object. You may create clones of clones. Clones can + * be created and discarded without affecting the original object directly.</p> + * + * <p>A clone is a different object to its clonee, so the following is always true:</p> + * + * <pre> vexi.js.clone(clonee) != clonee;</pre> + * * <h3>Clone Behaviour</h3> * - * <p>A clone of an object is initially identical to the object it has cloned, the clonee, and puts - * and reads on the clone will act upon the clonee, but they are not the same object. Traps placed - * on the clone are not placed on the clonee. That is, puts and reads on the clone will act upon - * the clonee unless otherwise intercepted by non-cascading traps on the clone.</p> + * <p>General behaviour:</p> * + * <ul> + * <li> + * <p><b><i>traps</i></b></p> + * <p>Traps are assigned and removed only from the clonee. Traps on the + * clone are called in order of assignment, before cascading down to the + * trapchain assigned to the clonee. Traps are always called before any + * puts to the clone or reads from the clone or clonee.</p> + * <p>Traps on the clone are not visible to the clonee, so puts or reads + * made directly on the clonee will never invoke traps on the clone.</p> + * </li> + * + * <li> + * <p><b><i>puts</i></b></p> + * <p>Puts only ever affect the clone, and will add to the keyset of the clone + * just as with a normal JS object.</p> + * <p>Puts directly on the clonee do not affect the keyset of the clone.</p> + * </li> + * + * <li> + * <p><b><i>reads</i></b></p> + * <p>Reads only fall back to the clonee in the event that the property + * key does not exist in the keyset on the clone.</p> + * </li> + * </ul> + * + * <p>Keyword specific behaviour:</p> + * + * <ul> + * <li> + * <p><b>keysof</b></p> + * <p>Returns a combined keyset of the clone and the clonee, with the + * exception that 'remove' will only ever remove keys from the clone. + * if the property is only in the keyset of the clonee, this will cause + * an exception.</p> + * </li> + * + * <li> + * <p><b>typeof</b></p> + * <p>A clone will identify itself as the same type as the clonee.</p> + * </li> + * + * <li> + * <p><b>instanceof</b></p> + * <p>A clone is an Object in addition to being the same type as the clonee.</p> + * </li> + * </ul> + * * <p>Consider:</p> * * <pre> var clonee = { a:3, b:5 }; * var clone = vexi.js.clone(clonee); - * var z; * * // true * 3 == clonee.a == clone.a; @@ -181,15 +239,13 @@ * clone.a = 2; * 2 == clonee.a == clone.a; * - * // still true after put to clonee + * // put to clonee.a alters this * clonee.a = 1; - * 1 == clonee.a == clone.a; + * 1 == clone.a; + * 2 == clonee.a; + * clonee.a != clone.a; * - * // these reads are equivalent - * z = clone.a; - * z = clonee.a; - * - * // non-cascading traps + * // non-cascading traps on clone do not affect clonee * clone.b ++= function(v) { return; } * clone.b ++= function() { return 0; } * @@ -198,16 +254,15 @@ * clonee.b = 2; // clone.b == 0, clonee.b == 2 * * // these reads are not equivalent - * z = clone.b; // z==0 - * z = clonee.b; // z==2</pre> + * var r1 = clone.b; // r1==0 + * var r2 = clonee.b; // r2==2 * - * <p>You may created multiple clones of an object. You may create clones of clones. Clones can - * be created and discarded without affecting the original object directly.</p> - * - * <p>A clone is a different object to its clonee, so the following is always true:</p> - * - * <pre> - * vexi.js.clone(clonee) != clonee</pre> + * // write trap on clonee affects clone put + * clonee.c ++= function(v) { cascade = 2*v; } + * clone.c = 2; + * clone.c == 4; // true + * clonee.c = 3; + * clonee.c == 6; // true</pre> */ /** The minimum set of functionality required for objects which are manipulated by JavaScript */ @@ -349,25 +404,31 @@ } } - /** A JS.Clone of a JS is identical to the object it has cloned, the clonee, - * except that traps placed on it are not placed on the clonee. */ + /** + * A JS.Clone of a JS is a mirror of the object it has cloned, the clonee, + * however modifications of the clone are not made to the clonee. That is + * property puts and trap assignments on the clone do not affect the clonee, + * it is impossible to directly modify the clonee by modifying the clone. + **/ public static class Clone extends JS.Obj { + + // The JS that was cloned protected final Cloneable clonee; + public Clone(JS clonee) throws JSExn { if (!(clonee instanceof Cloneable)) { throw new JSExn(clonee.getClass().getName() + " does not implement cloneable"); } this.clonee = (Cloneable)clonee; } - // Non-Trap methods forward to the clonee - public JS unclone() { return clonee.unclone(); } + public Keys keys() throws JSExn { final Set ourkeys = keySet(); final Set allkeys = new HashSet(ourkeys); JS c = this.clonee; - while(true) { + while (true) { allkeys.addAll(c.keySet()); - if(c instanceof Clone) c = ((Clone)c).clonee; + if (c instanceof Clone) c = ((Clone)c).clonee; else break; } @@ -389,11 +450,11 @@ }; } protected JS remove(JS key) throws JSExn { - if(ourkeys.contains(key)){ + if (ourkeys.contains(key)) { JS r = Clone.this.get(key); Clone.this.remove(key); return r; - }else if(allkeys.contains(key)){ + } else if (allkeys.contains(key)) { throw new JSExn("Cannot remove key from clonee: " +key); } return null; @@ -404,28 +465,35 @@ public int size() throws JSExn { return allkeys.size(); } }; } - public JS callMethod(JS this_, JS method, JS[] args) throws JSExn { - return clonee.callMethod(this_, method, args); - } + + /** gets a property of the given key, falling back to the cloned object */ public JS get(JS k) throws JSExn { - if(hasKey(k)) return super.get(k); + if (hasKey(k)) return super.get(k); return clonee.get(k); } + + /** put directly on the given key, but never to the cloned object */ public void put(JS k, JS v) throws JSExn { super.put(k, v); } - public String[] getFormalArgs() { return clonee.getFormalArgs(); } - public int callType() { return clonee.callType(); } - public String coerceToString() { return clonee.coerceToString(); } - public JS type() { return clonee.type(); } /** gets a trap for the given key, falling back to the cloned object */ public Trap getTrap(JS key) { Trap t = super.getTrap(key); return t!=null ? t : clonee.getTrap(key); } + + // Non-Trap/-Property methods forward to the clonee + public JS callMethod(JS this_, JS method, JS[] args) throws JSExn { + return clonee.callMethod(this_, method, args); + } + public JS unclone() { return clonee.unclone(); } + public String[] getFormalArgs() { return clonee.getFormalArgs(); } + public int callType() { return clonee.callType(); } + public String coerceToString() { return clonee.coerceToString(); } + public JS type() { return clonee.type(); } public boolean instanceOf(JS type) { - if(super.instanceOf(type)) return true; + if (super.instanceOf(type)) return true; return clonee.instanceOf(type); } } @@ -447,8 +515,8 @@ } }; static public ConstructorList base = new ConstructorList(Constructor,null); - + protected ConstructorList constructors = null; // a map of values against properties stored on this object private Map props = null; @@ -489,10 +557,10 @@ } if (traps!=null && traps.size()>0) { Iterator I = traps.keySet().iterator(); - while(I.hasNext()){ + while (I.hasNext()) { JS key = (JS)I.next(); Trap t = (Trap) traps.get(key); - if(t.findRead()!=null) + if (t.findRead()!=null) throw new JSExn("cannot deepcopy object with read traps: "+JSU.toString(key)); } } @@ -694,7 +762,6 @@ } } } - /** <p>Returns obj$xxxxxxxx where xxxxxxxx is the hashcode in hex.</p> * <p>Uniqueness (so can act as a keys in a map) and some human readability are @@ -702,7 +769,6 @@ * <p>REMARK - the hash should be unique, though its not guaranteed by Java</p> */ public String coerceToString() { return "obj$" + Integer.toHexString(hashCode()); } - public Map getPropsMap() { return traps; } public Map getTrapsMap() { return props; } } @@ -710,10 +776,10 @@ /** An implementation of JS that supports a meta trap on all properties */ public static class Proxy extends Obj { static public JS Constructor = new JS.Constructor("Proxy"){ - public JS new_(JS[] args) throws JSExn { - return new JS.Proxy(); - } - }; + public JS new_(JS[] args) throws JSExn { + return new JS.Proxy(); + } + }; Trap propertiesTrap = null; public JS get(JS key) throws JSExn { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ All of the data generated in your IT infrastructure is seriously valuable. Why? It contains a definitive record of application performance, security threats, fraudulent activity, and more. Splunk takes this data and makes sense of it. IT sense. And common sense. http://p.sf.net/sfu/splunk-d2d-c2 _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn