LuceeLang: How Compatible With CFML Should It Be?

Andrew Koenig (long time C++ Standard contributor, author, and former AT&T Research Fellow) is famous for describing C++ as being “as close as possible to C – but no closer” (see https://isocpp.org/files/papers/N0007.pdf). C++ was designed from the outset to be both a “Better C” and a migration path for C programs, and so it was important that (most) C programs ran (pretty much) unchanged under a C++ compiler. That document lists a number of deliberate incompatibilities and most of them are really fairly minor. One of C++'s long standing incompatibilities with C was eliminated when the C Standards committee voted to change the behavior of "default int" in declarations to match C++, thus bringing C in line with C++, rather than the other way around.

This approach to language design can also be seen in Groovy, which consciously decided that (almost) every valid Java program should be a valid Groovy program: just change the file extension from .java to .groovy and off you go! Groovy made a lot of Java syntax optional (including the type system) and treated several Java constructs as no-operations (e.g., fields and methods declared private in Groovy are still public). Groovy also added language features, so most idiomatic Groovy code looks like stripped down Java code with more expressiveness, as Groovy developers just omit elements of syntax they don’t need.

On the other hand, when Java itself was designed, although C++ was an inspiration, no compatibility was assumed: Java was to be a strictly “better” language than C++. The same happened with C#, when Microsoft had already taken Java and evolved it into J#, they decided a new language would be “better” and C# was designed without any real attempt at compatibility. Scala, in its own way, is a “better Java” only in the sense that it is a more powerful, more modern language that builds on the good things in Java but drops a lot of the bad things. In all three cases, there is no anticipated need nor expectation that the earlier language, the inspiration, should be runnable under the new language’s compiler. Other “inspired by Java” languages that are completely incompatible include Ceylon and Kotlin. Go and Rust were both “inspired by C++” (and both intended to be a replacement for it), yet they are both very different and neither are in any way source compatible with C++.

That’s not to say there’s no interoperability: C and C++ can happily call back and forth between each other at the native API level, along with Go and Rust. Java, Groovy, and Scala can all leverage each others’ libraries. Mixed language systems are increasingly the norm these days. Indeed, even wildly different languages such as C# and F# can be perfectly interoperable (and on the JVM, we have Clojure and “everything else”).

So what about LuceeLang? How compatible should it be with CFML? The Manifesto – http://lang.lucee.org/t/lucee-manifesto/183 – has this to say (my emphasis):

Lucee Language has its roots in the ColdFusion Markup Language (CFML) but Lucee Language is not CFML.

LuceeLang is intended to be modern, yet familiar, and to “grow in a more ambitious direction”.

Where possible lucee language should facilitate the transition of developers from CFML to Lucee Language.

LuceeLang is specifically designed to be interoperable with CFML, including CFML templates and creating instances of CFCs for example, and CFML developers should be able to quickly get up to speed with LuceeLang. Note that the Manifesto talks about the transition of developers, not programs. LuceeLang’s approach to tags is different: <cfwhatever> becomes <:whatever> so you cannot just change your .cfm file extension to .lucee and expect to run your code. At best you might be able to effect a mechanical translation, perhaps followed by some manual editing. What about changing .cfc to .lucee for all-script CFCs? I think this might be a more feasible change but even there some fundamental decisions need to be made about what’s available in LuceeLang, even if the syntax itself is almost the same.

The first question that needs to be answered is whether there really is an expectation that some subset of (mechnically transformed) CFML code should run otherwise unchanged as LuceeLang code, or whether the expectation is that in a CFML / LuceeLang project new files would be written with .lucee extensions (and therefore in LuceeLang) and perhaps pieces of legacy code ported over to LuceeLang over time as the project grows?

The second question is whether “all” of CFML’s top-level function-based library should be available directly in LuceeLang, or whether the “cruft” should be removed, or whether LuceeLang should go further and eliminate all those top-level functions in favor of member functions and, perhaps, a set of static class-based methods. Remember, this is a question of language design rather than one of theoretical performance. Folks who are concerned solely or primarily about performance tend to stay with languages that have less abstraction and that are “closer to the metal”. This is a question which needs to be answered on the basis of what makes a “better” programming language? Generally, history has shown that increasing abstraction and improving consistency are “better”.

CFML’s script subset is “close to JavaScript” by design – so it is easy to switch between those languages when working in a polyglot full stack environment. LuceeLang should keep that design goal (and, if anything, should move closer to JavaScript syntax for consistency).

CFML as it stands today is quite a sophisticated language but it also has a lot of strange semantics (behavior) and some definite syntactic warts. LuceeLang is committed to being a tag + script language in the same vein, but “better”. We need to decide how much of CFML we’re willing to simply “leave out” and how much we’re willing to “replace with (better) alternatives”. We should be guided by the Manifesto:

Lucee language is a modern alternative

LuceeLang does not have to be a superset of CFML. In my opinion, it should not be.

3 Likes

Thank you for such a thoughtful response. It is most definitely in the spirit of the original thinking behind the Lucee Manifesto. I agree wholeheartedly with the areas you emphasise and the inferences you make.

There should be no expectation that CFML would run within .lucee files.

Developers who want to use CFML can use CFML through the compatibility layer, or through interoperability options like <:include ... > or calling components.

A .lucee file should only run the Lucee Language.

This is certainly a lot harder to answer :wink:

On the one hand, top-level functions are a distinctive part of CFML development, and to remove them would certainly make Lucee Language less familiar to CFML developers.

On the other hand, top-level functions are a distinctive part of CFML development, and to remove them in favour of member functions would certainly make Lucee Language a less obtuse language and potentially more appealing to developers in general.

It’s hoped that the TAG will help us find our way.

I would have no expectations that .lucee is compatible with CFML.

As I understanding, Lucee Server will still support cfm/cfc. If that is the case, people would just use these file extensions, and migrate to .lucee at their leisure.

Fully agree. LuceeLang is a new language and it might have certain similarities and ideas from CFML, but no one should assume it’s backwards compatible to CFML and old code will run without changes.

Isn’t this second question @seancorfield raised really what we’re discussing here:

http://lang.lucee.org/t/luceelang-what-kind-of-language-should-it-be/229 ?

Or alternatively, I think the design/style of LuceeLangs function library should probably rather be discussed in the context of the overall language/change paradigm.