Monday 14 December 2015

ColdFusion: more on this encodeForHtml() crap

G'day:
This is a follow-up to last week's ColdFusion: please help me discourage Adobe from releasing bad code article; my inspiration drawing from Brad and Sean's comment on same. I found myself writing too much in reply, so have extracted it into an article instead.

First Brad:
[...] the word "encode" is noise in the method if the class is already called "Encode". I kind of like "Encode.forHTML()" to cut down on verboseness. I'm not too much of a fan of Ruby's uber-succinct shortcuts [methods like to_s() instead of toString() ] but I think there's something to be said for trimming down on unnecessary fluff typing.
I initially started with the same thought (see my comment on the ticket):
So they should be in something like:

String Encode.forHtml(String stringToEncode)
Sorry, was being hasty before. That class / method name example I gave was rubbish: Encode is a verb, so makes no sense as a class name; and the method suggestion had similar grammatical shortcomings. Something more like Encoder or StringEncoder or something for the class, and the methods themselves should be the same as their procedural counterparts, so:

static String StringEncoder.encodeForHtml(String stringToEncode)
The name of the method needs to stand on its own two feet (methods have two feet, just like you and I, apparently ;-). "forHtml()" does not adequately describe what the method does. This is a bit semantic given it'll generally be referenced in context with its class, but I still think a method name should describe what it does. "forHtml()" sounds like one is coming in half-way through the description.

Of course at that point, the only difference (to the average programmer) between

Encode.forHTML()

and

EncodeForHTML()

is one character and I think the latter is easier to remember and easier to type since it reads the same but isn't peppered with punctuation.
Well I'd be advocating StringEncode.encodeForHtml(), so that makes even more typing still. I think an appropriate level of brevity is a factor in language design, but not the chief one. And I programming is not an exercise in typing: it's an exercise in thinking. I am perpetually bemused by these people who think programming is some sort of typing race. In the bigger scheme of things, typing a few extra characters each time one wants to encode something? So what?

Also in equivocating over Encode.forHTML() and EncodeForHTML() you're arguing a case for something I'm not contesting. Or even talking about. This conversation is not about whether we should have a headless function or an OO method: that horse has already bolted.

I'm kind of torn here, because I like the highly-academic idea that a language does things "properly" and according to best practices (or at least the precedent set by other languages at the time) but I also like the idea that CF (and many other dynamic, loosely typed languages) bend rules here and there with an end result of making things as simple and easy for the developer as possible in order to get code out quickly and efficiently. (Push complexity on the compiler, not the programmer) At the end of the day, I'm not quite sure what real-world difference there is between a collection of related functions that differentiate themselves by starting with "Encode." and a collection of related functions that differentiate themselves by starting with "Encode".
This is - again - misdirected equivocation. This is not part of the discussion. The ticket is specifically about the member-function implementation of the encoding functions.



I think, Brad, you're close to missing the point entirely. The conversation is about the member function implementation, and what's the best way to implement it. The consideration you should be engaging in is the difference between myString.encodeForHtml() (a member function of String) and StringEncoder.encodeForHtml() (not a member function of a heretofore not implemented StringEncoder class).

Furthermore there's a broader picture that I perhaps left slightly too implicit... the exercise is really one of responsible and intelligent stewardship of the CFML language in the context of its OO implementation. I'm repeating myself a bit here, but CFML started being OO back in 2002 with the addition of CFCs, but this was for dev-written code. No nod to actually making native CFML OO was made until ColdFusion 11, over a decade later. Well there was the crappy Query.cfc, Http.cfc script-"friendly" implementations that Adobe shipped with CF9 (?), but it's telling that those are CFCs, not native constructs.

But now Adobe are drip-feeding in their OO implementation of the rest of the historically procedural CFML. This is good news, but they need to do it properly. As I said in the other article, their approach here is too reminiscent of the generic CFScript solution they foisted upon us in ColdFusion 11. I recoiled in horror at the time, but sadly it was too late in the piece to get anything done about it: I quit the ColdFusion 11 pre release before this stuff was in the product. Oops. This is something the ColdFusion Team has recently conceded (I'll need to see if I can find the citation for that... it's eluding me just now).

This means we have to think about how things are implemented. Now I contend there's a difference between "a function which operates on a string" and "a member function of the String class". I don't think in other situations too many people would contest this, but for some reason people seem to have a mental block about this when it comes to CFML. This is a comment from the ticket in the bug base:

These are string functions. They should work like all the other string functions do
Sigh.

I guess it bears repeating: the String class should busy itself with functionality which focuses on the general notion of strings. There will be other more "fine-tuned" string processing requirements which don't belong in that class; they belong in a more purpose-built class. This is all I'm advocating.

What I don't understand is people are going "but it's not like this anywhere else in CFML". Well... a) yes it is. One already calls methods on an appropriate class (and appropriate class); b) even if it didn't, that's a bit brain-dead as this is the beginning of the exercise in doing the OO implementation of CFML. So, yes, there will be some new elements added to the corpus. This is self-evident, surely?

Sean had some stuff to say as well:

Imagine a CFML where there had never been top-level functions: instead everything was a member function on something.
I'm not sure there's a point in doing this, TBH, because it's not the reality we reside in, so any conclusion one might drawn from that particular fiction is not going to be relevant in this real world. But I'll play yer silly game, Sean:
In such a world, if encodeForHtml() etc had started life as member functions on strings, would you have campaigned to move them somewhere else? I suspect the answer is "no".
Well in this fictional world I'd be the captain of the All Blacks, as well as an all rounder in the NZ cricket team. Other than when I need to be in parliament fulfilling my role as Prime Minister. I mean f*** it... if we're making shit up, let's at least make it interesting ;-)

Being less obtuse, this is still a straw man argument anyhow. If CFML had always had String.encodeForHtml() would I be campaigning to change it now in ColdFusion 2016? No. Too late. If I was in the pre-release for ColdFusion 1.0, and if - for the purposes of this increasingly stupid role-playing exercise we're engaging in - I had the same knowledge then that I do now? Yes, I'd still be campaigning to have it implemented properly.

If I didn't have the knowledge then that I do now, then I probably would not have noticed: no. But... well... so what? That's not reality. And I'd like to think someone else with a clue would be around to make the observation for me. As for if a new language was being developed now, how would I be advocating this gets implemented? Well you're seeing it in action as we speak. This is it. Also we can reflect on .lucee and Iris before that: I was saying the same thing there. Not perhaps for this specific example (indeed I think I missed this with Iris & .lucee), but for other situations this is definitely the approach I've been advocating from the outset.

Your position only works, Sean, if we were discussing already-released work. We're not. This work has not been released, indeed it's only currently in (closed) beta. And I started this "campaign" as soon as the ticket got onto my radar, within a) two months of it being raised; b) before Adobe had said what they were going to be doing; c) probably before they started working on it.

In closing, I'll fall back to the point that the implementation of CFML in an OO fashion is a significant facet of CFML going forward, and it's bigger than this small part of the implementation. Adobe needs to think stuff through properly, and do the implementation in a thoughtful, informed, and technically robust fashion.

Now if someone can put forward a decent, this-reality-rooted, case for why these encoding functions ought to be in the String class, I'm all ears. But can we please stick to a) the topic under discussion; b) this reality.

I'm now off to my other new reality where I have some rugby balls to sign... ;-)

--
Adam