tracker issue : CF-3648781

select a category, or use search below
(searches all categories and all time range)
Title:

Closures cannot be declared outside of cfscript

| View in Tracker

Status/Resolution/Reason: Closed/Fixed/Fixed

Reporter/Name(from Bugbase): Luis Majano / Luis Majano (Luis Majano)

Created: 10/10/2013

Components: Language, Closures

Versions: 10.0

Failure Type: Enhancement Request

Found In Build/Fixed In Build: Final / CF13 Final

Priority/Frequency: Trivial / All users will encounter

Locale/System: English / Platforms All

Vote Count: 12

Problem Description:

I found this shocking that I could not declare closures outside of cfscript or script only components. I find this a typical half way there in the language. Why can't I declare a closure using cfset???

What If I am in tags and need to pass in a closure to some CFC or native coldfusion function. I can't! This really needs to be addressed.

Steps to Reproduce:
{code:java}<cfset c = function()
{ return true;}>
{code}
{code:java}
<cffunction name="Foo" returntype="function">
<cfargument name="arg1" required="false" default="foo" type="string">
<cffunction name="Bar" returntype="string">
<cfargument name="arg2" required="false" default="bar" type="string">
<cfreturn arguments.arg1 & " " & arguments.arg2 />
</cffunction> 
<cfreturn Bar />
</cffunction>
<cfset foo = Foo("foo") />
<cfset foobar = foo("bar") />
{code}
Declaring any closure in any non-cfscript context.

Actual Result:

Expected Result:

Any Workarounds:

----------------------------- Additional Watson Details -----------------------------

Watson Bug ID: 3648781

External Customer Info:
 External Company: 
 External Customer Name: LuisMajano
 External Customer Email: 
 External Test Config: My Hardware and Environment details:

Attachments:

Comments:

Agree, and have mentioned this to them before. Railo has no problem with this. +1 -- Adam
Vote by External U.
14274 | October 11, 2013 02:40:55 AM GMT
I've run into this recently too. This should be added.
Vote by External U.
14275 | October 12, 2013 05:46:55 AM GMT
Currently not supported.Passing bug to internal bug for review (Comment added from ex-user id:vnigam)
Comment by Adobe D.
14228 | December 17, 2013 07:23:51 AM GMT
Wow, this is surprising. This sort of thing needs to just work no matter where you arein the language.
Vote by External U.
14276 | December 17, 2013 11:35:22 AM GMT
++1 This should be available on both ends of code format.
Vote by External U.
14277 | December 17, 2013 02:58:04 PM GMT
It is not about half implementation at all. Outside cfscript, functions are declared using cffunction tag. Now how do you define the closures in tag syntax? The only way to do that would be using an ugly mix of script and tag which would look like <cfset c = function(){ var a = something; var b = foo(); return a * b; }> To me, this syntax looks confusing. Given that more and more new code is being written in cfscript, I feel we should not mix script and tags in this way. Deferring it for the time being and we will revisit this later.
Comment by Rupesh K.
14229 | January 02, 2014 01:32:55 AM GMT
It's just an expression like any other sort of expression, Rupesh. You can't say "oh, this sort of expression is OK in a CFSET statement, but this other sort of expression? No, can't do one of those". That's ridiculous. By way of comparison, this already works fine in Railo. But then again they're not quite so judgemental/patronising as to what will / won't look "too complicated" for CFML developers. I think if it looks complicated *to you*, you probably should not be making decisions as to what does and does not go into the language. -- Adam
Comment by External U.
14230 | January 02, 2014 05:31:16 AM GMT
@Adam, of course it is an expression but with closures, things become different. There is no other language construct where an expression body has statements. The Closure body will have statements. Now should those statements be written using the tag syntax or script syntax? Is it ok to have the Closure body always in the script syntax and only allow declaring the Closure in tag? One can argue that since he/she is not inside cfscript and he/she should be writing the statements in the tag syntax using cfset. Considering these things, we had decided to have Closures only in script. Closure in tag, if really required, needs to be thought out properly. p.s : I would really appreciate if you can tone down your aggressive stance, avoid any personal attacks and focus on having a meaningful discussion.
Comment by Rupesh K.
14231 | January 02, 2014 06:48:33 AM GMT
Yeah, obviously (?) the expression can only be expressed in non-tag syntax. That's a bit of a no-brainer. As I referred you to previously, Railo have already implemented this, so you can simply use them as the reference implementation. Their implementation works, and makes sense. However if you are specifically speaking of functions using closure, then there's no reason a function using <cffunction> cannot be compiled to leverage closure, just with an attribute flagging as such. However I think you're actually only referring to function expressions? <Removed> -- Adam
Comment by External U.
14232 | January 02, 2014 07:11:05 AM GMT
@Adam, I have removed the last personal comments and unfortunately I will have to report this.
Comment by Rupesh K.
14233 | January 02, 2014 08:11:25 AM GMT
<removed> Back on topic though: let me "conjecturise" a bit. Talking to a former Adobe (well: Macromedia) employee... is it a case here that the main blocker is not the explanation you offered (which is, as I noted, a weak, patronising and dismissive one), and as much that the ColdFusion code parser is split into two different "systems": one for tags and one for script, so compiling a statement that has elements from both the tag lexicon and the script lexicon will require not insubstantial re-engineering on your part? And Railo doesn't suffer from this as they approach code compiling differently (probably due to recognising CFScript as a first class citizen early in the piece)? If so... entirely fair enough that this gets sidelined for the time being. I do believe it should have been dealt with properly in CF10 (this was first raised during CF10 development, remember), when the situation arose, but - so be it, "we are where we are". Does the way the parsers work completely negate this sort of thing without a major overhaul, or is it just too much to take on at this late stage? Like I said: this is just speculation on my part, so could be completely wide of the mark. -- Adam
Comment by External U.
14234 | January 02, 2014 08:42:13 AM GMT
I did not talk about any blocker so far. I am questioning whether this syntax can cause confusion and whether this is really required given that more and more code is being written in script only. Yes, the CFML parser does run in two modes - one for tag and another one for cfscript. Supporting this would definitely require a change in the parser but I will have check with the engineers to find out how big a change would that be.
Comment by Rupesh K.
14235 | January 02, 2014 09:11:28 AM GMT
We're not idiots, Rupesh. Can you please stop treating us like so. This is what I find so grating in the way you communicate here. Beginner CFMLers - the ones who could conceivably get "confused" by all this - are probably not going to be even writing functions, let along function expressions, let along knowing what a closure is. The people who are having this discussion know what they're doing, and know what they're talking about. And even then... it's not for you to second-guess this sort of thing. You're not even a CF developer (I don't mean that disrespectfully... you're just *not* a CF dev!), so how the heck would you *know* what's confusing or otherwise for CFers? And if people *can* get confused by something in the language, then they can just *learn*. I get them impression you feel you're a lofty Java developer and we're meagre CF developers. But we're not all stupid mate. Stop treating us that way. In short, I think I can speak for anyone who's interested in this topic: no, the mix of syntax is not confusing. If that's your reason for not implementing this, then it's not a valid reason, IMO. Cheers for sticking with this line of discussion. -- Adam
Comment by External U.
14236 | January 02, 2014 09:36:06 AM GMT
From my perspective, I am used to passing arguments into a method call the same way in script as I would to a method call in tags. Therefore, I would expect for closures to be consistent with that precedent. To give a real-world example, we've been embracing closures in our ColdBox tools to give developers more powerful and expressive ways of controlling execution of libraries. One example is where users of TestBox can provide a closure to filter what tests suites get executed. As most test runners output HTML, this will often times happen in a .cfm file in the context of tags like so: <cfset r = new coldbox.system.testing.TestBox( directory={ mapping="coldbox.testing.cases.testing.specs", recurse=true, filter=function(path){ return ( findNoCase( "test", arguments.path ) ? true : false ); }}) > <cfoutput>#r.run()#</cfoutput> (Example taken from the docs here: http://wiki.coldbox.org/wiki/TestBox-BDD-Primer.cfm#Directory_Runner) I find that reasonably readable and not too different to the eyes than struct or array literals. As you pointed out, a closure is an executable not a literal, but anyone using jQuery these days should be pretty familiar with the concept of passing in an executable function as a parameter. Thanks for your considerations on this.
Comment by External U.
14237 | January 02, 2014 10:49:54 AM GMT
I discovered this didn't work on ColdFusion when I watched someone try to port some code from Railo - where this works just fine - to ColdFusion, and they were very confused by the fact that ColdFusion only supports function expressions in cfscript, not as parts of expressions in tag-based code. *That* is what is confusing - the inconsistency.
Comment by External U.
14238 | January 02, 2014 08:03:54 PM GMT
This is inconsistent: a function expression should be treated the same, regardless of whether it appears in tag-based code or script-based code.
Vote by External U.
14278 | January 02, 2014 08:04:43 PM GMT
It is also not possible to have a argument's default value defined as a closure. function test2(closure1=function(a){ return a+1;}){ return arguments.closure1(4); } You can't define them in cfreturn either. I made a gist that has the different ways a closure can be used currently in the other CFML engine - https://gist.github.com/brucekirkpatrick/8231961
Comment by External U.
14239 | January 02, 2014 10:11:09 PM GMT
Function type as a value should work consistently through the language, including tags.
Vote by External U.
14279 | January 02, 2014 10:15:14 PM GMT
Bruce, *any* tag that can take an expression can, obviously, also take a function expression. For example: <cfparam> <cfthread> <cfmodule> [custom tag calls] <cfinvoke> <cfinvokeargument> <cfobject> [possibly more... the point being, there are quite a few that need consideration] The job needs to be done *properly*. -- Adam
Comment by External U.
14240 | January 03, 2014 05:06:43 AM GMT
Just FYI, so community input on this: http://cfmlblog.adamcameron.me/2014/01/results-of-survey-about-function.html -- Adam
Comment by External U.
14241 | January 07, 2014 03:31:19 AM GMT
This makes sense, I think it should be added
Vote by External U.
14280 | January 07, 2014 05:50:40 PM GMT
Thank you everyone for pitching in. It definitely makes sense and we should fix it. We investigated this and it does require a fundamental change in the parser as Sean already pointed out. Deferring it to the next release.
Comment by Rupesh K.
14242 | January 28, 2014 02:29:11 AM GMT
Right. So now that you have CF11 out the door and you'll be working on CF12, can we have this re-opened & queued up for CF12, pls? -- Adam
Comment by External U.
14243 | July 19, 2014 10:13:51 AM GMT
I was just surprsied to discover that <cfset e=arrayReduce(someArray,function(result,item,index,ar){return index;})/> doesn't work. It would be nice if it did because then converting arrays of structs (i.e. in model's) to strings in a view would be super easy.
Vote by External U.
14281 | January 16, 2015 09:22:27 AM GMT
HELLO?
Comment by External U.
14244 | September 09, 2015 09:27:27 AM GMT
+1 ......................
Vote by External U.
14282 | September 09, 2015 03:12:26 PM GMT
@Adam, I am not sure what information you are waiting for? It is already opened as "ToFix" and targeted for 12.0.
Comment by Rupesh K.
14245 | September 09, 2015 09:50:40 PM GMT
You dodgy dodgy geezer Rupesh. That was *not* the status of this ticket yesterday when I made the comment. Is this the way you operate, sunshine? Duly noted.
Comment by External U.
14246 | September 10, 2015 12:17:42 AM GMT
Wow, yeah, I'm with Adam. I checked this ticket when he commented yesterday and it was not marked "ToFix" then. I'm glad you're going to fix this issue but don't play us. At least have the decency to admit you've changed your mind.
Comment by External U.
14247 | September 10, 2015 01:00:41 AM GMT
Knowing Adam, I can't expect anything better from him. But I expected better from you Sean as I have respect for you. The bug was marked for 'ToFix' on Aug 4, 2014 and the audit trail shows that. https://picasaweb.google.com/lh/photo/iEol1JIDV-x1IJj2Vl2-d27qqJzRyYZIsVXUyNcYV90?feat=directlink Extremely disappointed.
Comment by Rupesh K.
14248 | September 10, 2015 12:33:24 PM GMT
Very strange. That both of us were convinced it was still marked Deferred early on the 9th. Could you show us the full audit trail extending right the way up to today please?
Comment by External U.
14249 | September 10, 2015 12:48:38 PM GMT
The audit trail is quite long and the snapshot shows the trail from the date it was re-opened till today.
Comment by Rupesh K.
14250 | September 10, 2015 12:56:42 PM GMT
Oh, it's in _reverse_ order... I see now... well then I must apologize. I really was convinced it had said Deferred, which is why I responded after Adam's comment. We've gotten very used to having to really harass the CF team at times to get old tickets looked at again... :) May I suggest, when you change the status of a ticket to ToFix, you also add a Note on the ticket to clarify your plans? After all the back and forth in early January 2014, then nothing until Adam asked for a status update in July 2014, and then _still_ nothing until he poked again yesterday... Responding to Adam's July 2014 note would have prevented all this.
Comment by External U.
14251 | September 10, 2015 01:04:06 PM GMT
It was marked as closed/deferred both y/day. I don't know what Rupesh is showing us. Perhaps the bug tracker's logging is as flaky as the rest of it?
Comment by External U.
14252 | September 10, 2015 01:11:32 PM GMT
(oops extraneous "both" in that last comment).
Comment by External U.
14253 | September 10, 2015 01:12:17 PM GMT
Adam, will you stop it now? Instead of accepting and apologizing, you are blaming the audit trail also. Shame on you Adam!
Comment by Rupesh K.
14254 | September 10, 2015 01:15:55 PM GMT
@Sean, yes, a comment would have helped. But anyway the damage has been done.
Comment by Rupesh K.
14255 | September 10, 2015 01:37:42 PM GMT
Google Cache from 6th August 2015 - Status Open/ToFix: https://webcache.googleusercontent.com/search?q=cache:https%3A%2F%2Fbugbase.adobe.com%2Findex.cfm%3Fevent%3Dbug%26id%3DCF-3648781 So either Google has a grudge against Adam/Sean and fabricated the above, both Adam & Sean were seeing things, or this flaky piece of shit issue tracker is itself so buggy it was showing an old/cached status, and is long overdue being ditched and replaced with *any* other software.
Comment by External U.
14256 | September 10, 2015 03:43:02 PM GMT
"Google has a grudge against Adam/Sean" -- whilst that may or may not be true :) I've accepted that I was mistaken about the status of this ticket (I'd been looking at several old tickets recently that the community has been pushing to get attention), and apologized. There are certainly many things that could be done to improve the bug tracker. Automatically adding a Note when there's any status changes, for example, color coding things (green for open, red for closed -- like GitHub), exposing more history on a bug, providing better custom reporting. The list goes on. My understanding is the bug tracker is maintained by a group other than the CF team? In which case, we can't blame them for shortcomings in the bug tracker (it sure would be nice to have more direct access that bug tracker team tho'! :)
Comment by External U.
14257 | September 10, 2015 05:18:14 PM GMT
Well I can't dispute that evidence. I was clearly (and bemusingly) wrong about all this. http://blog.adamcameron.me/2015/09/wrong.html Cheers for calling me out on this one, Peter. And sorry for me calling you out, Rupesh.
Comment by External U.
14258 | September 11, 2015 12:25:50 AM GMT
Hi all, I've filed Bug Tracker ER CF-3648781 (Display audit trail on tickets). Hopefully that would help. Thanks!, -Aaron
Comment by External U.
14259 | September 11, 2015 01:32:51 PM GMT
4054727 is the correct ticket#
Comment by External U.
14260 | September 11, 2015 01:39:16 PM GMT
Glad that it is all clear now. @Adam apologies accepted.
Comment by Rupesh K.
14261 | September 14, 2015 06:32:53 AM GMT
So, Rupesh, to confirm we can expect to see this in ColdFusion 2016 right?
Comment by External U.
14262 | December 22, 2015 12:59:53 PM GMT
Rupesh, I asked you a question in December. Do you think you could please have the professionalism to actually reply? I'm escalating this to Anit.
Comment by External U.
14263 | February 22, 2016 06:09:07 PM GMT
Updating this bug to reflect internal note that this is targeted for Aether (CF 13) at this time. More information to be posted soon...
Comment by Elishia D.
14264 | February 22, 2016 06:41:59 PM GMT
Closure is script like syntax which would get messy and will not look good with most of the CF tags. Closure definition might look clean in Cfset, but when used as attribute value within other CF tags, the closure code may get messed up. And we believe that people are moving away from tag to script. We will try to work on the solution and will update you guys soon.
Comment by Awdhesh K.
14265 | February 23, 2016 01:02:32 AM GMT
"what the code looks like" is really none of your concern, Awdhesh, But thanks for the update.
Comment by External U.
14266 | February 23, 2016 01:07:24 AM GMT
Adam's right: this has nothing to do with how the code _looks_ -- this is about (yet another) incompletely implemented feature. CFML expressions should allow for closures everywhere, since they are "just part of the language". You folks seem to have no clue about consistent language design. It's really frustrating for the users of your product -- who program in CFML day-in, day-out, whereas you do not. That closures can't be used in expressions in tag-based code is an arbitrary restriction because you didn't think things through properly. Lucee got this right: closures are just part of the language and can be used in any expression, regardless of whether that expression is in cfscript or tag-based code.
Comment by External U.
14267 | February 23, 2016 01:19:13 AM GMT
Indeed Sean. An expression is an expression, and a function expression is no different from any other sort. They should be usable in any code which takes an expression.
Comment by External U.
14268 | February 23, 2016 01:39:21 AM GMT
Sean and Adam thanks for your input. Will revert back to you on this shortly.
Comment by Awdhesh K.
14269 | February 23, 2016 08:21:02 AM GMT
Cheers fella.
Comment by External U.
14270 | February 23, 2016 08:24:43 AM GMT
Tag based closures please: <cffunction name="Foo" returntype="function"> <cfargument name="arg1" required="false" default="foo" type="string"> <cffunction name="Bar" returntype="string"> <cfargument name="arg2" required="false" default="bar" type="string"> <cfreturn arguments.arg1 & " " & arguments.arg2 /> </cffunction> <cfreturn Bar /> </cffunction> <cfset foo = Foo("foo") /> <cfset foobar = foo("bar") />
Comment by External U.
14271 | May 12, 2016 04:45:59 PM GMT
If you are worried about the syntax style issue of mixing tag based & script based CF, my example below, is a pure tag based solution for creating a closure. Based on JavaScript methodology. No excuses now.
Comment by External U.
14272 | May 13, 2016 01:38:28 PM GMT
The important point is not to call the child function, but to return a reference to it. So that the child function itself and not its result is returned, when it is executed.
Comment by External U.
14273 | May 13, 2016 01:44:16 PM GMT
+1
Vote by Abram A.
14283 | January 31, 2017 06:01:43 PM GMT