====== Objects, namespaces, dictionaries, and hashes ====== ===== DRAFT IN PROGRESS ===== [[http://forum.lolcode.com/viewtopic.php?id=293|Discussion thread here]]. ===== Prelude ===== One thing that was apparent whilst writing this proposal up: we're missing something in our declarations... To create an empty (e.g., 0, 0.0, "", or FAIL) variable of a given type: I HAS A ITZ A To contrast with and as an adjunct to the usual: I HAS A ITZ ===== BUKKITs ===== BUKKITs are the container type. They may hold NUMBRs, NUMBARs, TROOFs, YARNs, functions, and other BUKKITS. Each entity within a BUKKIT may be indexed by a NUMBR or a YARN. These indices, whether NUMBRs or YARNs, referring to functions, variables, or other BUKKITs, are generically called "slots". ===== Declaration ===== To create an empty object within the current object's scope: I HAS A ITZ A BUKKIT To create an object based upon an existing object: I HAS A ITZ LIEK A Behavior of this sort of inheritance will be described further below. To define an object, its methods, and the contained variables all at once, the following block may be used within the ''HAI''/''KTHXBYE'' block (or another ''O HAI'' block). O HAI IM [IM LIEK ] KTHX One can also use that structure to create an independent object, not immediately bound to the current scope and callable from outside. This is preferred because it encourages code reuse. The same code is used //outside// the ''HAI''/''KTHXBYE'' block: O HAI IM [IM LIEK ] KTHX More details will follow, but I'm looking to integrate ideas from [[http://forum.lolcode.com/viewtopic.php?id=192|this thread]] from xrestaussuredx. ===== Old commands in the context of objects ===== The root object, the global scope we have dealt with so far, has been referred to as "''I''" in the following language constructs: I HAS A I HAS A ITZ HOW DUZ I …? These forms of the commands effectively create variables and functions within the current object. Since we've been working only in the "root" object, that has always been where the variables and functions have been created. To declare and create variables //within// an object known in the current scope, ''I'' is generalized to an '''' name: HAS A HOW DUZ …? To add a variable (indexed with a YARN) to an object that has been declared and is within scope: HAS A [ITZ | ITZ A ] HAS A ITZ LIEK To define a new function within an object currently within scope: HOW DUZ [YR …] IF U SAY SO ===== Slot access ===== To access slots of BUKKITs (from the scope that contains the BUKKIT), I propose doing so by naming the object and slot, separated by two exclamation points: !! !! !! Additionally, runtime access (and array iteration) can be facilitated with some indirection. A question mark is substituted for the second exclamation point, meaning that the identifier that follows is a variable, and the value of the variable is then used as the identifier for the slot: !? For example: I HAS A NINDEX ITZ "DISWON" I HAS A NOBJECT ITZ A BUKKIT NOBJECT HAS A DISWON ITZ "TREE" VISIBLE NOBJECT!?NINDEX BTW "TREE" The unicode character interrobang (**‽**, u203D), and the "exclamation question mark" (**⁉**, u2049) are both legal substitutes for the pair of characters. //Note: I know this is //possible// with no punctuation at all. My gut is telling me that we want a bit of distinction here just as markers for the fact that we are pulling in objects and identifiers from a different scope. I'm willing to discuss it, though: this is not an issue that the whole proposal hinges upon.// Numerical slots (indexed with a NUMBR) do not need to be declared before being written to. They do not need to be contiguous: sparse arrays are possible. They may be heterogeneous: they can contain different types. ==== Inheritance of slots ==== Declaring a variable within the current object adds that variable to the object. Accessing a variable from within the current object looks for that variable within the current object. If it is not found, it searches for the variable within the parent object, and on up the chain of parents until it reaches BUKKIT (the base object type), whereupon it fails. Assigning a variable within the object first searches for it within the current object. If it has been declared within the current object, then it is set. If that fails, it attempts to access it within the parent object. Search continues in up the chain of parents. If the variable name is found up the inheritance chain, then that variable is declared and created within the current object (where the search started), and the value is set. If the variable search fails and the variable was never previously assigned, then it's a declaration error. In this way, a child object has all of the values and methods of its ancestors, unless it replaces them within itself. ===== Scope ===== Functions do not automatically have full access to the containing object's variables. Write access may be gained to only the variables declared with ''MAH'': MAH [[AN] …] Similarly, objects may declare read/write access to the next object up the //containment// hierarchy with ''MAH'' (but note that this is less useful in general, since with object orientation, we generally know a lot less about the containing object than the inherited type.) A function has read access to its defined namespace's scope. It gains write access by declaring access with the ''MAH'' keyword. It has no (read or write) access to the //calling// scope. When writing LOLCODE without objects, with only the primary ''HAI''/''KTHXBYE'' block, functions written in the main block had calling access to each other and to variables defined within that main block (subject to the normal read/write caveats with the ''MAH'' declaration). Note that this was because of the definition's scope and not the calling scope. HAI I HAS A LIFE ITZ "GUD" HOW DUZ I QUOTE YR THINGY? ":":{THINGY}:"" IF U SAY SO HOW DUZ I CHANGE? MAH LIFE LIFE R QUOTE LIFE IF U SAY SO VISIBLE LIFE BTW: GUD CHANGE VISIBLE LIFE BTW: "GUD" KTHXBAI Note that ''CHANGE'' can change a value within current scope, but only because it declared it with ''MAH''. Functions could be read and executed within the current scope normally. HAI I HAS A NUM ITZ 2 I HAS A TING ITZ A BUKKIT TING HAS A NUM ITZ 3 VISIBLE TING!!NUM BTW 3 VISIBLE NUM BTW 2 I HAS A NUTHERTING ITZ LIEK A THING VISIBLE NUTHERTING!!NUM BTW 3 NUTHERTING!!NUM R 5 VISIBLE NUTHERTING!!NUM BTW 5 TING HAS A BAR ITZ "BAZ" VISIBLE NUTHERTING!!BAR BTW "BAZ" KTHXBYE In this example, both ''TING'' and ''NUTHERTING'' are contained within the root object. However, ''NUTHERTING'' inherits from ''TING'' and therefore implicitly starts out with (clones of) ''TING'''s values. Since ''TING'''s values are already notionally "within" ''NUTHERTING'', there is no need to declare ''NUM'' within ''NUTHERTING'' before (re-)assigning it. ''NUTHERTING'' also gains values that are later added to ''TING''. ---- (more to come on ''O HAI'' and creating/populating a BUKKIT wholesale and in place) --- //Adam, 2007/07/13 22:20//