hey there is some daft Lucee "feature" that suppre...
# lucee
a
hey there is some daft Lucee "feature" that suppresses any/all buffered output in functions... and a setting to switch that off in Application.cfc? I've looked through the docs and jira and can't find it. Can anyone recall? Symptom: I have a writeDump/abort in some code and I'm getting the abort, but the dump ain't dumping.
It's this I think: https://docs.lucee.org/guides/Lucee5.3-kabang.html#unnecessary-buffering That gives me something to google on, anyhow...
m
There's a setting in the Output section of the admin
a
ah, yes! And the answer for doing it in code is:
Copy code
this.bufferOutput = true
Cheers Marc!
m
if this is unchecked, I think it can affect your cfdump outputs
a
yup. And it appears to be unchecked by default. So "should I do what you code actually asks, by default? NAH".
m
I rarely forget where this is because I've had so many violently frustrating moments when it was forgotten lol
a
How the fuck these decisions get made in Lucee is utterly perplexing. I suspect it involves a random number generator and too much weed.
(and actually... that would explain a lot)
anyway... rantyrantrant... thanks for yer help.
m
"well, you don't REALLY need that information you've coded up to dump, now DO YOU?!" =D
a
yeah I was just typing that code in for shits n giggles.
m
"See? We're helping you FOCUS."
a
anyway. My will to live has been completely eroded by the combo of Lucee and CFWheels in this current exercise I was trying to perform (which was largely pointless anyhow), so I'm gonna.... go do Friday evening stuff.
Have a good one man.
m
You too. I have a Lucee / CFWheels docker image used for a client, up and running under AWS fargate. Had a few little bugs here and there, mainly around the NGINX implementation and trying to get the CFWheels redirects/SEO stuff working, but overall it seems to be working now. In case you need help in that area.
a
Ha, actually I was just trying to replicate a coupla bugs I found in it the other day... but... we're on 1.4 and I was messing around with 2.2 just now and it's not at all doing what I'm expecting it to (but differently from 1.4), but... I don't think it's a good use of my time looking @ 2.2 as we will never be using it.
If I could come up with a repro case easily I was gonna raise an issue with them, but I can't so I won't.
m
well at least you know they behave differently. and it gives you a good excuse to truly indulge in the "Friday stuff." Just don't code and weed.
a
weed is not my particular peccadillo. But at any rate it'll just be beer for me this evening.
m
nice!
b
It is for this reason I have a permanent global env var in CommandBox called
Copy code
cfconfig_bufferTagBodyOutput=true
so all my local servers have that setting switched back on.
The setting was added in Lucee 5.2 but the default wasn't changed until 5.3 (as Lucee introduces breaking changes when incrementing their second version number, which they treat as "major").
It is done for performance. In a large tag-based app there is quite a lot of white space generated inside your UDFs, which is ultimately discarded if you have
output=false
. CF has always collected ALL output of UDFs regardless of their
output
setting just in case you decide to dump/abort from within the UDF. IMO it never should have worked in the first place, but ACF always did it historically and it was handy.
So starting with Lucee 5.3, the engine just straight up ignores all output from inside a UDF with
output=false
right out of the gate unless you flip the setting.
a
Also ignores it when
output=true
though.
And... you know what... it's up to me when I decide to output stuff. Not the app server. It's a poorly-thought-out setting.
Also... the overhead you describe is only symptomatic in tag-based code, so it's fuckin stupid to apply it to script-based code. Just... not thought through.
b
I don't think you're understanding what the setting does
When output=true, you should be able to output with no issue
a
yeah. I know.
b
Chances are your specific UDF has output=true but it is being called from within another method farther up the call stack with output=false
a
should be able to.
b
Every single method at play must have output=true in order for you to output anything
Unless, of course, you enable that setting and abort inside the method
So you still have full control
The Lucee setting controls whether Lucee secretly buffers the output behidn the scenes regardless of your UDF annotations
Which is what ACF always has done
a
Oh does that
this.bufferOutput
thing work in the immediate object as well? Not just an Application.cfc setting?
b
No, it's an app wide setting.
a
Sorry, misread/parsed this:
Unless, of course, you enable that setting and abort inside the method
b
The "rub" Lucee was addressing is even if you have this code
Copy code
function foo() output=false  {
  echo( 'bar' )
}
Then Lucee still buffers that text in memory (wasting heap space) even though you explici8tly told Lucee yuo didn't want to output anything
a
right so fix that
[shrug]
b
Just in case you randomly decided to do this one day
Copy code
function foo() output=false  {
  echo( 'bar' )
  abort;
}
and then demanded Lucee should have known that you still wanted to output that text even though you actually said you didn't
right so fix that
Fix what?? It's working as designed
a
yeah see coming at this cold, I'd be completely fine with that not output anything
b
By default in Lucee 5.3, Lucee obeys exactly what you tell it to do
a
I had output=true on the method...
b
And all methods up the entire chain of execution?
a
no
shouldn't need to.
b
There you go
Um, yes you do, lol
a
Well I know the way it's implemented I do.
b
The outer methods are responsible for capturing the output of the methods they call. That just makes plain sense
a
But the "closest" setting should trump upstream ones.
b
Copy code
function outer() output=false  {
  inner()
}

function inner() output=true {
  echo( 'Stuff and things' )
}

outer();
☝️ Even though
inner()
outputs text, it's still suppressed by
outer()
a
Yes, Brad. I understand.
b
If you used cfflush, I assume it would work. You're assuming your code flushes immediately to the top level of the page
a
It's perhaps best if you don't second guess what other ppl are thinking.
b
I don't think that's the issue. You're wanting to re-imagine how functions encapsulate calls to nested functions.
a
No, I'm thinking that if I have
Copy code
function inner() output=true {
then what I output in there should be added to the output buffer
b
And while you can make an argument for that, that's not nearly 'some daft Lucee "feature"', that's a basic tenant of functional programming.
a
Any output I add in
outer
? No. Any output added after the call to
inner
, in
outer
? Also no.
Hrm. Well I have yet to encounter a language that when I say "output this" it goes "nuh-uh"
b
My assumption has always been that each UDF has its own buffer that it hands to the calling function when its done so outer can do what it pleases with it. I haven't looked at the Lucee source to verify, but that's how I've always imagined it working
a
or when I say "add this to the output stream" if we're taking response content etc
Yeah I think what your assumption is is where I'm at.
b
Well, how else would tags like
cfsavecontent
work??
Copy code
savecontent variable="foo" {
  inner();
}
Oh, I'm sorry, you don't get any output because we already sent it to the page buffer?
Um, no, lol
output is passed "upstream" and the caller code gets to deal with it as a language design (from my understanding)
a
I guess perhaps
inner
, having been told to capture output, does so until it ends... and passes it back to [something]. that [something] might get discarded later (like if everything upstream is
output=false
.
However if there's an interruption in
inner
, the its buffer should be flushed according to its local setting
(sorry, multitasking slightly, so that might not be as clear as if I was focusing)
b
Yes, that is my understanding of how it works
a
yeah. And that was not what I was seeing.
b
But just to be clear, the original discussion of why lucee has this feature is still orthogonal to nested methods. The issue scenario could still exist in a single method as I showed above. The nested method discussion is more of a side quest here
a
until I put that application setting on... no output. Even with
output=true
on in the function I was aborting in.
oh yeah sure, I think the whole reason the functionality exists is also daft.
b
What the original functionality in Adobe CF, or Lucee's buffer setting?
a
with output=true / false on script-based code
On tags... yeah it's def solving a problem
b
Script based code isn't really any different than tag based code, other than the whitespace between lines isn't adding to the buffer automatically
a
but yer right, I might have hadtag-based code further up. This was CFWheels application code after all ;-)
other than the whitespace between lines isn't adding to the buffer
Yes so. no problem to solve there. So they could not bother trying. Still: fair cop.
b
Yeah, but that's mostly irrelevant. I actually used to think output defaulted to false in script, but that's not true. All UDFs default to output=true, it's just that script code doesn't inherently write to the buffer unless you use cfdump, writeoutput, or echo, etc
Lucees handling of UDF output is consistent regardless of whether you used tags or script which I think is good design
a
My approach would have been "stop writing shit tag-based code, CFMLers... there's a performance hit on remembering all your indentation so we can output it for you", and then leave it as-is 😉
b
Yes, I can get on board with that! 😆
a
Don't they default to
output=[not set]
? Which is different from
output=true
b
No, it defaults to true
a
output=true
also does an implied
<cfoutput>
around everything.
I could be misremembering. BUt I am "certain" that setting is tri-state
b
Never heard of that
a
yeah, I'm right (nice, for a change)
b
Both not set and true are the same behavior
you're not testing what I'm talking about.
b
Oh, you mean an implicit cfoutput?
a
bear in mind that the output attribute was added to control output of tags. It's an implementation coincidence it also does something when applied to script.
b
Yeah, so both versions output, but I see what you mean-- the implicit cfoutput only exists when it's set to true 👍
a
false ~= cfsilent; true ~= cfoutput; not set ~= just some text
b
It's been so many years since I did tags I forgot about that
a
good man 😉
I was there during the beta of CFMX6, so this got a good working over.
b
WhAT iS tHiS sTrAnGe LanGuAgE iN yOuR eXaMpLeS???
a
BAHAHAHAHA
I really have to stop and think how tag syntax works these days
b
Me too
a
Just now I was going "how do I add an argument to this function?" [albeit only briefly...]
(and then I was like "fuck that, I'm not typing in all that shit")
What do you make of this (can't run it on trycf.com cos of bugs, but run it just on Lucee): https://trycf.com/gist/7d620faba48c310ab8cce031e1ac047e/lucee5?theme=monokai
The two sets of functions are analogous, yeah?
b
I would expect them to be. What is the result when you run it?
a
Copy code
Tags
[#arguments.x#] [2]
Script
[#arguments.x#] [#arguments.x#]
Wasn't trying to find a bug, 'onest guv.
b
Oh, interesting...
lol
a
Not remotely surprised though.
b
There's not really an equivalent to cfoutput in script, but the tag island obviously is unaware of its context
a
(I started wondering "how can I emulate a tag-based function body in a script function...")