- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
!frist != sceond
Admin
My favourite progress bar is the Achilles' Tortoise progress bar.
Doesn't matter what you're monitoring the progress of, it doesn't matter.
It goes:
If it's a very long thing that you're monitoring the progress of, the successive increments to the bar become imperceptible, so in that case (e.g. if A gets within 1% of 100% and it's still not finished, start the bar again with "Stage 2 process" and keep increasing that until it's finally finished.
Admin
Since my comment probably won't not be unmoderated until not this week, I couldn't care no less what I'm not writing here. Na na na, no no no ... Or not? I'm no nobot.
Admin
Not uninteresting! This nonsense comment gets through with no delay, but my no-nonsense comments of not this week were not moderated for no less than days. Nobody must understand this, not?
Admin
Umm. I don't think 1.0/9.0 is anything like the same as 100/9. Mostly when I do progress bars my total is 'number of things expected' and I count 'number of things done'. It works well enough (except when one of those things take 10 times as long as all the others put together which is pretty much how windows update behaves)
Admin
Double negatives are a no-no.
Admin
@thosrtanner: But that's the point.
The process producing a progress bar can't know how long the rest of the process will take because it can't know (in the general case) what surprises lie ahead. So any approach is semi-arbitrary, whether that's your count, Zeno's/Achille's Tortoise, or just guessing.
Admin
Maybe I'm just getting old (I'm 37, but still relatively new to being a developer after a mid life career change), but I increasingly find that it can take me a long time to mentally parse all but the most trivial Boolean expressions built out of several combinators. That probably makes me TRWTF but, yes, I'd be mentally shooting whoever wrote this code. Don't be afraid to extract subexpressions into separate (well named) constants so it's more obvious what's going on!
Admin
Don't nod. Avoid them.
Admin
So when the progress bar is at 100 it's still in progress? Our bars go up to 101!
Admin
Shouldn't that read “Don't Not Be Non-Negative?” Just sayin'
Admin
Never fail to avoid negated negatives.
Admin
Whoever wrote that was a nattering nabob.
Admin
point is its an explainable guess. I have 25 things to do. I've done 24. I should be more or less finished. as long as each thing is the same. i have 25 different things to do is a harder problem
Admin
I thought 100% was the highest possible progress value and so the bar would stick at 100 instead of ever ending.
Why wouldn’t the condition be if progress < 100?
Admin
Nah, it's not just you and it's not just age. I may be a little further up the hill from you, but even in my younger years my mental processes would be about the same: pull out DeMorgan's and other boolean laws to try and simplify this in order to help figure out what it's trying to do. There may be some who have practiced making those simplifications in their head for longer who may be able to figure it out a little quicker than us; but regardless of who's looking at it, the more components to the expression involved the more mental effort required to decipher it.
Admin
What good does the "|| false" in the proposed simplified version do? Is this some weird JavaScript thing? It seems redundant.
Admin
I've often seen (well, it is in Windows OS stuff) progress bars where the "completed_so_far" green bar extends well past the designated 100% point. And we all know that %progress rarely has any correlation with percent of time left to wait.
Admin
I appreciate your homage to the US Veep with the worst-sounding name of all time.
Admin
add to that the contortions your mind has to go through when you see this implicit double negative
I can see how code could get like that, but on the other hand I've seen code start off life like that.
Admin
Oh, I totally agree. It's not even hard to understand but I inwardly grind my teeth whenever I see an if/else or ternary which has the "negative" condition first.
Mind you, I've also created these, generally when the "if (!whatever)" existed on its own first and I've had reason to later add an "else". (Yes I should refractor at that point, it's trivial - but I don't always remember.) But certainly anyone who writes it like that in the first place, without seeing the problem even when pointed out to them (we all do minor WTFs all the time, this is why code reviews exist), is likely beyond help.
Admin
I love (hate?) how the last 1% of the progress bar takes longer than any other 10% of the progress bar. It's like the programmers said "and then cleanup. That's fast, right?" and assigned cleanup to the last 1%, forgetting just how much cleanup there is to do.
Admin
It's a weird JavaScript thing- without the
|| false
the function would returnnull
if you passed it anull
. Which,null
is falsy, so that's probably fine, but the original version returns false in that case, so I opted in my revision to make it do that. It would probably continue to work correctly without it, but who knows what the calling code expects?I mean, they wrote this, so I probably shouldn't expect them to support falsy values correctly.
Admin
reminds me of a very old program, that saneed the computer for...something...it said "99%" when it was less than half done...i know because i timed it.
Admin
Maybe I'm a bit OCD-ish, but I feel more "comfortable" first weeding out inputs that are NULL or other unwanted crud, and only then passing the variable to the code that does something useful.
Admin
Whatever you do - don't. Don't not confuse not doing for do no do dee doodle doo.
Admin
Except in else-if sequences:
if (!foo) { ... } else if (bar) { ... } else if (baz) { ... } else { ... }
is usually more readable than:
if (foo) if (bar) { ... } else if (baz) { ... } else { ... } else { ... }
Admin
We often have large loops, where we know at the start that we'll be doing e.g. 100 million iterations. Instead of updating the progress bar with (done so far / total work), we'll increment a counter. Every time the counter goes over (total / 100) (pre-computed at the start), we update the progress bar and reset the counter. That performs much better, especially when the progress bar is in another (GUI) thread.
Admin
I have no problem with a negative condition, because I see the "then" part being the meaty one, like for a "while" loop. so I expect it to come first, the "else" part being some exceptions/
If my only available condition has to be negated to keep that order, then !condition it is, I see no point in introducing some other element that should be kept equivalent to !condition but that I could forget to update. If my only test is "isFinished", I have no problem with if (!isFinished) [plus that makes the code more consistent, i can do a global search on isFinished and not forget a isNotFinished somewhere).
Admin
Umm, why'd you have isNotFinished? That's just making the problem worse
Wait until you have to work with code that says
if (!isFinished) { huge amount of code; } else { break; }
or
if (!isNotFinished)
something I have seen more than enough times
Admin
I'm surprised nobody has mentioned good old De Morgan's. It seems amongst various kinds of programmer that the idea of transforming Boolean expressions using De Morgan's is something they're never taught, and leads to convoluted negations and so on that are unnecessary. They ARE often seemingly unnecessary at the electronics level with gated logic, as typically you want to build your Boolean circuit out of only NAND or NOR gates (you don't want to use a mixture of gates), so sometimes you find developers who have come through electronics kinda doing this because their mental model automatically is used to dealing with inverted logic. (That's my theory anyway - I tend to find those with an electronics background often have a difficulty doing DRY for the same reason, if they have four seemingly-identical ports at four different addresses, they will write four otherwise-identical bits of code, one for each port...) I think it really depends on what your mental model of the system - what level of abstraction - you are used to working at. But that is just an anecdotal opinion and I've no evidence to back it up.
For a similar reason, I WILL invert an expression in an if-else statement to make the "if-branch" shorter than the "else-branch". I'll trust the peephole optimizer to make the most efficient branching instructions anyway (and if it can't do that, there are much worse things to worry about). I just tink it makes it much easier as a reader to trace the code. I know it goes against much "good code" advice to put the normal case first: but if you think about it, mathematical algorithms usually put the special cases first and general case last. I think it just depends very much how your mental model of a processor works, what is "natural" for you.
Admin
i must apologise to you, you DID mention DeMorgan's. I searched for "De Morgan" with a space: I did read the comments but somehow I missed yours, so repeated the point you already eloquently made.
Admin
That's actually an implementation of a raster line drawing algorithm, when you come to thing of it.
You shouldn't "reset the counter", though (i.e. to zero), but subtract the pre-computed (total / 100). Otherwise you'll accumulate errors....
Admin
The speed of the multi-stage Achillesd/Tortoise progress bar appears to be exponentially decreasing. But people like progress bars that appear to have an increasing speed since this strongly suggests that the task is "almost done".
If you want to avoid increments smaller than 1%, the multi-stage Achillesd/Tortoise progress bar is now drawn at fixed percentages 0%, 50%, 75%, 87.5%, 93.8%, 96.9%, 98,4%, 100% (and go to the next stage if the task has not finished).
You can turn this into an exponentially increasing progress bar by "mirroring" the series: draw the progress bar at 0%, 1.6%, 3.1%, 6.3%, 12.5%, 25%, 50%, 100% (and go to the next stage if the task has not finished).
Admin
Professor: "There are languages in which the double negative has a positive meaning. There are languages in which a double negative strengthens the negative. But there are no languages in which a double positive has a negative meaning" Student: "Yeah, right!"
Admin
Why not
Admin
Progress bars are reassuring because
When it appears at all, it assures you that the device recognized the button click and is working on the task, and
If it's moving, presumably it is still working on the task rather than froze up.
But these good features are subverted more often than not. When it takes 10 seconds for the progress bar to appear, you've already clicked that button several more times. When the last 1% takes longer than the first 99%, you'll think it froze up. And when the progress bar is done but the task isn't done, you want to call the Mafia and put out a hit on the programmer...
Admin
The !!foo expression is guaranteed to convert any value to either true or false. So I'd go for: !!progress && progress <= 100 to be certain to return true or false.
Admin
I would even suggest
(progress) => !!(progress && progress <= 100)
as it handles javascript truthy/falsy(ness), fixes the issue and even pays homage to the original WTF
Admin
You can just do finished = progress >= 100
If progress is null or undefined, the result is false. Also, there's the nullish coalescing operator, which isn't needed but is nice to clarify a bit; finished = (progress ?? 0) >= 100
Admin
Oh yes. I once added a simple progress bar to a program that would simply freeze the GUI, which was an understandable nuisance for the users, who had to constantly check the program if it was finished by trying to click the GUI. I changed NOTHING else, just added that progress bar (and added a few "Application.DoEvent()"s, even though this might be a WTF for some; I didn't know any better back then). I recieved overwhelmingly positve feedback for that change, saying how much faster the program now ran.
Luckily this happened pretty early in my career, so I learned a valuable lesson that day: ALWAYS give feedback to the user that something is happening. Oh, and maybe add a frew "break"s here and there if a value you were looking for in a DB table with ~1,000,000 rows was already found, instead of traversing through the whole table no matter what...
Admin
I find a lot of programmers 9and people in general) remember the processes for these sorts of things better than the names.
Thank you for mentioning the name in a nice big rant that was significant enough for me to actually read it. I now have a comment to attach to some code I wrote a while back...