Add optional abort Attribute to cfinclude

I wanted to propose an optional attribute, abort, to the cfinclude tag, which will work similarly to abort in cfdump.

many times I find myself doing something like:

<cfinclude template="/sometemplate.cfml">
<cfabort>

the proposed syntax will get Lucee to abort the execution as soon as the code returns from the cfinclude tag, and it will look like this:

<cfinclude template="/sometemplate.cfml" abort="true">

what do you guys think?

1 Like

A piece of functionality should do one thing (preferably with its name describing that functionality).

In the case of include, it should… include.

If you need to add an and into the name of the functionality to describe what it does… it’s doing too much.

If you need to include/abort a lot (*), can I suggest you set up a macro in your IDE/test editor to do so. There’s no need to clutter the language to accommodate seemingly edge-cases like this.

I also think “needing to abort after an operation is performed” can be extended out to pretty much any operation, so it doesn’t make much sense to me to add it specifically to include.


Adam

(*) I don’t recall ever needing to do this. I’m sure I have, but with no sort of frequency. Certainly not enough to think it might be a good thing to roll into the language.

2 Likes

Hmm… interesting. Never knew you could do <cfdump abort="true"> (since CF9 to boot).

<cfdump  
    var = "#variable#"
    output = "browser|console|file"
    format = "text|html"
    abort = "true|false"
    label = "text"
    metainfo = "yes|no"
    top = "number of rows|number of levels"
    show = "columns|keys"
    hide = "columns|keys"
    keys = "number of keys to display for structures"
    expand = "yes|no" 
    showUDFs = "yes|no">

I can see that it would be useful in code bases where a lot of code is broken out with includes.

In a practical sense it seems easier to “cut and paste” or “hot key” in a cfabort beneath a cfinclude than to change the abort attribute. And I can’t think of a scenario where I’d be populating the abort attribute with a variable.

While I’d argue that its appropriate in cfdump as its a tool for debugging, I’m not convinced its appropriate in cfinclude.

While I’d argue that its appropriate in cfdump as its a tool for debugging, I’m not convinced its appropriate in cfinclude

many times you want to pass the code to another template and not continue with execution of the current one, e.g. when you validate parameters:

<cfcode goes here>
<cfif (!isValid)>
  <cfinclude template="/invalid_parameters.cfml" abort="true>
</cfif>

<cfcode of template continues here>

Hmm… interesting. Never knew you could do <cfdump abort=“true”> (since CF9 to boot).

yes, they added it after they saw it in Railo

Fully agree with @adam_cameron - this should NOT be implemented at all.

Edit: I’d actually even argue that cfdump shouldn’t have an abort attribute, but I can see why that’s useful given the lack of proper debugging tooling in CFML.

1 Like

From an architectual standpoint I have to agree with Kai and Adam, I never like tags/functions that mix in of unrelated functionality. Like:

  • cfdump-abort
  • cferror-mail
  • createObject

I added the attribute “abort” only under protest. But today I’m using it all the time, simply because it is faster to write

<cfdump eval=whatever abort> 

than

<cfdump var="#whatever#"><cfabort>

So from an architectual standpoint clearly no, but from a pragmatic one I’m undecided.

right. I was going for pragmatic.

there are many use cases for this, e.g. a template that requires a user login can check if the user is logged in, and if not include the login form and abort, or a wizard controller template that would include different “step” template and stop execution once the correct step is included.

sure, there are many ways to do those things. this will just make it a tad easier, and it makes a lot of sense IMO.

makes since because it is a quick use debugging tool. It is not meant to be left in the code past development. is not a debugging tool and should not have an abort attribute. I would say you should review your coding practices if you need to abort after a cfinclude.

Personally I think cfinclude is a bad practice in most cases, in that variables should never appear out of no where. The bad code I have seen over the last 15 years is mainly due to poor uses of cfinclude. Use a component and functions.

Andrew Penhorwood

1 Like

You were going for pragmatic for a use case that promotes bad practice in the majority of cases.

There are a lot of “pragmatic” things a language could do, but the sum of those will inevitably lead to the mess CFML is right now.

Surely could do with an email attribute to email yourself dumps for debugging. Even though I have to do that sometimes because no CFML servers currently offer proper and working well way of breakpoint debugging, I’d say adding this to the language would be one of the worst things to do.

In those cases: use the appropriate separate tags/functions and if one doesn’t want to type them: IDE snippet/template.

2 Likes

First of all, this falls into the category of something along the lines of:

function getUltimateAnswer(isCalculated) {
    if (!isCalculated) return "come back in 7 million years";
    return 42;
}

// vs

function getUltimateAnswer(isCalculated) {
    var result = "";
    if (!isCalculated) 
        result = "come back in 7 million years";
    else
        result = 42;

    return result;
}

I had a professor that would fail an assignment if there was a function with two return statements as in the first example. Now, I write code that does this on occasion, as it is quicker to implement. However, on a whole, I do strive to stick with the conditional logic with a single exit point.

Thats what I see is going on here. You may be doing maintenance on a some rather large and otherwise complicated templates, to where adding a else block around the remaining body of the template is not feasible. While sometimes necessary, using aborts as a normal way to end a request is, IMO, bad practice. It should be treated more like exit(1) for C programs. You should really only do it if there is a problem that you need to quit immediately before circuits get fried (well, maybe not that dramatic ;)).

However, that does lead me to an interesting thought that I shall bring up as a new thread…

if I had lived in the theoretical world like your professor then I may have done it the second way as well.

but for all intents and purposes, the first way is much more performant than the second one, and I always opt for the side of performance with all other factors being equal.

yes! (and some more characters to make the min 7 char mark)

Given that you can already exit on a template (as @21Solutions points out elsewhere) :

<cfexit method="ExitTemplate">

Are you actually advocating for something break related as opposed to debugging related, for example:

<:include template="/sometemplate.cfml" exit="true">
or
<:include template="/sometemplate.cfml" exit>

@dajester2013 raises this same concept here with some support, though I’m not sure why this finds favour whilst the notion of a breaking attrribute on <:include> does not:
http://lang.lucee.org/t/tag-to-cease-processing-the-current-template/134

Bear in mind that when you use abort, the code execution will never reach the OnRequestEnd() method.

Abort is a hard exit to stop execution of everything.

I think you’re spot on in your response to @modius. What Geoff is referring to here IS different because it exits a template and it doesn’t stop execution of everything.

Also: There is a conceptual difference.

@21Solutions problem CAN be solved with the existing language and using two separate tags for their respective purpose. Or if he’s too lazy to type it, use a Snippet. Under the premise that I (and others) think this coding style is not a good practice, I don’t think it should be made “acceptable” by a language shortcut.

From looking at the other discussion @modius linked, it looks like to me that the problem raised there can be efficiently solved with <cfexit>. SURELY the include tag could get an exit-attribute instead of @21Solutions suggest abort-attribute, but it kind of is the same situation from my point of view: meddling to things that should be separated into one tag just because we can.

And LuceeLang should not be about creating a new mess of “shortcuts” for a doubtful purpose - that’s a bad approach to language design.

If both of these are the same, but you can already do the first one without changing any of the engine code, then I’d be in favour of sticking with what we already have :smile:

<cfinclude template="/sometemplate.cfml">
<cfexit method="exittemplate">

vs

<cfinclude template="/sometemplate.cfml" exit="true">

(Same goes for “abort” or any other existing statement).

1 Like

sure Kai, I’m too lazy. that’s why I spent time posting this here instead of creating a simple custom tag that overrides the default behavior of the engine which would have taken a fraction of the time I spent on this here.

I think there’s a fundamental philosophical decision that LAS need to make about Lucee:

Is Lucee meant to be a language that enshrines best practices to appeal to a broader range of developers (i.e., outside the CFML pool), or is it meant to be “just CFML.Next” and carry over the sort of “quick’n’dirty” solutions that have given CFML such a bad reputation amongst so many non-CFML developers?

Many language design decisions cannot be made in a vacuum of just syntax and semantics. They need to be informed by the vision and mindset of the language philosophy. I think this is exactly one of those issues.

The “best practices” answer says: each tag should do one thing and do it well – don’t mix in unrelated functionality.

The “quick’n’dirty” answer says: sure, add exit="true" – but add it to every tag that could conceivably need to be the last executed one in a file.

1 Like

Calm down, Igal. No one said you’re lazy. I said that if you’re too lazy to type it (=the additional abort tag as it was clear from the context) then use a snippet.

Extending the “quick’n’dirty” thinking further could take you into Ruby territory with conditional execution:

<:include template="/path/to/file.lucee" exit="true" if="!isValid">

Ruby allows you to suffix any statement with if condition or unless condition and that’s really only a “small” extension to @21Solutions suggestion…?