Merging Maps And Objects

From RubyOnRails

{I'm curious about your statement, "... dynamic languages should merge associative arrays and OOP. They are too similar in dynamic languages to bother making distinct syntax." Could you expand on that? I'm not sure what you mean.}

Objects are very similar to maps (associative arrays or "hash") in many dynamic languages. With a few tweaks, they can be made one-in-the-same to simplify the language both conceptually and syntactically.

This has been done. LuaLanguage and JavaScript are examples. Boost.Fusion provides similar facilities (using TemplateMetaprogramming) for C++. HList provides similar facilities (using TypefulProgramming) in Haskell.

I don't claim it's a new or original idea. However, there may be ways to combine the best features and/or facilitate this concept further. --top

Dots and Brackets

Some languages have made it easier to mix dots and brackets as needed. Dots would usually be used, but brackets could be used if and when punctuation or "funny characters" are needed as part of the map key.

 x.y;
 x['y']; // equivalent
 x['7foo.*&6'];   // brackets used when the "key" has odd characters.
 x[myVar];  // if indexing is done via a varible

Each is used where more appropriate.

Storing Function Pointers

Maps could store function pointers to serve as methods. If parenthesis could be shortcut for an "executeFunction" operation, then it would resemble a method:

  x.y(p1, p2);  // shortcut

executeFunction(x.y, p1, p2); //longcut

Inheritance

A "reserved" key, such as maybe "~parent", could be used to specify the parent(s) for use in inheritance. If a method call is done on a map item and it doesn't contain the given key (method or attribute name), then the parent(s) are called until the name is found or until the top of the tree is encountered. "~parent" would contain the name of array (map) that serves as the parent. If multiple inheritance is allowed, then it would contain a list of the parents, separated by a comma. (This wouldn't be very efficient, but it would offer great meta-ability. Perhaps a shortcut could be to store the address of the parent array as an option, such as "&3928433" instead of "myArray". If the lookup mechanism sees the "&", it knows it's dealing with an address instead of a name.)

An alternative is to use a form of prototype-based inheritance and simply clone the "master" array to "inherit". It would only clone the method/function pointer (above), not the actual function code.

Even without cloning, there's no need for a formal "class" (as is the case with some other dynamic OO languages). A class-like syntax could be used to simplify the creation of the root objects.


What benefits does your scheme offer over more conventional OO syntax, such as that used in C#, Java, Python and Ruby? How does your scheme handle polymorphism and encapsulation?

It allows one to "switch" between using maps and objects or vise verse with little or no changes. It also simplifies the language and training because it reuses a single concept.

Why might you wish to switch between maps and objects?

Polymorphism is using the same key on a different array. It doesn't offer tight encapsulation, which is common with dynamic languages. I'd suggest you consult with fans of those languages, or related wiki topics, to hear their arguments for "loose" encapsulation. (It will probably trigger another type-heavy versus type-lite/dynamic debate.)

Could you expand on what you mean by "[p]olymorphism is using the same key on a different array"?

 person = newMap(...);
 dog = newMap(...);
 ...
 makeSound(person);
 makeSound(dog);
 ...
 function makeSound(obj) {
   obj.speak();
 }
Your approach seems similar to the struct/class equivalence in C++, except a struct is static but a map is (usually) dynamic. Is that what you have in mind?

{Structs and classes aren't exactly equivalent, they are similar or alike.}

What benefits does your scheme offer over more conventional OO syntax ...

Combining maps and objects simplifies GenericProgramming; for example, you can write functions to serialize arbitrary objects (even functions, if the language gives you a representation for them). SingleDispatch polymorphism is possible by assigning function pointers to object parameters - indeed, a common means of modeling OO is to use a record or map of names containing functions... though you might want a little SyntacticSugar for the 'this' or 'self' argument.

Encapsulation is provided by the borders of the map... but perhaps you meant to question the feasibility of InformationHiding, of the sort typically achieved by programming against AbstractBaseClasses (aka Interfaces). InformationHiding is important for security (per ObjectCapabilityModel), performance (optimizations), and forwards compatibility (CouplingAndCohesion). These are valuable properties that suffer in MergingMapsAndObjects, but there are several ways to recoup those properties if they are necessary.

Personally, I find mutable maps problematic, and I believe CompositeConsideredHarmful. If we have immutable maps, and we do not use 'objects' to compose data structures, then maps and objects no longer overlap and there is no reason to merge them. Top's desire is to eliminate apparent LanguageIdiomClutter. Rather than MergingMapsAndObjects, a feasible alternative is to further separate them.

What about separating the various features and allow them to be switched on or off as needed by language keywords or some other approach? Is there really a true difference, or can the various attributes be mixed and matched depending on need?
I am the developer of a dynamic language and I have both Objects and Maps. Although I allow interchange of them both in many places, they are quite different. An Object has no optional fields where a Map most certainly does. If a List is created using Class "xyz", then each row will have exactly the same set of fields if an Object is based on the same Class. Class has nothing to do with Maps. With an Object you could use syntax like "xyz.a" if you knew that the Class of "xyz" contained a field called "a", you could know that code would work but there is never a guarantee that any particular field exists in a Map. Using a field from a Map requires that you always verify it's existence before you use it but that can be done at compile time for a field in an Object.

Similar but definitely not the same. -- DavidClarkd

Doesn't sound like a "dynamic" language to me if it's hard to add or remove attributes to objects. If a map-like object had inheritance, then you'd know it always had "a" because the parent had "a". But if you are "locking" existence of attributes to class definition statements, then it's arguable not a dynamic language, or perhaps a hybrid of dynamic and static. (Of course it depends on whether one is using reference inheritance or cloning inheritance.)
See also: ObjectsAreDictionaries
CategoryDataStructure

EditText of this page (last edited July 5, 2013) or FindPage with title or text search