Merging Maps And Objects

Maps and objects have lot of similarities in dynamic languages such that a language designer should consider making them one in the same.
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 CeePlusPlus. HList provides similar facilities (using TypefulProgramming) in HaskellLanguage.

For Boost.Fusion see BoostFusion and BoostFusionUserExtension.

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']; // 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


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(...);
 function makeSound(obj) {
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.)

"dynamic" has many meanings where most "dynamic" languages have features of both static and dynamic typing (optionally defined, inferred and/or type checked at execution time). What is a "map-like object"? An Object is based on a Class whereas a Map is not. A Map contains it's own schema whereas an Object gets it's schema from the Class it is based on. If you have many Objects that are based on the same Class then that schema is only defined once. If you have many Maps, whether they have the same schema or not, each has it's own schema. My system can change the Class at execution time which most dynamic languages don't allow (Ruby can for instance). Inheritance has nothing to do with dynamic typing or not. I have a very easy way of translating an Object to a Map and vise-versa (the assignment statement), but they both have uses which make the one better or worse than the other, depending on it's use. Why choose to have one or the other in a language when you can have both? -- DavidClarkd

Objects are based on Classes and can therefore have multiple functions associated with them (Classes don't just identify a set of variables). What languages allow functions to be encapsulated with named Maps? I guess it would be possible but why give Maps that capability when you already have Classes that do exactly that? Maps are much more self contained than Objects and more light weight. My Classes can have meta and pseudo variables as well as functions. Why use a sledge hammer when a regular hammer will do? -- DavidClarkd

[What are "meta and pseudo variables"? How are your "[m]aps ... more self contained than Objects"?]

My system has 2 quite different kinds of Objects. One kind is used to program at the macro level (called a Server Object SO) and the other at the micro level inside the SO that uses a Class. Although both SO and normal objects contain both data and programs, they have a different set of features and are used for different purposes. The SO objects have their own local memory manager and can access global resources like other kinds of memory (heap etc), disk, web and other services and can only directly access their own data. SO objects send messages to each other that are queued and each SO executes on a single core as independently as possible. Any number of SOs can run on any number of cores at the same time. Code is always defined inside an SO and can be written in a totally single user style with no explicit locking or need to program for multi-user or multi-core processing. There are higher levels of abstraction at the SO level as well (apps and groups of SOs).

Normal objects are defined and used inside SOs where there is persisted data, functions and interfaces. Classes are only used for normal objects, as a SO has it's own setup/change document with it's own format. A Class can have any user defined data associated with a field that can be used to automatically create input HTML, reports etc. All Class data including, meta data defined on fields, is available at compile and execution time. These user defined attributes are called "meta data" in my system (eg label="Some Label:", dtype="Read Only", etc). Pseudo variables are a list of fields defined in a Class that don't change the resulting record length of the Object created from the Class. These fields are placed in a Map variable on each record where you can optionally define that "key/value" pair or not, on each row. A multi-index is available that can access these variables quickly using both the key and data for these pseudo fields. Many tables have a set of fields that are used by most rows (normal fields) but there is also many other fields that are only used by a small subset of the rows and pseudo variables are used to efficiently look after these fields. Pseudo fields can be added to a Class without any change to existing Objects that use that Class. Pseudo fields can be used anywhere "normal" fields can be used and they are validated like any other field even though they are optional on any row.

Although Objects can be created and used, most Objects are actually rows in Lists, Tables, Stacks, Queues and Indexes rather than in a single Object like most other OOP languages. Data can be easily moved from a Collection row to an Object, to a Map, or to a vector where each element can be a different type.

In my system, a Map is a normal variable type. It can contain any number of any other variable types, including other Maps. It doesn't "depend" on any other variable to define what it is, therefore it is self contained. All collections like List, Index, Table etc and Objects are defined by a Class that is a normal variable itself. The function of these Collections and Objects is therefore dependent on another variable for it's functionality. Sending a List to another SO would be useless if it's Class wasn't also sent, however a Map can be sent all by itself. Putting a List inside a Map automatically also puts it's Class inside the Map as well (or at least the part of the Class that is needed).

The topic of this page is why not combine Maps and Objects? The answer (at least on my system) is fixed length versus variable length. Objects are fixed length and Maps are variable length. Fixed width Lists (Collections) are very efficient but also not very useful when variable length data needs to be stored. All fixed and variable length data can be stored in a variable length structure like a Map but not as efficiently for many uses. If all the data in the collection is fixed length then why not use fixed length records rather than the more general variable length method? Even if some variable length data is needed and your processing doesn't need that variable length data then maybe the performance penalty of variable length storage can be elliminated by using fixed length records and adding the variable length data in another structure. This is the approach of my langauge. These fixed length records are fixed length Objects where the variable length field data is stored in a Memo manager associated with the List or Table. Objects always contain a specific set of fields of a certain length (have a record length) whereas Map data can contain any set of fields. The flexibility of a Map is required in some circumstances whereas always knowing a particular field exists in an Object or row of a Collection makes programming to those fields a lot easier and efficient. Using a field from a Map would normally mean you have to check that it exists in the Map before you use it but if you know the Class of an Object, you could just assume that variable always exists in that Object. Both Objects and Maps have advantages and programmers need access to both.

There are links under my id on this wiki that will point to my web site where there is much more information on my system if you are interested. -- DavidClarkd

{Re: "Objects are fixed length" - Please elaborate. In general, or your system?}

Your question concerns an implementation detail, so I don't know in general. My "Objects" are made up of fixed length and variable length fields. I implement those objects by creating a "fixed length" Object where the variable length fields use a separate "variable length data manager" to store their variable data in a serialized form. So my Objects are always fixed in length but the data contained in that Object can be of any variable length. -- DavidClarkd
See also: ObjectsAreDictionaries, NonOrthogonalLanguageFeatures
CategoryDataStructure, CategorySyntax, CategoryProgrammingLanguage, CategoryLanguageDesign
