Tuesday, August 3, 2010

Multiple presences.
Brief summary:
     I think we should make deep copies of presences when we're making new presences.
       ---->Issues to be decided: What context are handlers executed in? When will we be in root context?
Axioms/Assumptions:
    1) Entities support multiple presences between worlds.
    2) There will be one entity presence per world.
    3) The (overwhelmingly) common use case will be a programmer scripting an entity with a single presence.
    4) The most likely reasons one would have multiple presences would be to:
      a) Bridge two worlds: Project content from one world into another world.
      b) Simplify sharing state between presences.
    5) Even for the above two scenarios, the amount of shared state between two presences should be small compared to the amount of independent state. For instance, consider an art gallery. The art gallery may want to share some data (eg. a list of which pieces are for sale), but it may not want to share the majority of other data. For example, what times the gallery closes; whom to contact in case of fire, flood, or theft; customer's addresses; etc. (Note: this point excludes functions. Both presences will likely share lots of functions.)
    6) Presences in multiple spaces will want to be more similar to each other than different: if an entity is a store in Space A, it's not going to be a truck in Space B; if an entity is a duck in Space B, it's not going to be a computer in Space A.


Wants:
    1) Want to make programs easy to reason about.
    2) Want default case to hide presences.
    3) Want to limit having to re-write or copy functions each time we create a new presence.




Suggestion:
    1) Have a default presence.
    2) When creating a new object in the root context (but when will we be in the root context?), the object will be copied to each presence. For instance:

-Before object creation:
root------List Object
/ \
/ \
P1 P2

-Object creation:
myList = List();

-After object creation:
root------List Object
/ \
/ \
P1 P2
| |
myList myList

    3) One can specify context of object to change by prepending presence. For instance,

p1.myList.add(7)

    adds the number 7 to the list under presence 1. If one does not prefix with desired presence, for instance,

myList.add(7)

    then the operation will occur to the object in the default presence.
    4) To specify an object that will be available globally, one should just need to do the following:

-Before global object creation:
root------List Object
/ \
/ \
P1 P2

-Object creation:
AddressBook = globvar Object(); //or root.AddressBook = Object();
root.AddressBook.listOfNames = List();
root.AddressBook.listOfAddressables = List();

-After object creation:
root------List Object
/ \ |____AddressBook---listOfNames
/ \ |______listOfAddressables
P1 P2
| |
myList myList

-To instantiate a separate copy for each presence:
mAddrBook = AddressBook();

root------List Object
/ \ |____AddressBook---listOfNames
/ \ |______listOfAddressables
/ \
mAddrBook----P1 P2---mAddrBook
| |
myList myList

    5) Let's say that myList has the function messageSumElements, which sums all the elements in the list and then writes a message to all presences in its local address book with the sum of the elements in the list:

function messageSumElements()
{
//initialize counter
summer = 0;

//walk list and sum.
for s in myList:
summer += s;

//send individual message to all members of mAddrBook
for s in mAddrBook.listOfAddressables:
s.sendMessage(str(summer));
}

    When you call

p1.myList.messageSumElements()

    the function messageSumElements will execute within the context of p1. What this means is that the mAddrBook inside of messageSumElements will be p1's mAddrBook.
    If you wanted to instead send messages to members of another presence's address book, you could re-define the messageSumElements function as follows:

//presArg is a presence argument that tells us where to select address book data from.
function messageSumElementsOthePres(presArg)
{
//initialize counter
summer = 0;

//walk list and sum.
for s in myList:
summer += s;

//send individual message to all members of mAddrBook
for s in presArg.mAddrBook.listOfAddressables:
s.sendMessage(str(summer));
}

    And to call it, you would say:

p1.myList.messageSumElementsOtherPres(p2);

    Finally, to always send messages to a hard coded presence (discouraged: what if you got disconnected?):

//always sends messages to presence 1.
function messageSumElementsFixedPres()
{
//initialize counter
summer = 0;

//walk list and sum.
for s in myList:
summer += s;

//send individual message to all members of mAddrBook
for s in root.p1.mAddrBook.listOfAddressables:
s.sendMessage(str(summer));
}

    6) We can declare a handler for presences to handle when presences are destroyed. This handler would, for instance, save all objects' data.
    7) For state that should be shared, for instance a global counter, you would create it as follows:

root.counter = 0;

    Let's say the messageSumElements function from above also wants to increment this global counter each time it's called, we'd re-define the function as follows:

function messageSumElementsAndIncrement()
{
//initialize counter
summer = 0;

//walk list and sum.
for s in myList:
summer += s;

//send individual message to all members of mAddrBook
for s in mAddrBook.listOfAddressables:
s.sendMessage(str(summer));

//******Change:
root.counter +=1;
//******End change
}

    8) When add new presence, we just copy the object tree of the default presence (or have no object tree if no previous presence).

P3 = new Presence(); //copies default presence's object tree.
P4 = new Presence(P2); //copies p2's object tree.
P5 = new Presence(null); //creates a presence with a blank object tree.




Reasons:
*****
    -For the case of a single presence, a programmer won't really have to worry too much about the difference between globvars and presence vars. Using either should work, but mixing and matching won't work (because of the implicit default presence).
    -For the case of a single presence, mirror keywords won't affect program control.
    -When creating multiple presences, state defaults to separated (through copying object tree), so don't have to juggle a bunch of what belongs to whom (recall assumption that there will be more separate data than shared data). Only have to declare what state should be shared (and hang it off of root or hang it off of a single presence, and fix that presence as where the state is stored in all calling functions).
    -Because they have similar object trees, presences will behave similarly in different spaces. However, it's easy for the programmer to specifically tinker with presences in different spaces and change behavior.
    -Supports copy-and-paste from the internet. Imagine an alternate solution, where programmers needed to specify the context of each object in each function. For instance, returning to the messageSumElements function, a programmer finds the following code snippet on the Internet and copies and pastes it into his/her editor.

function messageSumElementsNoContext()
{
//initialize counter
summer = 0;

//walk list and sum.
for s in root.presence1.myList:
summer += s;

//send individual message to all members of mAddrBook
for s in root.presence1.mAddrBook.listOfAddressables:
s.sendMessage(str(summer));
}

    If the programmer wanted this to work for all of his/her presences, he/she would have to make separate copies for each, and remember to over-write all of the times that "root.presence1" is prefixed to words (common way to gather bugs according to CP-miner paper).
    -An alternative approach that would also solve this problem is if we had functions pass the "self" keyword. The default presence would be passed as self when the argument isn't specified. Reason not to:
      -->May show too much to programmers that just wanted to have a simple, single-presence entity.
      -->Consider the messageSumElements function from above with self command. Wouldn't it look like this:

function messageSumElementsSelf(self)
{
//initialize counter
self.summer = 0;

//walk list and sum.
for self.s in self.myList:
self.summer += self.s;

//send individual message to all members of mAddrBook
for self.s in self.mAddrBook.listOfAddressables:
self.sendMessage(str(self.summer));
}




Incidentals:
    The structure of a presence:
      Field: Addressable.
      Field: Geometry (from space).
      Field: Presence specific objects.




Issues:
    When modifying a function in the code text, how will a programmer know that its a function for presence 1 or presence 2?
      --->Mitigated through a good ide, where you can visualize object tree.
    What happens when add new presence?
    Which direction will the prototype look for things? Can you have a prototype that is in the presence change.
    When will we ever be in the root context?
    What context will handlers be executed in?

Friday, July 2, 2010

system.presences

Concretizing our concept of presences and separating the entities from presences, we have a new reference to system.presences in the Emerson.  At present, we have two addressable arrays:  system.presences and system.addressable .  Presences are the self address of the hosted entity each in different space. IT is just a logical connection. Currently, we just store the spaceID of the space in the presence javascript object which should be sufficient for most purposes.  Addressables lets the script to refer other presences of other entities. However, addressables will contain presences too.

Following this, work needs to be done to unify addressables and presences. The idea is that a presence can do few things synchronously too while addressables will always require the asynchronous messaging. A bit more thought has to go into designing this. Currently addressable does not store the space information of the entity. And this has to be incorporated too.

Next thing would be to add functionalities like system.presences[0].setMesh  and other functionalities similar to this. All these are inbuilt into system currently and assumes the default connection to the space.These have to be made space specific.

Thursday, July 1, 2010

system.create_entity

Emerson finally has the ability to create scripted entities from an executing script. This is achieved by following


           system.create_entity(Vector3d pos&)


The (presence of )new entity will be at the position specified by pos and with other default location properties. Entity creation is an asynchronous operation and will not block the running script. The script for the new entity is initialized only after the new entity is connected to space.


There are few things that need to be solved as followup of this feature:



  1. create_entity can take more arguments. 
    1. Texture
    2. Reference to existing entity
    3.  may beLocation features like orientation, velocity
    4. A script to attach to the script
  2. The addressable array for all the neighboring entities and the new entity should be updated to reflect the new entity. This can be done by adding a callback in ObjectScript and calling it when the space confirms the new entity is connected.


Screen Shots of new entities. The small cubes were created while running the "create.js" script.







Thursday, June 24, 2010

Squashed a seg fault related to modifications of event handler list made from within an event handler.

Problem:
On receiving a message, we iterate through our list of registered event handlers to see which callbacks to fire. If a message matches a callback, then it fires that callback. However, if a callback for an event handler affects the list of registered event handlers (eg through addition of handler or removal), elements in list of event handler I was iterating over became invalid, causing a seg fault.

Solution:
All additions and removals of event handlers take effect *after* we've tried matching a message against all registered event handlers. All addition and removal changes to event handler list are queued, and applied at end of iterating over list. (Order: first apply all additions, then apply all removes.)
Note: this does not affect suspend and resume of event handlers. An event handler can be suspended or resumed from within a handler.

Reasoning:
We could have also immediately added and removed handlers, rather than queueing operations for end. However, it seemed that reasoning about what a program would actually do became very difficult. For instance, users would have to know what order handlers executed in to determine what the results of a program would actually be.

-Behram

Wednesday, June 23, 2010

Done today:
When register handler, returns an object. This object supports suspend, resume, and printContents. (Suspend will prevent the handler from firing, resume allows a suspended handler to resume firing, and printContents prints the pattern data that causes a callback to fire.)

--Still need to print the callback in printContents.
--May want to make it so that all handlers are accessible through some type of system array. (If you lose track of the object you assigned to the handler, currently, you're out of luck.)
--Probably put off until users demand: make it so that can reset the callback from the handler object.

Bugs fixed:
--Can match against values again. (Needed to create persistent objects for values in JSPattern.hpp.)

Decisions made:
--Will not support multiple senders to match in event handlers. Reason: users can always do dispatch within a function, and membership that would match an event handler is likely to be dynamic. Downside: could lead to some bad coding practices. For instance, someone might iterate over an array, creating separate handlers for each potential sender in the array. These handlers would do the same things: would be difficult to modify, inspect, and play with.

--Holding off on a "default" handler. Default handler is invoked if no other handler matches. For now, not adding it because no concrete use case. Additionally, makes difficult to reason about what happens if users do some additional checks in their handlers that aren't relevant.

--I'm leaning heavily towards dispatching all handlers with matching patterns. Ewen mentioned doing something along the lines of strongest match, but that seems like a can of worms: how do you measure strongest? If you say that it's the most fields, then you can still have ties.

Current status:
--Broadcast works. (__broadcast(obj))
--Can send specific messages through system.addressable array.
--Objects serialized. (Can pipe around code with this + messaging)
--Pattern matching (minus prototype) works.

Tuesday, June 22, 2010

registering callback for multiple senders and a given pattern

today we argued on whether is it useful to have a list of senders as part of system.registerHandler().
It is not clear how useful this feature is to have at level of the language. Seems like a librarish type of feature. For example, exposing  system.addressable is enough and then system.broadcast just becomes a library feature. Similarly, how frequently user would actually want to register a set of senders for a particular pattern. Also, this list has to be static list => how frequently do users know their senders beforehand at the time of registering the callback.

In the bulletin board, user really didn't know the senders beforehand ( until they registered) and so callback was registered when the users were registered i.e. one at a time. Additionally, having an array of patterns might not be a good idea when we anyways plan to have "regex" for patterns.

It is certainly a useful feature and we should, as we write more scripts, evaluate the usefulness of this feature. We might end up incorporating this in emerson.

Monday, June 21, 2010

Doxygen documenting

Add the support for the Emerson API using doxygen or any other popular document generating tool.
Also, integrated the documenting process with the build.

Objects and Regular Expressions

Currently pattern matching does not use "regex" for the fields. Field name can be a regex. Field values which are string can be a regex.  Also, the value of a field can be an object and we need to do some pattern matching recursively. Need to add the support for objects as the field values.

Resume and Suspend

have two new functionalities:


  • suspend: This is like temporarily disabling callbacks for a script. This is good because if an entity goes bizarre after executing some callback, it should be easy to disable a callback. 
  • resume: re-enable a callback which has been suspended. The callback must be register for resume.
suspend and resume can happen for event callbacks that have been registered.

We currently have a "system.reboot" which clear the complete state of the script. This is like getting a new scratchpad..

some more work

There are multiple events in the system: Communication, Timers, Proximity and Motion. Can we unify them to a generic events; after which all events would be handled in a uniform way. However, the emerson syntax may be different for them.

         Eg. for timeout events we have:

         system.timeout(30, callback)

         OR we could have

        timer_id = timerEvent(30);
        register_handler(timer_id,  callback);

need to think how we can get all the events to be treated the same way in the runtime
Scoping questions:
--->There's an issue with whether variables are going to be looked-up/written to local objects or global. For instance:

class ()
{
x = 3;
function mFunc()
{
x=2; //local x, or class's x
}
};

Another way of doing things is to have self.x/this.x be for global. Javascript gives var for local. Do we just want to force using var?