Root object The root object is an ancestor of every object, and thus defines behavior common to all objects. Public methods (non-overridable): name() Get name (non-overridable) owners() Get owners is_owned_by(obj) True if obj owns this public() True if object is public fertile() True if object is fertile parents() Returns parents of this children() Returns children of this ancestors() Returns ancestors of this is(obj) True if obj is this or an ancestor follows(protocol) True if obj follows protocol is_agent(protocol) True if obj is agent of protocol Owner methods: set_name(name) Sets object name set_public(val) Sets whether an object is public set_fertile(val) Sets whether an object is fertile set_owners(owners) Specify new set of owners add_owner(obj) Adds an owner del_owner(obj) Removes an owner add_parent(obj) Adds a parent del_parent(obj) Removes a parent destroy() Destroys this compile(code, name) Compiles a method onto this add_parameter(name) Adds a parameter del_parameter() Removes a parameter del_method(name) Removes a method Restricted to owners for non-fertile objects: spawn([args]) Spawns a child Restricted to owners for non-public objects: parameters() Returns parameters methods() Returns method names find_method(name) Finds method definer find_next_method(name, after) Finds next method definer list_method(name) Returns method definition show() Returns an object listing object root var root name "Root object" var root owners [$root] var root public 1 var root child_index 0 var root fertile 0 var root inited 0 method initialize if (!caller().is_agent('hierarchy) && sender() != this()) throw(~perm, "Caller is not this or an agent of hierarchy protocol."); if (!inited) { (> .init(ancestors()) <); inited = 1; } . method deinitialize if (!caller().is_agent('hierarchy)) throw(~perm, "Caller is not an agent of hierarchy protocol."); (> .deinit(ancestors()) <); . method init arg ancestors; var prime_parent; if (!caller().is_agent('hierarchy)) throw(~perm, "Caller is not an agent of hierarchy protocol."); if (definer() in ancestors) { child_index = 0; name = "_unnamed_" + tostr(this()); owners = setadd([this()], sender()); fertile = 0; // Inherit public, fertile from parent. prime_parent = parents()[1]; public = prime_parent.public(); } . method name disallow_overrides; return name; . method owners disallow_overrides; return owners; . method is_owned_by disallow_overrides; arg obj; return obj in owners || $sys.is_admin(obj); . method public disallow_overrides; return public; . method fertile disallow_overrides; return fertile; . method set_fertile arg val; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner"); fertile = val ? 1 | 0; . method set_name arg s; // Only accept calls from owners or admins. if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); // Make sure first argument is a string. if (type(s) != 'string) throw(~type, "First argument (" + toliteral(s) + ") not a string."); // Don't allow names beginning with "_unnamed_". if (strlen(s) >= 9 && substr(s, 1, 9) == "_unnamed_") throw(~name, "Invalid name."); // Set name to first argument. name = s; . method set_public arg val; // Only accept calls from owners or admins. if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); // Set public to the given value. public = val; . method set_owners arg owners_arg; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); owners = owners_arg; . method add_owner arg obj; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); owners = setadd(owners, obj); . method del_owner arg obj; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); owners = setremove(owners, obj); . method chparents arg parents; var old, init, uninit, i; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); old = ancestors(); (> $sys.change_sender_parents(parents) <); init = []; uninit = old; for i in (ancestors()) { uninit = setremove(uninit, i); if (!(i in old)) init = init + [i]; } catch any { .init(init); } with handler { (| .uninit(init) |); $sys.change_sender_parents_back(old); return; } (| .uninit(uninit) |); . method ok_to_inherit arg obj; // This method is called by the system object to determine if it is okay // for an object to inherit from us. return (fertile || .is_owned_by(obj)); . method spawn arg name; if (!fertile && !.is_owned_by(sender())) throw(~perm, "Not fertile and sender not an owner."); // Ask the system object for a child. child_index = child_index + 1; return $sys.spawn_sender(child_index, sender(), name); . method destroy // This doesn't actually destroy us immediately, but we will go away when // nothing is holding onto us any more. if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); (| .uninitialize() |); $sys.destroy_sender(); . method add_parameter arg name; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); (> add_parameter(name) <); . method parameters if (!public && !.is_owned_by(sender())) throw(~perm, "Not public and sender not an owner."); return parameters(); . method del_parameter arg name; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); (> del_parameter(name) <); . method del_method arg name; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); (> del_method(name) <); . method methods if (!public && !.is_owned_by(sender())) throw(~perm, "Not public and sender not an owner."); return methods(); . method parents disallow_overrides; return parents(); . method children disallow_overrides; return children(); . method ancestors disallow_overrides; return ancestors(); . method is disallow_overrides; arg obj; return (obj == this() || obj in ancestors()); . method find_method arg name; if (!public && !.is_owned_by(sender())) throw(~perm, "Not public and sender not an owner."); return (> find_method(name) <); . method find_next_method arg name, after; if (!public && !.is_owned_by(sender())) throw(~perm, "Not public and sender not an owner."); return (> find_next_method(name, after) <); . method list_method arg name; if (!public && !.is_owned_by(sender())) throw(~perm, "Not public and sender not an owner."); return (> list_method(name) <); . method compile arg code, name; if (!.is_owned_by(sender())) throw(~perm, "Sender not an owner."); return compile(code, name); . method show var output, i, data, obj, vars; if (!public && !.is_owned_by(sender())) throw(~perm, "Not public and sender not an owner."); // Show parents. output = ["Parents: " + toliteral(parents())]; // Show parameter names. output = output + ["Parameters:"]; for i in (parameters()) output = output + [" " + tostr(i)]; // Show method names. output = output + ["Methods:"]; for i in (methods()) output = output + [" " + tostr(i)]; // Show variables. data = $sys.sender_data(); for obj in (ancestors()) { vars = (| data[obj] |); if (!vars) continue; output = output + [toliteral(obj) + " variables:"]; for i in (dict_keys(vars)) output = output + [" " + tostr(i) + ": " + toliteral(vars[i])]; } // Return what we've shown. return output; . method follows disallow_overrides; arg protocol; var obj; for obj in ($sys.followers(protocol)) { if (has_ancestor(obj)) return 1; } return 0; . method is_agent disallow_overrides; arg protocol; return (| this() in $sys.agents(protocol) |) ? 1 | 0; . method eval arg code; var errors, result; if (!.is_owned_by(sender())) throw(~perm, "Sender doesn't own this."); // Compile the code. errors = compile(code, 'tmp_eval); if (errors) return ['errors, errors]; // Evaluate the expression. Be sure to remove it afterwards, so that no // one else can call it. catch any { result = .tmp_eval(); } with handler { del_method('tmp_eval); rethrow(~methoderr); } del_method('tmp_eval); return ['result, result]; . eval .add_verb("@list * on %this", 'list_verb, 'remote); .add_verb("@show %this", 'show_verb, 'remote); .add_verb("@params %this", 'params_verb, 'remote); .add_verb("@methods %this", 'methods_verb, 'remote); .add_verb("@verbs %this", 'verbs_verb, 'remote); .