- From: Bjoern Hoehrmann <derhoermi@gmx.net>
- Date: Wed, 24 Apr 2013 04:08:18 +0200
- To: www-archive@w3.org
So, I very strongly prefer writing code that always works, and code that does not look like it always works correctly is hard to swallow. Doubts and bugs tend to go hand in hand. There are some implications with that, I wouldn't be very happy to write `querySelector('linearGradient')` if that matches non-SVG `<linearGradient>` elements, and when I see, say, my $query = "SELECT ObjectId" . " FROM Transactions JOIN Attachments" . " ON Attachments.TransactionId = Transactions.id" . " WHERE ObjectType = 'RT::Ticket'" . " AND MessageId = '" . $MessageId . "';"; as via <http://www.w3.org/blog/systeam/2009/05/19/tracking_requests/> then <https://lists.w3.org/Archives/Team/sysreq/2009May/0227.html> I'd report the bug. In <news:3a270eaf.15148572@news.bjoern.hoehrmann.de>, and I would link the Google Groups version here, but the "new" Google Groups ... one thing that bugs me about it is that someone at Google used the wrong GWT options to make it, for me it loads a 2.5 MB script that, for instance, has 1493 functions, in a string constant, like function ABC(a){this.a=a} Anyway, that message is from the year 2000, I was still in school and a year before I didn't even have an e-mail address, but I was following the german PHP and Perl newsgroups and people were building lots of web sites with user account management, and I learned "hashing passwords" is a thing. This whole "one-way-function" business made no sense to me, as I encountered it in that context anyway, and being very curious, I ended up experimenting with them. Before Google Groups we had DejaNews, which had the nice slogan "Share what you know, learn what you don't", and in that message I shared, in the german PHP newsgroup at the time, a Perl script (poor form, I know) that showed what I learned, namely that hashing passwords is no better than storing them literally for practical purposes, by computing all the hashed passwords up to a certain length and comparing it to a given one, noting that for a couple of thousand Deutsche Mark you could persist all the hashed passwords to disk and just look them up (now known as "rain- bow tables"). Actually, the way I was looking at this at the time was more that I did not want anybody to know my passwords! Very much including the sites I might sign up with. That seemed to be the whole idea, only I and nobody else should know about it. Especially because I might want to re-use my passwords, but when I sign up with the wrong service, they might be able to compromise my other accounts! This whole thing didn't make a lot of sense to me, and still doesn't, not that I know why I should have about a zillion of Bugzilla and mailman accounts across the web to begin with, yet, in the mainstream news over the past few years there have been lots of cases with "hacked web sites" where password were, at best, "hashed". With no salt, I will add. With my Usenet posting above, it was followed up with by Kristian Koehntopp, best known to me as managing the german PHP community very well, maintaining an elaborate FAQ about it at the time and encouraging good behavior in the PHP newsgroups, from which I learned a lot, ... pointing out that the problem I mentioned is why it's common to add salts to the password before hashing and storing it. I did not know anything about salts back then, just as I don't know why people do not know about salts today... Anyway, we want to wait for DOM Events using `yield` which brings me to http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0333.html http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0337.html and then finally back to my original Waiting for DOM Events using yield at <http://lists.w3.org/Archives/Public/www-archive/2008Jul/0009.html>. I made http://www.websitedev.de/temp/purple-clouds-canvas.html and as is usual with web browsers, this worked fine in some, and partially in some and not at all in others, even though they all supposedly supported the features it uses. It basically just loads two PNGs, scales them using a `<canvas>`, and then uses the bigger versions in a background image ani- mation. The images are partially transparent, and they move at different speeds, so you get an illusion of multi-layer movement. Now, as it turned out, you can draw images onto a canvas that have not yet fully loaded without some obvious signal that you are doing anything wrong, at least not at the time. This was round about the first time I used the damn thing, so I asked around and debugged a bit, identified that as the cause, and eventually came up with another version that does wait http://www.websitedev.de/temp/purple-clouds-canvas-2.html for the two images to load. I had to write a state machine that, in this version, counts the images that have successfully loaded, with code that requires updates in more than one place if I later decided to load three images instead of two, which would obviously lead to more bugs, and if I wanted to avoid that, I would have to write some "load multiple images" library making even more of a mess. Browser vendors had, at that point, long ago decided that there should be "no more synchronous APIs", but for plumbing like what was needed here they had nothing... So, in that message above I point out that, essentially, generators as they had been implemented in Firefox by then encapsulate continuations, so there is no need to manually write continuation-passing-style code; in the version there I ended up with var img1 = new Image(315, 48); OnYieldWaitForEvent(self, img1, 'load', false); img1.src = 'http://www.w3.org/Icons/w3c_main'; yield; // wait for img1 'load' // ... load more images here ... Besides the obvious problem that you actually want to load the various images in parallel, as the browser sees fit, which would require some- thing akin to `WaitForMultipleObjects` as it is called in the Win32 API, I actually started out with yield WaitForEvent(...); But that requires setting `src` before registering the listeners, and back then that would lead to bugs, and five years later it still does. I liked http://lists.w3.org/Archives/Public/www-tag/2013Mar/0024.html where Alex Russell notes the problem of code that looks like it has ti- ming issues "but doesn't" (actually "does", due to bugs). So I went with the code above, where there is no chance that the listener has not been registered before the load event is dispatched. I also didn't want to learn all about the "interesting" practise of throwing a `StopIteration` iteration exception to signal that there are no more elements to be expected from a generator, and being unable to obtain a reference to the generator object from the generator code was also frustrating (can you write a Y-combinator for this case?) and as handling multiple images would have required a lot more code... Well I figured just get the main point across, and I think it did that. In the years after, there did not really seem to be any interest to make any headway in this direction; on the contrary, as usual, people went for the local optima, the easy, quick solutions that work right now and do not require coordination or long-term thinking; rather, there we got plenty of suggestions to add "sync" APIs to "workers" because "async" is "sux" but workers don't need "async", right. But now Futures and Promises are all the rage and you get to see `await` on es-discuss, and discussions about monad flattening on "GitHub", and http://lists.w3.org/Archives/Public/www-dom/2013JanMar/0203.html has not really been resolved yet, as far as I am concerned, so I figured it may be useful to have a better-world version of the code posted back then: function OnYieldWaitForEvent(target, name, useCapture) { return function(resume) { var listener; listener = function(){ target.removeEventListener(name, listener, useCapture); resume(); }; target.addEventListener(name, listener, useCapture); } } function ExecWithOnYield(func) { var generator = new func; var ExecOneStep; ExecOneStep = function(){ try { var wrapped = generator.next(); // TODO: what if `wrapped` throws `StopIteration`? wrapped(ExecOneStep); } catch (e) { if (e instanceof StopIteration) { console.log("StopIteration"); } else { console.log("other exception"); } } } ExecOneStep(generator); }; function test() { var img1 = new Image(315, 48); img1.src = 'http://www.w3.org/Icons/w3c_main'; yield OnYieldWaitForEvent(img1, 'load', false); console.log("img1 has loaded when we get here"); }; ExecWithOnYield(test); In http://taskjs.org/ my `ExecWithOnYield` is called `spawn`, and the `OnYieldWaitForEvent` function would return a "Promise", and then the `ExecWithOnYield` function would probably call `wrapped.then` instead of calling the function object, and so on, but the ideas are the same, with devilish details that have yet to be worked out. As for my question on www-dom, my intuition is that if it is indeed "best" to ... well, language seems to get awkward here, let's perhaps say that if it is indeed best when promises can only be kept asyncly, making that incompatible with the existing event dispatch mechanism, then some re-architecting is needed to, in essence, bring the use case, load multiple images to draw on canvas, that got me here, in line with "Futures". How to go from `new Image(...)` to a `Future` is one problem. And, perhaps, to wind back to the beginning a second time, in Perl, the `...` is a valid expression that throws a "Not Implemented" exception if executed. That is great, because that way I can hint at error handling code without actually writing it, and unlike a `// ...` comment, it will work at runtime. In contrast, in my PNG recompressor `pngwolf` I write stuff like https://github.com/hoehrmann/pngwolf/blob/master/pngwolf.cxx if (fwrite(PNG_MAGIC, 8, 1, out) != 1) { } which is strictly worse, but at least you can see easily that something is missing. And if you start using `...` to mark stubs, say in case of <https://gist.github.com/5392308> to mark stubs like sub binary_search { ... } you will soon find yourself wanting syntax to mark sections of code that "cannot happen", which may indeed be "impossible", but only until some- one modifies the preceding code, and if you fail to encode "this cannot happen" in a dynamic language where the "compiler" cannot easily tell you about, say, missing return values, in certain branches, you will end up having a bad time debugging the code one day. Hence some of the few `Carp::confess("Impossible")` in the code, but that doesn't look terrib- ly right to me... Perhaps three U+2620 as expression? regards, -- Björn Höhrmann · mailto:bjoern@hoehrmann.de · http://bjoern.hoehrmann.de Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de 25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/
Received on Wednesday, 24 April 2013 02:08:47 UTC