I’m going to be brief here and only address specific points. Where I’ve
truncated stuff I either agree, don’t sufficiently disagree to comment, or
our opinions are sufficiently divergent it doesn’t warrant further
discussion.
Side note, I would say with executeWithin(), it would be a must for it to
return the value of whichever callback returns first.
Yup, that was my intent.
return executeWithin(createTimespan(0,0,0,30), function() {
One thing that occurred to me over night is that createTimeSpan() is the
wrong mechanism to use here. It should just be a unit of seconds (poss ms).
Agreed - I wrote that poorly, and I’m not sure if I can convey my thoughts
on it correctly - however I’ll try. I still feel the closure syntax feels
too verbose. What I intended to point out was that dealing with timeouts
as a concept feels less integrated with the language itself. Sure, it is
a built-in function, integrated with the language, but honestly (and
expounding on this would be its own thread), when I have the option, I *think
*I would prefer syntax constructs or objects as opposed to procedural
functions, especially when I’m dealing with otherwise object-oriented
code.
I get what you mean, and in general I err towards OO code over procedural
where possible too. However I also think cocking around adding new language
constructs is something that should be treated with extreme caution.
My challenge here is that I think adding a time out to try/catch is just
wrong, so another approach is needed. It’s not that I think it’s better
or worse than a closure-based option (or even the other syntax variation
mentioned, which I’ll get to), I just think it’s absolutely the wrong and a
syntactically invalid approach.
Some people would fall back to that “tags without angle brackets in script”
syntax for a solution, which - IMO - isn’t as bad in theory, however I
think the actual syntax variation is lazy and inelegant language design
which ought to be phased out of CFML… in favour of a “closure” approach.
I dunno if you read my blog or saw my earlier link, but I put my position
forward here:
In summary if we were talking about purely tag-based code, we could have
this:
That’s fine.
Now in Railo/Lucee’s CFML, the script-based equivalent to that is currently:
executewithin timeout=“1” {
// etc
}
As per my article above, that approach is goddawful, IMO.
The natural evolution of the thought process from tags to script ought to
have continued along the lines I blogged, and resulted in:
executeWithin(1, callback);
Not just for this specific example, but for any block-based functionality.
That’s how I got to where I did.
I need to not fall into the same trap Micha did with his generic approach
though: is a generic approach actually the right approach all the time? No,
it won’t be. And I think this is what’s being explored by you and others
now. I’ve still not seen anything that compels me to think the non-generic
approach gives us anything. And as I said, the time out on a try/catch is a
show-stopper for me.
But you have a point re the procedural-ish-ness here.
I can think two things:
- like it or not, most of native CFML is still procedural. It’s been
getting better since Railo 4.0, but it’s still miles behind what you or I
would do with our own CFML-written code. The question is: should we
perpetuate this? And is messing with existing language constructs or adding
new ones so as to not perpetuate more procedural headless functions the
correct approach?
- decide that this is a method of a class. System.executeWithin()?
Request.executeWithin()? Perhaps it’s just a static method of one of
Lucee’s own classes? I’d like to go that way, TBH: ditch all procedural
functions in favour of methods on classes / objects. It does mean actually
creating some of the “missing” classes though. Is it OK to have the System
(for example) class implied, so headless functions are implicitly methods
of that class?
These are more questions than answers.
Also bear in mind that I also see all enhancements as only applying to
.lucee code, so we can be ambitious as to how the implementation could be.
If .lucee went ahead, I would expect all the headless procedural functions
to go. Well: I’ll be requesting it.
- […] an overall request timeout (which apparently cannot be handled
gracefully?)
I think Micha is wrong on that, but that’s another thread.
I’m omitting the rest as we simply don’t agree on this. Which is cool.
My gut feeling on this is that if you are going to go to the trouble of
wrapping a long running block of code, you should be ready to handle it at
that point, and not just automatically pass along a different flavor of
exception. For that reason, I would probably lean toward the timeout
handler being required.
Overnight I came back to that way of thinking too. However In the course of
thinking about all this again this morning (all of this is pre-coffee
too!), I’ve swung back.
I think there is value-add in just being able to time-box the code block,
whether or not the handling of the time out automatically errors, or
requires a handler callback, or might take an optional one.
I also think it’s legit for the request to exception-out if the time-boxed
code exceeds its allowed execution time. I think that generally just
failing the request with a Timeout exception is going to be the remedial
action in these situations? And having an alternative handling of it (which
may then end with an exception of some sort after doing some other stuff)
would itself be the exceptional handling of the situation?
If you intend to not handle the timeout then you should throw the
exception. At that point, both ways (closures/trys) are essentially
equivalent, only the try syntax is faster for me to read and understand
what is going on. Nor do I think its a stretch for someone reading it for
the first time to understand it quickly.
I do not dispute that try/catch syntax is easier to read for the first
time. However you hit the nail on the head. This is only ever a problem
for the first time one encounters it. After that you do understand it.
And, TBH, is not using inline callbacks pretty much second nature for
anyone who uses JS these days (and don’t all CFMLers use JS too?) I realise
understand the minutiae of how closure words eludes a lot of people, but I
don’t think inline functions are really that foreign for people?
All new syntax is new to a person once.
However, as always, I can think of alternate scenarios, where you do
intend to simply throw an exception. That brings this new thought to
mind. Lets say you have a component method that should throw an exception
if it takes to long to run. You could either wrap the body in an
executeWithin, from which you throw an exception explicitly, or… put the
timeout on the function:
function mayTakeAWhile() timeout=30 {} // reads very succinct
try {
mayTakeAWhile();
} catch(Timeout e) {
…
}
// or if you’re doing something inline you can use try/timeout
// if timeout is implemented on the function def, then this should follow
suit, although I do think try/within is easier on the eyes
try (within/timeout:30) {
} catch(Timeout e) {}
It’s not the job of a function to know whether it might take too long to
run in whatever context it’s being called in. This is a compile time
conceit here, which isn’t the right approach.
You’re also making the function do two things: a) it’s job; b) and timeout
if needs must. Functions should only do one thing. The subtle difference
here from the executeWithin() function is its one job is to time-box a
callback.
On the other hand, is the exception handling for the missing file / DB
error supposed to be part of the code that might time out? It could be! In
which case, obviously that does belong in the executeWithin() call
too. Not in exception handling which is excluded from the time out.
My point was I saw a *possibility *of a race condition where a database
exception occurs at the same time the timeout occurs, in which case, are
the catch/finally blocks allowed to complete? From the way the request
timeout currently operates, I’m not sure that it would. If they are
allowed to complete - could the timeout handler execute first? Possibly.
Are these major blockers - no, just extra things to consider. However,
these are non-issues with the try/catch.
Don’t follow you here sorry. Try again? (I might just be being thick).
Another side note - if you have timeouts integrated in with the try/catch
(or function), you can get more pinpoint location of where the timeout
occurred - page/line/etc - for you to potentially identify the root cause
faster. With executeWithin, all you know is something within the first
callback took too long. Maybe you know what it is, but maybe not.
You’re inventing a shortcoming here. Remember my suggestion was to pass
some context to the time out handler to accommodate this very thing. Even
if I hadn’t suggested it, you’re presupposing a shortfall in something that
hasn’t been implemented yet simply to further your case 
Still: you’re entitled to your preferred approach here. I’m not suggesting
you’re not. Nor am I suggesting you’re intrinsically wrong. However I’m
also not finding myself thinking “hey, Jesse’s got a point here”.
I’m wondering if the real Adam Cameron actually wrote that.
Perhaps my
point is to make sure anything that gets done is fully thought out first -
win-win 
It’s always the real Adam Cameron.
I treat with respect people who treat both themselves and myself with
respect (whichever level of respect is warranted, which in the case of the
latter is sometimes “not much” 
I treat with contempt people who insult either their own intelligence, or
try to do same with mine.
Good discussion though
Agreed
You are highly respected in the community, myself included, and
it has been fun hashing this out.
, and it’s encouraged me to better evaluate the viability / suitability
of the function-based solution. I like it more now 
I’ve been told I’m stubborn…I still like the try/catch better, and now I
like the function timeout idea better too. 
I suspect we are going to ultimately agree to disagree with this one. But
let’s see where it goes.
You’ve certainly got me irked about the whole “procedural function” thing
today. And I’m not sure my response was “explanation” (good), or “self
justification” (bad). I think it’s mostly the former, but I’m not sure.
And now I need to go find some coffee.
Cheers fella.On 16 February 2015 at 03:25, Jesse Shaffer <@Jesse_Shaffer> wrote:
–
Adam