This is an adjunct to my “How Compatible With CFML Should It Be?” post – http://lang.lucee.org/t/luceelang-how-compatible-with-cfml-should-it-be/228 – and in this one I want to look more at the nature of what we want LuceeLang to be. I think this is much less contentious but I think it’s also something we need to clarify as an overarching design goal.
CFML started life simply as a way to get dynamic data into otherwise static HTML pages. It added tags with a specific prefix, which would be interpreted on the server to retrieve data from a database and perform other tasks, as part of generating the final HTML page that was delivered to the browser. It was very much a simple procedural language. It gained user-defined functions along the way, to help with code organization and provide a form of reuse, but it didn’t gain any form of component-based organization until the rewrite on top of Java with Macromedia’s CFMX 6.0 (an effort that had begun at Allaire prior to Macromedia’s acquisition of them). Even in CFMX, the language was not Object-Oriented, it merely had “components” as a way to organize libraries of functions. CFMX 6.1 made it possible to write OO-style code for the first time, but the language was still primarily procedural with some OOP “bolted on”. Claiming it was Object-Based was perhaps more accurate than Object-Oriented.
Many other languages of comparative age to CFML had evolved into much more capable OOP languages by this time – or had even started out life as fully OOP languages (e.g., Ruby). For good or bad, OOP became the way to write large systems by the early 2000’s and that trend continued on over the next decade. Many people in the CFML community petitioned Macromedia, then Adobe, and then Railo (and New Atlanta) – and now Lucee – to make CFML a more capable, more consistent OOP language. The performance aspects around creation of objects kept improving. The syntax for dealing with objects improved (
new, scripted-based components, using
var at the point of first use). We now have member functions on built-in object types (arrays, structs, queries, etc) and a more natural syntax for iterating over collection-like objects as well. We got interfaces. Some CFML engines support abstract classes, static methods, and so on. We even have ORM built-in.
It is no longer a particularly controversial position to argue that CFML is an OOP language. All the major frameworks and libraries are packaged as classes / objects and often the expectation is that your code extends classes provided by the framework or library. We have (to some extent) adopted a number of common OOP design patterns in the everyday code that most of us write. It took a long time to get here but we are now at a point where many CFML developers are questioning why new functionality is still introduced as top-level functions (or tags!) when member functions, or new system-wide classes with static methods, would seem like a more modern, more sensible approach.
What we decide we want LuceeLang to be – whether it be more procedural(!), more OOP, more FP, or more hybrid OOP/FP – should guide us in the way we approach language design decisions.
If we want more OOP, we should probably view all our top-level functions with suspicion. If we want more FP, we should look at ways to leverage closures more in our “standard library” – and we should look at how we can improve thread safety and simplify concurrent programming in LuceeLang, as those are the main forces driving the recent increase in adoption of the FP style.
A little history: FP is not new. It predated OOP. The early work on OOP was actually done on top of FP languages. The early OOP languages were message-based: you had coarse-grained objects that behaved as actors in your system and they sent messages to each other to effect change in the overall system. FP has continued to be studied and developed but has primarily remained an academic concern until the mid- to late-2000’s, as we started to hit the limits of current systems and needed ways to better leverage concurrency on multi-core machines. What we know as modern OOP, is not what the folks who first designed OOP systems had in mind! Modern OOP leans heavily on shared state, and that is what causes the problems with concurrency. FP favors immutable data with carefully encapsulated mutability where it is still needed: early OOP was similar, with immutable messages and very little shared data.