Showing posts with label StackOverflow. Show all posts
Showing posts with label StackOverflow. Show all posts

Tuesday 15 January 2013

Floating point accuracy

This is not going to be particularly earth-shattering, sorry.

Yesterday someone asked on my favourite source of militant pedantry (Stack Overflow) how to pass a BigDecimal to POI for a spreadsheet cell value. You'll need to take my word for it, as the original question has been deleted (not sure what to make of that). There's a Google-cached version of it here. I dunno how long google caches stuff for though. The gist of the question text is (this is an abridged version of the original:

Saturday 12 January 2013

Not that it will really matter in the bigger scheme of things...

After all the shenanigans on Stack Overflow y/day (more of the same as last time, except a more egregious example), I've decided I can't really support Stack Overflow as a venue for the ColdFusion community to seek help. Stack Overflow is more interested in demonstrating how "good" Stack Overflow is (according to a yardstick I don't agree with) than they are in actually helping people - all people - and that's not something I can get behind.

Thursday 27 December 2012

More balance, fewer @rseholes

There's been a bit of back-and-forth on Twitter (nothing of any merit, sadly) regarding my posting from the other day regarding some "shortcomings" in the attitude of some of the users on Stack Overflow, and also - given how said users behave - some potential areas for improvement in the Stack Overflow process.

I don't contest that the first part of the article was quite vitriol-laden, and that was by design. However later in the article I did try to discuss - in an objective, balanced way (? well, mostly) - where I think things could be improved.  However I think I did not succeed in the objectivity, or some people didn't get past the headline, or if they got that far, didn't read past the vitriol. I am guilty of doing this (to myself) in my writing sometimes.

Anyway, the article was put on the twitter radar of one of the blokes who started Stack Overflow (thanks Stephen Moretti for thinking to do that), and there was a brief exchange between myself and Jeff Atwood (the S/O bloke) and some others. I think Jeff was a bit defensive, but in his defence, I can see how he'd find my article incendiary. And equally my responses to him could have been more diplomatic. Well the ones I made just now, anyhow. I'll leave it to you - the reader - to dig it up in my Twitter history if you so choose. It's not very exciting.

So, here I am again. What I'm going to try to do in this article is to articulate my point differently:
  • no vitriol, snippiness, back-handedness or passive aggressiveness (this will be a stretch for me, as you can imagine ;-)
  • maintaining objectivity (OK, that's a variation on the above);
  • trying to convey my thoughts more clearly than I have previously.

The very first thing I'd like to say is I really like Stack Overflow! Jeff, if you only glance at this article before dismissing it, hopfully you'll see that bold red bit there.

Tuesday 25 December 2012

Christmas Spirit, StackOverflow style (#2 in a list of why StackOverflow is populated by @rseholes)

Is it the season for "Peace on Earth and goodwill to all men"? No, on StackOverflow it's more like "Screw you, newbie @rsehole: I have power over you, die die die" for some people. And, again, people like this demonstrate how the Stackoverflow approach to site self-management needs some thought.

If you read this article, also please make sure you read the follow-up to it as well.

A newbie ColdFusion user has posted a newbie-ish question over on Stackoverflow. Given the treatment they've received from non-ColdFusion users over there, I would not be surprised if it's their last.  Here's a summary of their question (by someone called "volume one"):

Friday 21 December 2012

Need help? Know how to ask for it


This article is borne out of exasperation rising from dealing with people on StackOverflow. But this time not the nazi muppets who like to think they are in a position of authority (and they're at it again today…), but the people asking the questions. To be fair: not all the people asking the questions, but a reasonable percentage of them. An uncomfortably high percentage of them. And the same extends to people asking questions on the Adobe ColdFusion forums, and other similar environments created for people to seek and get help.

I never cease to be amazed at how bloody useless people are at asking for help. And continue to marvel (not in a good way) at how disconnected from reality people must be to approach asking for help the way they go about it. And even before getting to the point of asking for help, how lacking in gumption people can be when it comes to trying to solve their own problems before expecting someone else to pitch-in and help them.

Before I start ranting too much (some might say "too late!" but I've only just started, trust me)… I enjoy participating on help forums. I've been doing it since I first located the alt.comp.lang.coldfusion Usenet group in 2001 (I started with CF in late 1999).  I enjoy the feeling I get when I've successfully helped someone move past a problem (both for myself, and knowing that the other bod will be pleased to move on from this stumbling block they'd encountered); I like the selfish sense of satisfaction I get when I work something out that someone else couldn't work out (I'm not proud of this, but I'm a realist, and it is a factor); most of all I like it when I initially don't know the answer to something I'm trying to help with, and end up learning something as a result. It also helps the ColdFusion community keep ticking over, which Adobe kinda leave up to us to do, so that's gotta be good for ColdFusion's viability going forward. Albeit in a very small way. But community activity is important to the viability of the language, I think.

Anyway, as much as I enjoy it, boy do I find it irritating at times. You probably got that already.

OK, so what's the problem?  Actually the problem is basically described by inference in this distillation of how to ask questions the smart way. It should be required reading for anyone signing up to a help forum. It should be required reading for everyone working in technology. Go read it. Now. But here's my take on where people go wrong when they encounter a problem they don't know the answer to, and where they start going wrong right from the outset.

Identify the problem

If you encounter a problem - like getting CF error on your screen - approach solving it coherently. A lot of people when they get bamboozled by an error simply start trying random things to try to solve it: "I'll restart CF and see if that helps". "I'll use a list instead of an array". "I'll just rewrite it, maybe it'll go away". This is a daft approach to solving things. Even if the problem does happen to go away, you probably won't end up knowing what the problem was, so you really can't be sure it's not some sort of transient problem that didn't just not occur after your remedial action because of some contributing factor that was not present at the time you tested. Plus isn't it nice to know what caused a problem so you don't do it again, rather than just masking it?  Also generally random actions like this don't help, and just make things worse, so attacking things incoherently is just a waste of time in a situation in which you're already probably not wanting to "invest" your time. This just increases frustration.

I use scientific method when I'm faced with a problem I can't nut out. Well a layperson's version of it anyhow. The process I use is basically this:

  1. Make an observation, eg: the manifestation of the error on the screen, or the unexpected results, or whatever it is.
  2. Form a hypothesis of what could be causing the error ("ah… that application-scoped variable has vanished").
  3. Identify the manifestations / side-effects of the situation being hypothesised ("well if that variable has been blitzed, I'll be able to tell by looking in this other place").
  4. Formulate an experiment to test the hypothesis, giving consideration to the bits identified in (3), as well as making sure the results of the experiment will conclusively demonstrate that the hypothesis is borne out. EG: simply restarting CF is not going to be a good experiment for testing a missing application scoped variable, as it doesn't actually identify what caused the problem in the first place. Basically you need measurable results (not just a nebulous change in state).
  5. Perform the experiment, and aggregate the results & any side-effects noticed from the experiment, which might need to be tuned-out in subsequent round of experiment.
  6. Draw a conclusion based on the results. Do the results of the experiment bear out the hypothesis? Quite possibly not, but they should help to finetune the next test of the hypothesis, or alter the hypothesis itself.
  7. Rinse and repeat as necessary.

Now I'm not suggesting one needs to don a labcoat and deploy the pocket protectors to do all this (but hey, if that's your outfit already, all good ;-).  All it means is stop and give some thought to what you're doing, work out a coherent way to test the situation and approach things logically.

Most people I know don't do this, they just throw their hands up in despair (or in a jazz-esque sort of way) and post all their code to StackOverflow going "doesn't work".

And most people really struggle with step 4 there. Judging by the code people end up posting on the the forums, they don't generally have a concept of a portable reproduction case. If - for example - you are having an issue with a JDBC error coming back from a <cfquery> tag, the only things that are relevant are:

  • the SQL statement being passed to the DB driver;
  • any variables that contribute to the construction of said string;
  • the values of any parameters being passed;
  • the data source (and, by inference, which DB server one is using, eg: Oracle, MySQL etc);
  • depending on the nature of the error, the schemas of any tables etc being queried;
  • the error message
  • what the expected results were ("this query is supposed to return [whatever]" or similar)

What is not relevant to any of this is:

  • any code after the <cfquery> tag
  • any code before the <cfquery> tag that don't contribute to the points above;
  • never ever ever any "code" other than CFML. HTML is never going to be relevant to a CF error.

But what I often see posted to forums (or maybe in pastebin etc if the person is remotely sensible in that regard) is the contents of the entire file the error occurs in, including all mark-up, CSS, JS, and unrelated CFML. The immediate effect this has on me is to think:

  • they've done bugger-all of their own troubleshooting if they haven't actually factored-out any of that from contributing to the situation;
  • it's not occurred to them that by posting all that cruft, the person reading the issue is kinda forced to wade through it if only to find the bit they're talking about;
  • if they can't be arsed doing any troubleshooting, why would they think I should be arsed either?

Now… back to my mention of a repro case. What one should do in this situation is pull the code that's causing the problem completely out of the context it's running in, mock the variables that it uses as inputs to perform its logic, decide what one would expect to get as a result, and then run the code. There will be three possible results of this:

  1. If the code works, then one's assumptions as to what the problem is are actually incorrect.  It suggests that one of the inputs is not what one thought it is. That needs to be tracked down and then shift the repro case to that code to work out what the story is. This is forward progress because it has fine-tuned one's understanding of the issue.
  2. If the code doesn't work in a different way from the initial error then one hasn't replicated the inputs properly. This needs to be fixed, and then the experiment repeated. In doing this, it will clarify what's going on and what's contributing to the problem. By the very nature that one's initial baseline expectation of the inputs and the results were off suggests that there's something missing from the analysis of the situation. This is a forward step in solving the problem.
  3. If the code errors in exactly the same way as it was in its original context, then one has a repro case, and one has greatly reduced the factors that could be contributing to it. From here, it's generally pretty easy to work out what's wrong. Almost all issues that initially seemed "weird", "like a bug in ColdFusion", or "just don't make any sense" get solved at this point.

If one is still at stages 1-2, then one is not yet ready to post to a forum for help. Once one gets to stage 3 - and still hasn't cracked the problem - one's got a nice terse piece of code with known inputs and outputs which can be posted to a forum. At this point one will have a far better understanding of what's going on, can articulate the experimentation that has already been done and discarded as not contributing, and there's a small piece of code that someone trying to help can copy & paste down to their local system and run without having to horse around too much. It's also demonstrated that a reasonable amount of effort has already gone into trying to sort it out one's self, which will be a positive sign to anyone thinking of helping. Plus a lot of potential help suggestions will have already been tested and discarded, saving the people helping some time. It's an all-round win.

Also, if perchance the repro case demonstrates a ColdFusion bug, you've already got a repro case to send to Adobe. Excellent.

Describe the problem

A lot of this will have been covered already if the approach above has been taken. But what I mean here is too many people start a thread / question and basically say something along the lines of "I've got this code and it doesn't work. Why doesn't it work?"  The issue here is the person reading it doesn't know what constitutes "not working". It could mean there's an error. But one still doesn't know what sort of error (compile error, logic error, SQL error, etc); it could mean one was expecting ten rows back from the DB and is only getting one; it could mean the table is outputting ten rows by five columns when one wanted five rows of ten columns. The point is: one needs to identify what constitutes "not working". Seriously, this should be bloody obvious, but for some reason it is not.

Furthermore, if one has got an error, one needs to post the bloody error message. Do not describe the error (yes, people do this: "oh I got some error about the array being wrong").  And if there's code involved (OK, obviously with an error code will be involved! ;-), post the code and identify which line the error is saying is a problem.

Pay attention

Actually… let's back up. Before posting the error… read the bloody thing. So many questions I see are asking what the problem is where the error message is saying exactly what the problem is, and is identifying the precise line and column of the line the problem is at (usually this is with compile errors). Even if they're not that explicit, ColdFusion errors are generally very descriptive, and do pretty much identify what's gone wrong. I also encounter people who say "oh, I never understand that stuff" (seriously!), but when challenged and I say "OK, which word are you struggling with?" and ask "OK, even if you've not heard the term before: what do you think a 'complex object' [for example] might be?" they realise that it's just a case of never having bothered paying attention to the error message, rather than it being impenetrable in some way. I would say 80% of errors I get asked about can be solved by simply reading the error message.

There is no such thing as telepathy

People also have a tendency to assume that just because they know something (or are aware of something about their environment) that everyone else magically will. This is not the case. No-one else is privy to the internal mechinations of your mind, nor with they know your enviroment (or even your ColdFusion version, etc). One needs to make sure that any environment consideration or other peripheral factor needs to be actually articulated. People might be able to guess, but people probably actually can't. But either way: they shouldn't be made to guess. If nothing else it's a barrier to them helping you, which is counterproductive for you.  Consider this problem (this is actually something that I have had to deal with in the past):

SELECT        *
FROM        someTable
WHERE        someColumn = #someValue#
ORDER BY    anotherColumn
LIMIT        5

My DSN is MySQL, but this errors for some reason. If I run the same query in MySQL it works fine.

The problem isn't the filter or the table schema or anything like that. It's that this code wasn't a DB query, it was a QoQ on an earlier-fetched record set. The initial data came from MySQL, sure… but it didn't occur to the person that a QoQ is not run on the DB server, it's run on CF's own little SQL stub thing, and that doesn't support LIMIT.

Now the person should have just read the damned error message (and posted it), but at the very least they should have mentioned that this wasn't a DB query.

There is no such thing as telepathy (redux)

Another thing you need to do is to research the issue, once you've identified it. This means googling error messages, programming constructs you're struggling with, and anything else relevant. And if one still needs to ask for help (TBH, googling will solve 80% of problems: very few problems are unique), then part of your question should also detail what sort of research you've already done. Because if you don't mention it, then the first valid sugggestion one ought to offer you is "did you google it?". Some of you might think "well of course I will have researched it first, that goes without saying", but let me assure you: you're the good 'uns. Most people are bloody useless, and all they do is use StackOverflow and other forums as a kind of mechanical turk: to try to get other people to be their search engines. So let us know what you've already found. Also let us know what things you've found which might seem like a solution, but turned out not to be: this will save us making the same suggestion to you, and it's also useful information to fine-tune your issue.

Most errors are your fault

A lot of people posting questions start off from a fairly defensive position that whatever is going wrong, it's not their fault. They'll say "I don't know what's wrong, because my code works fine", or "I've found a bug in ColdFusion".  I'm sorry, but almost always this is not the case. 99% of the time… perhaps more… it's a problem with the code or the approach, or something like that. ColdFusion might have a number of bugs, but they're generally pretty esoteric these days, so the odds of someone who is having a problem with a listAppend expression having suddenly found a new bug in listAppend is rather small.

The problem I have with this way of thinking is that it's much easier to discover what a problem is if one starts with the mindset that it's one's self who's cocked-up, rather than someone else or Adobe. Firstly because it almost certainly is them, but secondly because is one is troubleshooting in a defensive way and going "well I know that works, so it can't be that", one's not going to spot the fact that actually it is that code that's got the problem. I think it's also a logical fallacy that "well my code works, so it can't be that, it must be something else", because the evidence that has lead one to decide something is wrong will be manifesting from a line in one's own code, so - really - even on first indications that's probably where the problem lies.

Approach this stuff with… um… an open mind (or just a neutral mind… just not a closed mind), and one will be in the best place mentally to find the problem.

Also one comes across as a bit of a cock if one starts asserting it's a bug in CF but it happens to be that they don't know the difference between listFind and listContains (or just didn't spot they'd used the wrong one). And it's best to not look like a cock if possible, yes? ;-)

Well that was a nice rant for a Friday just before Xmas, wasn't it?

I'm off to Ireland from tomorrow through until Dec 27 - I get to see my son for a dozen or so hours in that time… thankfully 2h of which is on Xmas Day - so I dunno how much attention this blog will get across that period. On one hand I'll have my laptop with me, but on the other hand finding internet connectivity is tricky. But I'm mostly stuck out in the middle of nowhere with little else to do, so perhaps wittering on will pass the time. Who knows?  I'll at least get part 3 of the regex stuff posted at some stage in the next coupla days.

In case this is it before you head off to do festive things that are more interesting than hanging on my every blog-written word, have a good break. And make sure to eat too much. And have a beer for me.

Merry Xmas.


Wednesday 5 December 2012

I love being wrong

That's not sarcasm, I actually do rather like being wrong about stuff: it's a great vector for learning new things and improving one's knowledge. Provided one doesn't get defensive about being wrong (which if just daft), and does endeavour to understand how one was wrong, and do something about it.

Anyway, enough airy-fairy philosophising. What was I wrong about?

The form scope.

Saturday 1 December 2012

What you see is not necessarily what you get

This is another case of me not having enough space on Stack Overflow to articulate myself properly, so I'm creating a blog article and will cross reference my answer to here. With enough of a summary on S/O to try to avoid snippy comments from the self-appointed sheriffs.

Friday 30 November 2012

Stack Overflow is populated by @rseholes (#1 of what could end up being a series...)


RANT ALERT! (and language some people will find unpleasant).
Since I started this blog, I've had a link over on the right-hand side of the page encouraging people to help out other ColdFusion developers on the ColdFusion channel on Stack Overflow (and on the Adobe ColdFusion forums). I stand by my sentiment that it's important to help people, but I've about had a gutsful of Stack Overflow. Not the concept - it's admirable - but the "gimme-a-little-power-and-I-become-a-nazi" fvckwits who try to find meaning in their pathetic little lives by demonstrating how they have a tiny tiny tiny amount of authority over other people, and by god, they will exercise it.

Friday 28 September 2012

Wednesday 19 September 2012

CFML:Curious behaviour with THIS-scoped variables in onSessionEnd and onApplicationEnd

This article stems from a question that came up on StackOverflow today. In summary the bod wanted to know if they could set this.datasource conditionally on a CGI variable, and I confirmed they could, eg:
  • if the cgi.server_name equals "" => this.datasource = "firstdsn"
  • if the cgi.server_name equals "" => this.datasource = "seconddsn"
My initial response (beyond "just try it and see") was to confirm it was possible.

Someone (called "nosilleg") followed my answer up with  a warning that there could be unexpected results if onSessionEnd (etc) was to use the this.datasource value, as the CGI scope wouldn't be there, so which DSN would be used?  Good question!

To clarify... normal requests all instantiate Application.cfc, and run the pseudo-constructor code to create all the this-scoped config variables, and the CGI variables will all be there so logic predicated on them will work: that's fine.  But things like onSessionEnd() and onApplicationEnd() do not run via a request, per-se, so they won't have any CGI variables.  So what will happen?

This was - of course - my cue to slap together some test code and log stuff and run requests and all that sort of malarky, and now you have to endure reading about my findings.  Well don't say you weren't warned.

So I knocked some code together to test this:

And had a test file to request, thus:

<cfdump var="#this#">

The idea here is that I have DSN1 and DSN2 set up pointing to two different DBs, both of which have identical T_TEST tables to write data to.  Conditional on whether I request test.cfm via localhost or testing.local (both point to the same CF instance) I set this.datasource to point to one or the other (via checking CGI.SERVER_NAME).  If CGI.SERVER_NAME is neither of those, they get nowt.

What I was expecting here was for the onSessionEnd() and onApplicationEnd() to error.  I was not correct.  Well I was a bit correct.  But there is definitely fishy behaviour here.

My log file says this:

Start of logIt(). onApplicationStart [localhost] [dsn1]
End of logIt(). onApplicationStart [localhost] [dsn1]
Start of logIt(). onSessionStart [localhost] [dsn1]
End of logIt(). onSessionStart [localhost] [dsn1]
Start of logIt(). onRequestStart [localhost] [dsn1]
End of logIt(). onRequestStart [localhost] [dsn1]
Start of logIt(). onSessionStart [testing.local] [dsn2]
End of logIt(). onSessionStart [testing.local] [dsn2]
Start of logIt(). onRequestStart [testing.local] [dsn2]
End of logIt(). onRequestStart [testing.local] [dsn2]
Start of logIt(). onRequestStart [localhost] [dsn1]
End of logIt(). onRequestStart [localhost] [dsn1]
Start of logIt(). onSessionEnd [none] [dsn1]
End of logIt(). onSessionEnd [none] [dsn1]
Start of logIt(). onSessionEnd [none] [dsn1]
End of logIt(). onSessionEnd [none] [dsn1]
Start of logIt(). onApplicationEnd [none] [dsn1]
CATCH in logIt(). onApplicationEnd [none] [dsn1] [Attribute validation error for tag CFQUERY.] [The value of the attribute datasource, which is currently '', is invalid.]

I've truncated it, but the "proper" request's log entries were made by "catalina-exec-nn" when nn was a number, whereas the onSessionEnd() and onApplicationEnd() entries were made by "scheduler-n" (where n was a number).  This demonstrates the difference between a normal request running and CF doing its own thing in the background to tidy-up sessions and applications.

Note that neither onSessionEnd() or onApplicationEnd() see a CGI.server_name value.  This is no surprise. However what appears to happen is - by magic, it seems - the onSessionEnd() and onApplicationEnd() calls both receive the last value that this.datasource was set to be via a legit "request".  I verified this through more testing I'll not bore you with, but it was always the DSN of the previous request that these handlers used.  However - rather weirdly - despite onApplicationEnd() definitely seeing this.datasource, the <cfquery> tag in Query.cfc did not think it had a default datasource set.  That's an interesting disconnect, isn't it?  Especially given it seems like onSessionEnd() is in the same boat, but its query worked fine.  Oh, I should have said: data when into the DB tables exactly as one would expect, given the DSN setting (other than the error in onApplicationEnd(), I mean).

If I can be bothered (currently: no) I will refactor the Application.cfc to be tag-based so I can use <cfquery> instead, and see what happens.

Anyway, the bottom line here is that nosilleg was right to be cautious here.  However in situations wherein one doesn't need to use the DSN in the tidy-up handlers, the technique works fine.  I'll feed this back to StackOverflow.

And that's it.


Wednesday 15 August 2012

CFML: More on Application.cfc... when things run

This one stemmed from me trying to come up with an accurate answer to someone's question on StackOverflow.  To summarise, the question was about what order things run in, what scopes come into play when, and all that sort of thing.  Stuff I imagine most of us pretty much know, but perhaps don't completely know the boundaries of the edgecases.  Certainly I sat down at the keyboard, drew myself up in an all-knowing sort of way ready to type the model answer, before thinking... "you know what?  I don't actually know for sure".  And when I answer stuff on forums, I like to be like 99% confident I'm right.  Not for my sake, but because I don't like wasting people's time by giving inaccurate answers.  And a bit for my own sake ;-)

Anyway, I voted-down the two answers that were there when I first read the question, because I thought they were - on balance - inaccurate.  Both had elements of correctness about them, but they both had blatant inaccuracies about them too (ie: they stated things that were outright wrong).  But I figured if I was voting stuff down, I had better come back with the goods.
Speaking of StackOverflow... here's an aside.  If you are reading this and you don't already help out on StackOverflow and - more importantly - the Adobe ColdFusion forums, please consider donating some of your time to helping the ColdFusion community.  There are a lot of people asking questions out there, and not enough people to answer them.  We could use your help.
But anyway... that's not the topic of my wittering for the day.

So, yeah, it occurred to me I didn't actually 100% know when various scopes became available, and what was available where, and that sort of thing.  I also saw it as low-hanging-fruit for a blog entry, so here I am now.

I knocked together a quick Application.cfc, which logged what it was up to and when:

The logic at play in this is repetitive: at each step of the Application.cfc I test various scopes that might exist, report if they do exist, and attempt to create a variable in them.  Then as processing continues through various event handlers, I keep track of what exists and where.

The log file created is as follows (this is a bit longwinded... scroll down rather than read it all. I've highlighted the important bits):

1 in pseudoconstructor before application name is set application scope not enabled
1 in pseudoconstructor before application name is set session scope not enabled
1 in pseudoconstructor before application name is set request.pseudoconstructor initialised
1 in pseudoconstructor before application name is set this.pseudoconstructor initialised
1 in pseudoconstructor after application name is set application scope not enabled
1 in pseudoconstructor after application name is set session scope not enabled
1 in pseudoconstructor after application name is set request.pseudoconstructor existed
1 in pseudoconstructor after application name is set this.pseudoconstructor existed
1 in onApplicationStart application.pseudoconstructor initialised
1 in onApplicationStart session scope not enabled
1 in onApplicationStart request.pseudoconstructor existed
1 in onApplicationStart this.pseudoconstructor existed
1 in onApplicationStart application.onApplicationStart initialised
1 in onApplicationStart session scope not enabled
1 in onApplicationStart request.onApplicationStart initialised
1 in onApplicationStart this.onApplicationStart existed
1 in onSessionStart application.pseudoconstructor existed
1 in onSessionStart session.pseudoconstructor initialised
1 in onSessionStart request.pseudoconstructor existed
1 in onSessionStart this.pseudoconstructor existed
1 in onSessionStart application.onApplicationStart existed
1 in onSessionStart session.onApplicationStart initialised
1 in onSessionStart request.onApplicationStart existed
1 in onSessionStart this.onApplicationStart existed
1 in onSessionStart application.onSessionStart initialised
1 in onSessionStart session.onSessionStart initialised
1 in onSessionStart request.onSessionStart initialised
1 in onSessionStart this.onSessionStart existed
1 in onRequestStart application.pseudoconstructor existed
1 in onRequestStart session.pseudoconstructor existed
1 in onRequestStart request.pseudoconstructor existed
1 in onRequestStart this.pseudoconstructor existed
1 in onRequestStart application.onApplicationStart existed
1 in onRequestStart session.onApplicationStart existed
1 in onRequestStart request.onApplicationStart existed
1 in onRequestStart this.onApplicationStart existed
1 in onRequestStart application.onSessionStart existed
1 in onRequestStart session.onSessionStart existed
1 in onRequestStart request.onSessionStart existed
1 in onRequestStart this.onSessionStart existed
1 in onRequestStart application.onRequestStart initialised
1 in onRequestStart session.onRequestStart initialised
1 in onRequestStart request.onRequestStart initialised
1 in onRequestStart this.onRequestStart existed
1 in onRequest application.pseudoconstructor existed
1 in onRequest session.pseudoconstructor existed
1 in onRequest request.pseudoconstructor existed
1 in onRequest this.pseudoconstructor existed
1 in onRequest application.onApplicationStart existed
1 in onRequest session.onApplicationStart existed
1 in onRequest request.onApplicationStart existed
1 in onRequest this.onApplicationStart existed
1 in onRequest application.onSessionStart existed
1 in onRequest session.onSessionStart existed
1 in onRequest request.onSessionStart existed
1 in onRequest this.onSessionStart existed
1 in onRequest application.onRequestStart existed
1 in onRequest session.onRequestStart existed
1 in onRequest request.onRequestStart existed
1 in onRequest this.onRequestStart existed
1 in onRequest application.onRequest initialised
1 in onRequest session.onRequest initialised
1 in onRequest request.onRequest initialised
1 in onRequest this.onRequest existed
1 in onRequestEnd application.pseudoconstructor existed
1 in onRequestEnd session.pseudoconstructor existed
1 in onRequestEnd request.pseudoconstructor existed
1 in onRequestEnd this.pseudoconstructor existed
1 in onRequestEnd application.onApplicationStart existed
1 in onRequestEnd session.onApplicationStart existed
1 in onRequestEnd request.onApplicationStart existed
1 in onRequestEnd this.onApplicationStart existed
1 in onRequestEnd application.onSessionStart existed
1 in onRequestEnd session.onSessionStart existed
1 in onRequestEnd request.onSessionStart existed
1 in onRequestEnd this.onSessionStart existed
1 in onRequestEnd application.onRequestStart existed
1 in onRequestEnd session.onRequestStart existed
1 in onRequestEnd request.onRequestStart existed
1 in onRequestEnd this.onRequestStart existed
1 in onRequestEnd application.onRequest existed
1 in onRequestEnd session.onRequest existed
1 in onRequestEnd request.onRequest existed
1 in onRequestEnd this.onRequest existed
1 in onRequestEnd application.onRequestEnd initialised
1 in onRequestEnd session.onRequestEnd initialised
1 in onRequestEnd request.onRequestEnd initialised
1 in onRequestEnd this.onRequestEnd existed
2 in pseudoconstructor before application name is set application scope not enabled
2 in pseudoconstructor before application name is set session scope not enabled
2 in pseudoconstructor before application name is set request.pseudoconstructor initialised
2 in pseudoconstructor before application name is set this.pseudoconstructor initialised
2 in pseudoconstructor after application name is set application scope not enabled
2 in pseudoconstructor after application name is set session scope not enabled
2 in pseudoconstructor after application name is set request.pseudoconstructor existed
2 in pseudoconstructor after application name is set this.pseudoconstructor existed
2 in onRequestStart application.pseudoconstructor existed
2 in onRequestStart session.pseudoconstructor existed
2 in onRequestStart request.pseudoconstructor existed
2 in onRequestStart this.pseudoconstructor existed
2 in onRequestStart application.onApplicationStart existed
2 in onRequestStart session.onApplicationStart existed
2 in onRequestStart request.onApplicationStart initialised
2 in onRequestStart this.onApplicationStart existed
2 in onRequestStart application.onSessionStart existed
2 in onRequestStart session.onSessionStart existed
2 in onRequestStart request.onSessionStart initialised
2 in onRequestStart this.onSessionStart existed
2 in onRequestStart application.onRequestStart existed
2 in onRequestStart session.onRequestStart existed
2 in onRequestStart request.onRequestStart initialised
2 in onRequestStart this.onRequestStart existed
2 in onRequest application.pseudoconstructor existed
2 in onRequest session.pseudoconstructor existed
2 in onRequest request.pseudoconstructor existed
2 in onRequest this.pseudoconstructor existed
2 in onRequest application.onApplicationStart existed
2 in onRequest session.onApplicationStart existed
2 in onRequest request.onApplicationStart existed
2 in onRequest this.onApplicationStart existed
2 in onRequest application.onSessionStart existed
2 in onRequest session.onSessionStart existed
2 in onRequest request.onSessionStart existed
2 in onRequest this.onSessionStart existed
2 in onRequest application.onRequestStart existed
2 in onRequest session.onRequestStart existed
2 in onRequest request.onRequestStart existed
2 in onRequest this.onRequestStart existed
2 in onRequest application.onRequest existed
2 in onRequest session.onRequest existed
2 in onRequest request.onRequest initialised
2 in onRequest this.onRequest existed
2 in onRequestEnd application.pseudoconstructor existed
2 in onRequestEnd session.pseudoconstructor existed
2 in onRequestEnd request.pseudoconstructor existed
2 in onRequestEnd this.pseudoconstructor existed
2 in onRequestEnd application.onApplicationStart existed
2 in onRequestEnd session.onApplicationStart existed
2 in onRequestEnd request.onApplicationStart existed
2 in onRequestEnd this.onApplicationStart existed
2 in onRequestEnd application.onSessionStart existed
2 in onRequestEnd session.onSessionStart existed
2 in onRequestEnd request.onSessionStart existed
2 in onRequestEnd this.onSessionStart existed
2 in onRequestEnd application.onRequestStart existed
2 in onRequestEnd session.onRequestStart existed
2 in onRequestEnd request.onRequestStart existed
2 in onRequestEnd this.onRequestStart existed
2 in onRequestEnd application.onRequest existed
2 in onRequestEnd session.onRequest existed
2 in onRequestEnd request.onRequest existed
2 in onRequestEnd this.onRequest existed
2 in onRequestEnd application.onRequestEnd existed
2 in onRequestEnd session.onRequestEnd existed
2 in onRequestEnd request.onRequestEnd initialised
2 in onRequestEnd this.onRequestEnd existed

The log here follows two consecutive requests (labelled "1" and "2" in the leftmost column).

There's a whole lot of bumpf there, but the stand-out things are highlighted.

First, let's look at what happens in the pseudo-constructor (the bit of code within the component tags, but outwith any method in the CFC).

This is not surprising:

1 in pseudoconstructor before application name is set application scope not enabled
1 in pseudoconstructor before application name is set session scope not enabled

There's no chance that there'd be any sense of application before the line had been encountered.  CF doesn't know which application a given request is part of before it's been told.  Equally the session scope cannot exist prior to the application being identified, because sessions are bound to applications.

This is straight forward:
1 in pseudoconstructor before application name is set request.pseudoconstructor initialised
1 in pseudoconstructor before application name is set this.pseudoconstructor initialised

Obviously we know we can set this-scoped variables here... we'd not be able to set the application settings otherwise.  Being able to set request-scope variables is slightly surprising, given that this is before onRequestStart(), esp. given what I'm drawing your attention to next:

1 in pseudoconstructor after application name is set application scope not enabled
1 in pseudoconstructor after application name is set session scope not enabled

So this is after the application has been named.  But still the application and session scopes aren't available.  I expected they might have been as there's no reason for them not to.  I guess CF waits until the onApplicationStart() and onSessionStart() event handlers start before starting those two scopes.  Given my earlier diatribe on events vs event handlers, I half expected the scopes to be there, even if the event handlers had yet to be called.  So that is definitely something I have learned about all this.

Friday 27 July 2012

How do I know if this variable is a file handle?

I'm not going to make a habit of making two posts in one day, but this quandary has just presented itself, so I'm gonna ask about it on StackOverflow, the Adobe forums, and Twitter (via this post).

I have this code:

This is a version of the code from my earlier post, having been fixed slightly as per Simon Baynes's observation that I had a spurious catch() block in the original.

Anyway, there's another bug in it: if there was an error during the fileOpen(), then the file variable won't be a file handle, so the fileClose() in the finally block will error.  Oops.

So I need to identify whether the file variable is actually a file handle, and iff it is, then close it.

Thursday 19 July 2012

According to ColdFusion "0,6" == "6,0". And both are integers to boot

If you participate on StackOverflow or the Adobe ColdFusion Forums, you might be aware of this already.  But I thought I'd write it up again, and also solicit people's opinions on the topic.

Consider this code:

<cfset list1 = "0,6"> 
<cfset list2 = "6,0">

<cfif list1 eq list2>
    #list1# equals #list2#<br />
    #list1# does not equal #list2#<br />

What would you expect this to output?  Would you be surprised to here it outputs this:

0,6 equals 6,0

I was, initially.  My reaction was something along the lines of "WTF?"