Objects, namespaces, dictionaries, and hashes
DRAFT IN PROGRESS
I hope to “finish” the proposal this weekend before we begin ripping it apart. Feel free to look at it and get a feel for what I've tried to compile.
Variables/Scope
Memory
The LOLCode language so far has either had only static variables, or required the use of a garbage collector. This proposal formally specifies a Garbage Collection Strategy. All variable are merely refernces to locations in memory. It is assumed that when a variable is no longer referenced, that variable's allocated space will be freed sometime in the future, or on program exit.
Declaration
Here's a few changes to how Declaring variables works.
I HAS A <variable> ITZ <value>
This instantiates and initializes a variable. If the value is a literal, the variable is initialized to the appropriate object type (YARN, TROOF, NOOB, NUMBR, NUMBAR). If the value is an identifier or expression, the variable is initialized to the resulting expression.
I HAS A <variable> ITZ A <type>
This instatiates a variable, and initializes it to a default value.
Built-In default values:
- YARN - ””
- TROOF - FAIL
- NUMBR - 0
- NUMBAR - 0.0
- NOOB - NOOB
I HAS A <variable>
This instatiates a variable and initializes it to NOOB. It is shorthand for I HAS A <variable> ITZ NOOB
Function types are declared/initialized using the HOW DUZ I / IF U SAY SO blocks, however they behave the same as variables. For example:
HOW DUZ I var YR stuff BTW implement IF U SAY SO I HAS A var ITZ 0 BTW Throws an error AS var is already taken var R 0 BTW FUNIKSHUN var no longer exists, it's now NUMBR-0
Deallocation
<variable> R NOOB
This above code ensures that a variable no longer references anything. The reference still exists on the current scope and still requires a small amount of memory. If this was the last reference to an object, it will be garbage collected in the future.
NERF <variable>
Is a command that will remove the reference from the current scope. If this was the last reference to an object, it will be garbage collected in the future.
Primitive Types
All primitive types are considered Immutable. All built in operations return new objects instead of references to old objects. The exceptions to this rule are WIN, FAIL and NOOB. Every TROOF reference is either the WIN or FAIL object. Every NOOB reference is ot the NOOB instance.
SRsBiZnUs Cast
The SRS BIZNUS operation can be used to interpret a YARN (or something castable to a YARN) as an identifier.
SRS BIZNUS <expression> MKAY
Example:
I HAS A var ITZ 0
Is the same as:
I HAS A name ITZ "var" I HAS A SRS BIZNUS name MKAY ITZ 0
FUNKSHUNS
Functions have a new function call syntax to ensure appropriate gramatical parsing:
I IZ <funkshun> (WIF <argument> (AN <argument>) * MKAY) ?
The I parameter is used to distingish a function call on the current namespace vs. a function call on a bukkit (defined below).
BUKKITs
BUKKITs are the container type. They may hold NUMBRs, NUMBARs, TROOFs, YARNs, functions (FUNKSHUN), 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”.
Introduction
To create an empty object within the current object's scope:
I HAS A <object> ITZ A BUKKIT
This object will have the default behavior of all bukkits.
Slot Creation / Assignment
One of the most obvious thing to do with a bukkit it place something in a slot.
<object> HAS A <slotname> ITZ <expression>
A slot may be declared/initialized more than once, however doing so only changes the value the slot references.
This places the value returned from expression (could be another object) into the slot identified by slotname. The slot name may be any identifier (or SRS BIZNUS cast). Note: This identifier may be a function. Example:
HOW DUZ I blog YR stuff VISIBLE blog IF U SAY SO <object> HAS A blog ITZ blog
Functions
The function definition syntax has changed as well. To declare a function inside a bukkit's slot
HOW DUZ <object> <slot> (YR <argument>)* ( <statements> )* IF U SAY SO
So, the above code becomes
HOW DUZ <object> blog YR stuff VISIBLE blog IF U SAY SO
Me, myself and I
Functions operate differently in the context of bukkits. When a function is called from an object, some scope rules and variable resolution change.
When an identifier is used in a function, the variable is looked up in the following manner:
- The function namespace
- The calling object's namespace (if called from object)
- The “global” namespace
IT is always looked up from global namespace
The function namespace is made up of all arguments and any variable declared using the identifier “I” it resides within the function's namespace.
HOW DUZ I foo YR bar BTW bar is on function namespace I HAS A bar2 BTW bar2 is on the function namespace IF U SAY SO
ME is an identifer used to access the calling object of a function. If there is no calling object, access to ME throws an exception. Define This exception
Declaring a variable on the calling objects namespace is done as follows:
HOW DUZ I foo YR bar ME HAS A bar2 BTW bar2 is now a slot on calling object IF U SAY SO
ME can also be used to explicitly use a slot variable vs. a function namespace variable.
HOW DUZ I foo YR bar ME-bar R bar BTW sets calling object's bar slot to bar value IF U SAY SO
Alternate Syntax
There is an alternate way to define a new object/bukkit
O HAI IM <object> [IM LIEK <parent>] <code-block> KTHX
Anything “I” inside the codeblock actually refers to <object>. This can simplify syntax, eg:
O HAI IM pokeman I HAS A name ITZ "pikachu" HOW DUZ I pikachu YR face BTW DEFINE IF U SAY SO KTHX
Identifiers within the O HAI block are looked up via slot-access first. If they are not found, the global scope is then searched. If that fails, then an error is thrown.
Slot Access
Bukkit slots are accessed using the slot operator ”-”.
<object> - <slotname>
or indirectly using the Srs Biznus operator
<object> - SRS BIZNUS <expression> MKAY
Slot access is very important to function calls. The new function call syntax is as follows.
To call a function on an object:
<object> IZ <slotname> (WIF <variable> (AN <variable)*)? MKAY
combined with the SrsBinuz operator allows the following:
HOW DUZ I get YR object AN YR varName I HAS A funcName ITZ SMOOSH "get" AN varName MKAY FOUND YR object IZ SRS BIZNUS funcName MKAY MKAY IF U SAY SO
This will call get<varName> on object.
Special Slots
Every bukkit contains a few slots that have special meaning
- parent
- zomg
TODO - Figure out what else may be needed
parent
refers to a bukkit's “parent” object and is described below.
zomg
refers to a function that is called when slot access fails. This function should return a variable (that will be placed in the unknown slot) or throw an exception. The default implementation of zomg is to always throw an exception.
Inheritance / Prototyping
To create an object based upon an existing object:
I HAS A <object> ITZ LIEK A <parent>
Behavior of this sort of inheritance is described further below.
To define inheritance using alternate syntax, do the following.
O HAI IM <object> [IM LIEK <parent>] <code block> KTHX
Inheritance implies a few things, one of which is inheritance of slots (described below). Another thing inheritance does is automatically create a “parent” slot on the new object. The “parent” slot refers to the object that this object was inherited from, or its prototype. The parent slot is treated specially by the Bukkit. An interesting side effect of this is that a Bukkit may change its “parent”/“prototype” by changing its parent slot. More on this later.
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 (using the parent slot), and on up the chain of parents until it reaches an object where the parent slot is NOOB or it reaches a parent object is has already searched before.
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.
Functions and Inheritance
No matter where a FUNKSHUN is stored in a slot, during a Slot-Access Function call, the Function obtains variables from the object it was accessed from.
TODO - This needs to be reworded
<object> IZ <functionSlotName> MKAY
In this case, the function will pull variables from <object>.
SO:
HOW DUZ I funk YR shun ? VISIBLE SMOOSH prefix AN shun MKAY IF U SAY SO O HAI IM parentClass I HAS A prefix ITZ "parentClass-" I HAS A funk ITZ funk BTW Pulls funk from global scope KTHX O HAI IM testClass IM LIEK parentClass I HAS A prefix ITZ "testClass-" KTHX parentClass IZ funk WIF "HAI" MKAY BTW parentClass-HAI testClass IZ funk WIF "HAI" MKAY BTW testClass-HAI
Mixin Inheritance
LOLCode supports a form of multiple-inheritance (I'm calling mixin-inheritance) via a new use of the SMOOSH operator.
I HAS A <object> ITZ A <parent> SMOOSH <mixin> (AN <mixin>)*
or
O HAI IM <object> IM LIEK <parent> SMOOSH <mixin> (AN <mixin>)* <statement-block> KTHX
A mixin may be any bukkit type. When declaring a new object using mixins, All slots defined on the mixin are copied into the newly construct bukkit in reverse order of declaration. So
I HAS A ZipFileRiver ITZ A River SMOOSH FileStuffz AN ZipStuffz
This copies all slots from ZipStuffz into ZipFileRiver, then all slots from FileStuffz into ZipFileRiver, then replaces the parent slot with a reference to River.
Mixin-Inheritance is static. It can only pull in slots that are defined when the mixin takes place. If the FileStuffz or ZipStuffz objects change after the ZipFileRiver object is defined, the ZipFileRiver class does not see the change.
Here's a method of performing Mixin-Inheritance after a bukkit has been created.
Example:
BTW burger is on the stack I HAS A cheezburger ITZ A burger SMOOSH cheeze BTW Let's do the same thing, but assume cheezburger2 already exists BTW Makes sure all of cheeze and its parent slots are copied into slice I HAS A slice ITZ A bukkit SMOOSH cheeze slice-parent R burger-parent BTW slice & burger are now commons sub-classes cheezburger2-parent R slice BTW cheezburger2 now has same functionality as cheezburger
LOLCode Standard Library
These classes represent ideas for an LOLCode standard library of classes for use when Bukkits are first implement. These classes represent functionality and reference implementation and are by no means what should be distributed with LOLCode runtimes.
PileZ (Stacks)
${standlibdir}/collections/pilez.lol
O HAI IM pile I HAS A length IZ 0 HOW DUZ I push YR item ME HAS A SRS BIZNUS length MKAY ITZ item length R SUM OF length AN 1 IF U SAY SO HOW DUZ I pop length R DIFF OF length AN 1 BTW Do bounds checking... I HAS A mom ITZ ME-length NERF ME-SRS BIZNUS length MKAY FOUND YR mom IF U SAY SO KTHX
Usage:
RiverZ (Streams)
${standlibdir}/collections/riverz.lol
O HAI IM River KTHX
Usage: