Exagg'itive Summary (TM)
You get a few things.
- Prototypal inheritance and cloning
- Dynamic addition of new properties
- Co-existence of objects of different versions (specification levels) of the same class.
- Objects belonging to the more recent versions (specification levels) will have extra "optional" properties.
- Introspection of properties, old and new
- Introspection of validation rules (discussed below)
There's one fatal drawback.
- Compiler doesn't check for misspelled strings for you.
- Automatic refactoring tools won't rename property key names for you - unless you pay for the fancy ones.
The thing is, you can get introspection by using, um, introspection. This is what usually happens:
- Enable reflection.
- Add a large introspection library into your project.
- Mark off various object methods and properties with attributes or annotations.
- Let the introspection library do the magic.
In other words, if you don't ever need to interface with FP, you don't have to take Rich Hickey's advice.
Last, but not the least (nor the prettiest), although using
String as property key makes the most straightforward sense, you don't have to use
Strings. Many legacy systems, including Android™, uses integer IDs extensively through the entire framework to refer to classes, properties, resources, etc.
Android is a trademark of Google Inc.
You can also make both worlds happy.
For the Java world, implement the getters and setters as usual.
For the FP world, implement the
Object getPropertyByName(String name)
void setPropertyByName(String name, Object value) throws IllegalPropertyChangeException
Class<?> getPropertyValueClass(String name)
Inside these function, yes, ugly code, but there are IDE plugins that will fill that up for you, using... uh, a smart plugin that reads your code.
The Java side of things will be just as performant as usual. They'll never use that ugly part of the code. You might even want to hide it from Javadoc.
The FP side of the world can write whatever "leet" code they want, and they typically don't yell at you about the code being slow.
In general, using a map (property bag) in place of object is commonplace in software development. It is not unique to functional programming or any particular types of languages. It may not be an idiomatic approach for any given language, but there are situations which calls for it.
In particular, serialization/deserialization often requires a similar technique.
Just some general thoughts regarding "map as object".
- You still have to provide a function for validating such a "map as object". The difference is that "map as object" allows for more flexible (less restrictive) validation criteria.
- You can easily add addition fields to the "map as object".
- To provide a specification of the minimum requirement of a valid object, you will need to:
- List the "minimally required" set of keys expected in the map
- For each key whose value needs to be validated, provide a value validation function
- If there are validation rules that need to check multiple key values, provide that as well.
- What's the benefit? Providing the specification this way is introspective: you can write a program to query the minimally required set of keys, and to obtain the validation function for each key.
- In OOP, all of these are rolled up into a black box, in the name of "encapsulation". In place of machine-readable validation logic, the caller can only read human-readable "API documentation" (if fortunately it exists).