Showing posts with label rambling. Show all posts
Showing posts with label rambling. Show all posts

Sunday, November 9, 2025

The System Is the Authority

This is the first post for Decoded Node that has been written with league/commonmark instead of erusev/parsedown.  This technically aligns the Markdown implementation between this blog and my personal website (where CommonMark was readily integrated with Twig.)  Which is fancy talk for:

  • Footnote-style link syntax works on both sites now
  • Smart quotes are automated, instead of using platform-dependent input methods, or UniCycle

UniCycle “works,” but it’s not maintained (AFAICS), and the implementation strikes me as a bit of a hack.  It works fine in insert mode, but r' won’t replace with smart quote.  It’s a shame, because it has such a great name.

(Also along the way, I decided that .md won, so this processor no longer accepts anything like .mkd or .mdown.  Makes things easier than asking, “does this file match /\.ma?r?k?do?w?n$/?”)

Didn’t the Title Mention… Authority?

What strikes me about this is that “the format which I author in” is only incompletely described as “Markdown."  This particular move was feasible because league/commonmark is effectively a superset of erusev/parsedown.  If I decided I wanted to go back, I would have to edit all the new features out of newer posts.  Actually, if I want to update an old post and I happened to miss a smart quote in it, the non-smart quotes would also be changed by using the new parser.

What actually defines the output is not only the input, but the exact tool used to create it.

(I’m thrashing around in the direction of “the purpose of a system is what it does” and Hyrum’s Law, but neither of those things fit.)

That wouldn’t be much of an observation if I were saying, “An XLST processor doesn’t turn my Markdown into HTML,” but I didn’t really expect the choice of Markdown tool to matter so much to processing Markdown input.

Maybe it could be phrased as, “Markdown processors are not bug-for-bug compatible.”

Version Note

I use this code to write posts, not to mess around with code, so it’s not always clear whether the Markdown parser is up-to-date.  However, it seems I was using Parsedown 1.7.4 which is, at the time of writing this post, the latest stable release.  1.8.0 is in beta, and 2.0.0 seems to be barely started.

Sunday, June 15, 2025

Nostalgia for the Amiga

When I was young, my father owned a series of Commodore machines, the last one being an Amiga 500.  BASIC was for chumps, and our only other alternative was an assembler and a single misprint-riddled book for it.  We didn’t have the internet, or any local user group/mentoring.  We made the asm stuff work, by which I mean, mostly I stole the results of my older brother’s reverse engineering.

Years later, just before the Java phenomenon reached our little community college, I started learning C++ (officially) and C (from the internet), and some mysteries started falling into place.

  • The large blocks of declare statements in assembly were a C struct.
  • The weird parts of that struct like next_window: dc.l 0 were spaces for the OS to put a pointer to the next window, creating a singly-linked list of windows on screen.
  • The difference between label and #label snapped into sharp relief when I reached Pointer Enlightenment. They were *p and p, respectively. (Somewhat; C doesn’t distinguish between absolute and PC-relative addressing.)
  • Loading the label at the start of a block of declare statements into a register before making a library call was passing a pointer to the OS.
  • The 68000’s data/address register split wasn’t arbitrary; only address registers could be used with an offset, so the pointer-to-struct went in an address register, for reading fields within the struct.
  • That weird WaitForEvent function in the OS library was the core of cooperative multitasking.  The Amiga also had preemptive multitasking, but the time slice was large enough to make the system visibly laggy if a process was uncooperative. Like all of my asm programs.

That experience of simultaneous, two-way enlightenment (asm to C and back) with pointers was incredible, but has also been a once-in-a-lifetime high.  It also gave me a lot of “if-only” feelings.  Had I understood all this stuff back then, I could have done so much more with the Amiga.

(Incidentally, that next-window pointer being in the window structure makes it invasive.  I guess this means my first encounter with invasive lists could have been before Linux was ever released.)

I also felt a sort of awe or magic about the hardware design, that was missing from the PC space.  The Amiga was half computer, half game console internally, with a bunch of custom chips to do really neat graphics. Although it had a limited number of colors in the palette, the co-processor could switch out the palette between scan lines, allowing quite a few colors per screen.  HAM mode [hold-and-modify] could also produce “thousands of colors” out of a 16-color palette, if one could accept some color-fringing artifacts.

We didn’t have a VCR or camcorder (the money was spent on the computer) but apparently, the Amiga was great at video, too.

But it was soon proven to be a dead end.  When RAM gets fast enough, a boring linear RGB framebuffer is the best option, and bitplanes (or HAM mode) turn from “cool hacks” into mere workarounds for the era’s limitations.  The 68000 family wasn’t able to keep up with Intel’s immense fab budget to fling clockspeed with the best of them, and Commodore died before a PowerPC transition could have happened.  And who even knows if they could have been as successful as Apple with it?

The Amiga’s ability to “just plug it into a TV” became a limitation over time, as the business world put all its money into PCs with dedicated monitors.  They were more expensive, but also better.  Our first PC would run in 800⨉600, although it could also produce a flickery 1024⨉768.  By comparison, Workbench on the Amiga ran in “medium” resolution, 640⨉200.  High resolution only doubled the line count, and flickered intensively on our monitor.  Ultimately, monitors came down in price and offered much better than TV quality; I went off to university (post-community-college) with a monitor capable of 1280⨉1024.

This entry was somewhat prompted by “Classical "Single user computers" were a flawed or at least limited ideas”.

Sunday, January 19, 2025

Reminiscing about fvwm

Inspired by Chris Siebenmann talking about his setup and reminiscing about MGR, let’s jump in the Epoch and set the dial for 2002.

I was in college, absolutely blown away by the customizability of X11.  You could have a “full desktop” like CDE on the Suns, or KDE/Gnome on my home computer (variously Linux and FreeBSD); or else you could choose to run with only a window manager.  Those ranged from quasi-desktops like WindowMaker and Fluxbox, down to minimalist options like Ratpoison (so named because it was intended to be used without the mouse), with what I can only describe as “normal” options in between.

In this milieu, I found fvwm2 and really dug into that.  The configuration makes it more of a “window manager construction kit” than a fully-defined window manager.  (In contrast, one could barely do anything but theme Metacity.)  I put my window title bars down the left side, because it let me have ten more pixels of vertical space!  And, let’s be honest, just because I could.

I had keyboard shortcuts for everything.  Nobody in Unix space used Macs in those days; we were busy calling the iMac a “lampshade.” Therefore, Linux applications all used ctrl/alt/shift for shortcuts, and left the Windows key (Super) free for my window management shortcuts.  Oh, and I think I drew my own icons, so I could have Amiga-style raise/lower buttons in the title bars.

I also found out I had limits.  I configured a 3x3 grid of virtual desktops each with 3x3 pages on them, but even “9 places to look for windows” was absurdly oversized.  In practice, I only ever used 3 pages on 1 desktop.  By the time I wrote Layer Juggling, I had forgotten about fvwm’s “pages” layer entirely.

I had a great run with fvwm and WindowMaker for 2–4 years there, but it soon became clear I was trading features (like having a volume control, or instantly applying themes) for an environment that nobody else could use.  Meanwhile, I was losing familiarity with Windows, which would slow me down if I were using anyone else’s computer.  I switched to KDE by 2004, and I would eventually, relucantly, capitulate and try Gnome again in 2008.  More or less just in time for Gnome and Canonical to blow everything up again!

Ironically, over time, there has been less need to use other peoples’ computers.  Besides which, I have kept using Dvorak for 20+ years now, despite that being a much bigger issue when switching systems.

Monday, July 25, 2022

How does macOS Keychain determine which app is using it?

Thinking about the differences between macOS and Gnome keyrings, I began to wonder… how does macOS know what the app making the access is?  It obviously can’t be by the filesystem path, or malware could steal keys by naming itself aws-vault and sneaking into the keychain.

According to this Stack Overflow answer, Apple is using the app’s bundle ID to determine this, authenticated by code signing.

That’s an infrastructure that doesn’t really exist on Linux.  Each distro signs its packages, but the on-disk artifacts are generally neither signed nor checked.  That turns it into a much larger problem for Gnome Keyring to tie secrets to individual apps, because first, we’d need to build a secure way to identify apps.

And then, culturally, Linux users would reject anything resembling a central authority.  Developers (including me) don’t usually bother even using GPG for decentralized code signing, and that’s not even an option with the fashionable curl|bash style installers.

Sunday, December 13, 2020

The world is turning upside-down (2006)

Editor's Note: this is a post from my old Serendipity weblog, "Pawprints of the Mind," which was originally posted nearly 14 years ago, on 2006-12-29. Since then, I can't help but notice that social media created itself on a Pull model—follow who you want—and then replaced it with algorithms to Push into that stream. The text below is reproduced verbatim from the original post.

In the beginning, Push dominated.

A company built a product, and it was Pushed to market. Long ago, newspapers pushed by paper boys on the street carried advertisements. Direct-mail catalogs, pushed through the postal service, were nothing but one long and comprehensive advertisement for the company who created it. The rise of radio and television, both one-way broadcast media, allowed advertisements to be pushed to millions at a time, quickly and easily. Movies and music are produced and pushed, and the producers hope they break even.

After a company pushed their product, they spent plenty of money watching what happened to the sales. Was it going to explode or tank? Was the initial 10,000 piece production run going to be liquidated, or was another run ten times the size waiting in the wings? There was no way to sense demand except to Push supply and watch what happened.

Inevitably, Push was brought to the new media: the Internet. Building on the ideas of direct mail, email lists formed. Spam happened. Spam filters happened. Better spam filters happened. But those may be only a temporary solution.

As Pushing got cheaper, more was pushed, until users fled the deluge. Too much yang leaves people wanting yin. Onto this stage stepped Pull.

Nobody knew it was Pull yet. It called itself RSS or reddit, and it was about users coming and getting it. No more HTML-heavy, graphic-packed email stuffed into their Inbox every other day to make up for the poor quality of the site's search capabilities. No more "Insert-Brand-Here Loyalty Updates". No more subscriptions, passwords, bounce processing, and unsubscribing. No more spam, because the provider no longer needs to know where to send anything; they just wait for users to come and get it.

Pull is about user control. Pull is about saying "I want that" and not having some gatekeeper in the way, trying to extract monopoly rents. This is what scares the recording industry; their value as gatekeepers is plunging as alternative ways of connecting bands and fans arise.

Sunday, December 6, 2020

Can Micropayments Even Work? (2007)

Editor's Note: this is a post from my old Serendipity weblog, "Pawprints of the Mind," which was originally posted over 13 years ago, on 2007-05-13. The text below is reproduced verbatim from the original post.

(This is not entirely academic, as a current goal of my day job essentially amounts to implementing a micropayment system.)

I am beginning to believe that the fundamental problem behind micropayments as a viable option for widespread payment is that credit cards are effectively already micropayments. We're just spoiled by cash. Physical currency is limited by reality. There's not a limitless supply to steal, nor can it be readily created. Undetectable counterfeits cannot be manufactured by poking a few bits inside a computer. Rather, it's difficult to produce high-enough quality counterfeits, which is why good counterfeits only come in $100 notes. The run-of-the-mill counterfeiters are stuck trying to figure out how to make a passable $20 out of card stock or ordinary paper, because anything bigger is subject to too much scrutiny for their materials. (Even then, a local supermarket tests all those, pushing the bar down to $10.)

In essence, I suspect the cost of doing business with a credit card company is mostly the cost of implementing imaginary money securely. The more credit processing costs, the fewer shops join in, and the less of the currency marketshare the creditor ends up with. On the other hand, the services can't be priced so low as to be unprofitable. Not to mention, the more that people use their cards, the more interest the creditor can collect at little extra cost, as all the billing and accounting framework was already in place for that cardholder anyway. Charging less makes economic sense for them, even if they were a monopoly.

A credit card company ends up shaving a few percent off transactions made through them. Micropayments want to be the same thing, only smaller: shave a few percent off penny-sized transactions and make up for it by volume. But the micropayment competes with the credit gateways, if one of the main ways of getting money into the system is to purchase microcurrency on a credit card. Inside the system, the shaving has to be high enough to make up for the transaction cost of the microcurrency being bought and sold, as well as the real costs of doing the transaction and turning a profit.

And if micropayments are essentially equivalent to real currency, then they're also equivalently desirable for fraud, stealing, and counterfeiting: something the large creditors are spending plenty of money on for the best and brightest to counteract. This brings up another point: micropayments probably won't have the same amount of consumer trust as credit cards, because personal liability is legally limited to $50 on the cards. This is not the case for micropayments, which is going to make people not want to have too many of them at one time. That in turn limits the total amount of microcurrency that can be circulated, and restricts the market for higher-priced microsales.

Is it possible to best Visa and MasterCard at their own game?

Sunday, November 15, 2020

State of the Linux Desktop (2009)

Editor's Note: this is a post from my old Serendipity weblog, "Pawprints of the Mind," which was originally posted nearly 12 years ago, on 2009-05-18.  History since then has unfolded differently in some details, but the broad strokes seem to be accurate.  The text below is reproduced verbatim from the original post.

The Linux desktop is a curious thing. Years ago, the annual prediction was that that year was finally going to be the Year of the Linux Desktop, and Windows would be kicked out of market dominance for good. World domination by open source, and all that.

Linux has come a long way since then. Monitors can be largely auto-configured, fonts can be anti-aliased, CDs can be burned without fiddling with ide-scsi, USB works without having to care about your kernel version, and even media keyboards and mice with tilt-wheels seem to work these days.

But the "desktop" has come a long way since then, too. Various OS X versions introduced technologies like Display PDF, Quartz Extreme, Exposé, and other things that Windows Vista copied with WPF and Aero. Linux eventually duplicated them in Compiz, Beryl, Compiz-Fusion, or something. Somewhere in there. It kinda-sorta works now, if you don't want thumbnails of minimized windows.

Now that Linux has joined the current decade, Microsoft is readying Windows 7, with features like thumbnails of windows on the taskbar (with Aero), the 'recent documents' of an application available from the taskbar button, and so forth. Apple certainly has their own plans. And both of them have decent sound and MIDI support, where starting up one audio application is actually not likely to silence another's sound.

So, the "Linux Desktop" is still behind, and always has been. One problem here seems to be that it's not about innovation. It's about copying everyone else's modern technology with ancient components. It's about solving problems again that already have better solutions in other systems, just to see how closely Linux can approximate them with its decades-old core design.

And then someone, or maybe a few people, whine about the solution and come up with an alternative. The alternatives vie for dominance, and the rest of the desktop world moves on while the Linux landscape settles into one predominant choice, if they're lucky. If they're unlucky, you get things like the KDE/Gnome situation.

Due to Linux's philosophy about neither inventing wheels nor including batteries, there's a large number of components with their own maintenance and release schedules, and most of them target "current" versions of other components. For any given complex program, there's a relatively small window of time between the components it uses being released, and becoming obsolete with future releases. Every time components break compatibility, a new version of all programs dependent on them have to be released to deal with the changes. The more changes dealt with, the more complex the program becomes, so compatibility with older versions also gets cut out after a time.

And sometimes, a sweeping change comes through, and no compatibility is maintained between the two versions: App 2.0 will run on Foo 3.0 and newer, and App 1.4 will only run on Foo 2.5 and below.

From a software developer's point of view, then, supporting Linux is a risky proposition. You have to either watch the work in progress on the entire stack, and guess what will be completed and be important to your application, or you end up being taken by surprise when one of your components updates and your application doesn't run on an ever-growing range of Linux systems until you have time to update it.

Apple and Microsoft may have their own problems, but they have the clout and the guts to say, "We need to migrate to doing things this way, and it'll be good for at least 5 years." Look at Windows 95–Me, or NT4–XP. Whereas the rate of change in Linux effectively limits compatibility to about a year at the most. So most serious software gets developed for other platforms, and most serious users are on those platforms as well. Then familiarity begets desire for those platforms over Linux.

In short, Linux is sort of the Perl of operating systems: messy and aging. People working on Linux desktop technologies seem to be doing it to prove that they can. And secretly, they hope to get horses fast enough to put that Ford guy out of business.

Sunday, August 20, 2017

Types as Communication

In my last post about static typing, I missed something.

My current employer is larger than any previous employer I’ve worked with, at least on the tech team side, and I’m getting a lot more interaction with other programmers.

Mostly, they’re a pain… because I have a tendency to nano-optimize for fast. Following the ground rules, my PHP code is fairly likely to cheerfully Do The Wrong Thing™ if it’s passed some incorrect type. It might leave Important Data blank, or outright crash.  My general attitude was, “Don’t do that, then!”

But I can also see that it’s a drag on other people.  They write code, it looks reasonable, maybe it even runs, but it quietly gives an unexpected result.  I wrote some code that took an int to pack into something. When it received a string, it would silently pack 0 instead.  Fortunately, the developer realized they were making an assumption, and checked it before that bug made it toward testing or production.  A different developer may have rushed on ahead and released it.

This leads to an intriguing property of static typing: the types become an additional point of documentation between programmers.  And unlike doc comments, they never go out of date if the compiler insists on their correctness.

The stronger the type system, the richer that communication is.

Which means that the most interesting comparison is not along the lines of Python vs. Java, but Python vs Haskell.  How easy is it for a team to work on a Python codebase, compared to Haskell?  How easy is it when the code is 2, 5, or 10 years old?

Saturday, July 8, 2017

Trying F# for static types and functional programming

Between all the ado about monads and rereading a literature review of static vs. dynamic typing on Dan Luu’s blog, I decided to take another swing at both static typing and functional programming in one go. I built a thing with F# because, well, I’m not really sure.  It sounded cool, and F# for fun and profit had a lot of pragmatic articles about it.

Tuesday, February 23, 2016

PGP

For the first time in over fifteen years of awareness about PGP, I met someone who actually wanted to use it.  I got to set trust on a key and see this awesome menu:
Please decide how far you trust this user to correctly verify other users' keys (by looking at passports, checking fingerprints from different sources, etc.)

1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately

This reveals a lot about the assumptions of PGP and the problem it was trying to solve...

The menu clearly focuses on real-world identities, trying to get users to establish ‘trust’ that people correspond to the cyber-space identities. (Those digital identities are the keys: anyone with the key is indistinguishable from anyone else who has it.) Why else is the focus on “verifying” by looking at passports and fingerprints?

In short, PGP was the first Google+: built by nerds as an identity service for the masses… that failed to become mainstream.

Saturday, September 5, 2015

Templates and DOMs

In my last post, I mentioned my ideal of keeping “HTML” generation as operations on a DOM tree, instead of assigning variables to templates and using string substitution. Parse the initial template file, fill it with data, then render it once with safe encoding (where relevant) at the end.

I also know why this approach isn’t as popular: everyone hates the DOM.

Thursday, November 27, 2014

Versioning

Dan Tao asks, “In all seriousness, what’s the point of the MINOR version in semver? If the goal is dependency stability it should just be MAJOR and PATCH.”

I think I finally remember the answer. It’s set up to flag no compatibility, source compatibility, and binary compatibility. The “thing” that dictates bumping the minor shouldn’t be “features” so much as binary-incompatible changes. For example, GTK 2: if code was written against 2.4.0 using the shiny new file chooser, it would still compile against 2.12. But, once it had been compiled against 2.12, the resulting binary wouldn’t run if 2.4 was in the library path. A binary compiled against 2.4.2 would run on 2.4.0, though, because every 2.4.x release was strictly ABI compatible.

IIRC, they had a policy of forward compatibility for their ABI, so that a binary compiled against 2.4 would run on 2.12, but I don’t remember if that’s actually necessary for SemVer. Another way to look at this is, “If we bump the minor, you’ll need to recompile your own software.” Where that could be programs using a library, or plugins for a program.

I believe that’s the motivation for SemVer to include minor, but upon reflection, it doesn’t really make sense in a non-binary world. If there is no binary with baked-in assumptions about its environment, then that layer isn’t meaningful.

Also upon reflection, most of my currently-tracked projects don’t use SemVer. The AWS SDK for PHP is (in 1.x/2.x) organized as “paradigm.major.minor”, where 2.7 indicates a breaking change vs. 2.6 (DynamoDB got a new data model) but e.g. 2.6.2 added support for loading credentials from ~/.aws/credentials. PHP itself has done things like add charset to the PDO MySQL DSN in 5.3.6. When PHP added the DateTime class, it wasn’t a compatible change, but it didn’t kick the version to 6.0.0. (They were going to add it as Date, but many, many people had classes named that in the wild. They changed to DateTime so there would be less, but not zero, breakage.)

So I’ve actually come to like the AWS 2.x line, where the paradigm represents a major update to fundamental dependencies (like straight cURL and calling new on global classes to Guzzle 3, namespaces, and factory methods) and the major/minor conveys actual, useful levels of information. It makes me a bit disappointed to know they’re switching to SemVer for 3.x, now that I’ve come to understand their existing versioning scheme. If they follow on exactly as before, we’ll have SDK 4 before we know it, and the patch level is probably going to be useless.

I think for systems level code, SemVer is a useful goal to strive for. But the meta point is that a project’s version should always be useful; if minor doesn’t make sense in a language where the engine parses all the source every time it starts, then maybe that level should be dropped.

At the same time, the people that SemVer might be most helpful for don’t really use it. It doesn’t matter that libcool 1.3.18 is binary compatible with libcool 1.3.12 that shipped with the distro, because the average distro (as defined by popular usage) won’t ship the newer libcool; they’ll backport security patches that affect their active platform/configuration. Even if that means they have effectively published 1.3.18, it’ll still be named something like 1.3.12-4ubuntu3.3 in the package manager. Even a high-impact bug fix like “makes pressure sensitivity work again in all KDE/Qt apps” won’t get backported.

Distros don’t roll new updates or releases based on versions, they snapshot the ecosystem as a whole and then smash the bugs out of whatever they got. They don’t seem to use versions to fast-track “minor” updates, nor to schedule in major merges.

One last bit of versioning awkwardness, and then I’m done: versions tend to be kind of fuzzy as it is. Although Net::Amazon::DynamoDB’s git repo has some heavy updates (notably, blob type support) since its last CPAN release, the repo and the CPAN release have the same version number stored in them. When considering development packages in an open-source world, “a version” becomes a whole list of possible builds, all carrying that version number, and each potentially subject to local changes.

Given that, there’s little hope for a One True Versioning scheme, even if everyone would follow it when it was done. I suspect there’s some popularity around SemVer simply because it’s there, and it’s not so obviously broken/inappropriate that developers reject it at first glance. It probably helps that three-part versions are quite common, from the Linux kernel all the way up to packages for interpreted languages (gems or equivalents).

Saturday, June 7, 2014

Musing on Iterator Design

PHP’s standard library (not the standard set of extensions, but the thing known as the “SPL”) includes a set of iterators with a kind of curious structure.

At the root is Traversable, which is technically an empty interface, except that there’s some C-level magic to enable C-level things to declare themselves Traversable. This enables them to be used in foreach loops even though they don’t support any Iterator method.

Iterator exists as the basic interface for regular PHP code to implement iteration, internally. Notably, while Traversable is a once-only iterator, Iterator is not. rewind() is part of its interface.

For classes that wrap a collection, there’s an IteratorAggregate interface, which lets them return any Traversable to be used in their place. And who could forget ArrayObject, since a plain array (in spite of being iterable in the engine) is not actually a valid return from getIterator()?

There are some interesting compositions, like AppendIterator, which can take multiple Iterators and return each of their results in sequence. AppendIterator is a concrete class that implements OuterIterator, meaning that it not only provides regular iteration but the world can ask it for its inner iterator.

There’s the curiously named IteratorIterator, which I never appreciated until today, when I tried to pass a Traversable to AppendIterator. For no apparent reason, AppendIterator can only append Iterators, not Traversables. But IteratorIterator implements Iterator and can be constructed on Traversable, thus “upgrading” them.

Long ago discovered and just now remembered, PHP provides DirectoryIterator and RecursiveDirectoryIterator—but to make the latter actually recurse if used in a foreach loop, it needs to be wrapped in RecursiveIteratorIterator, because the caller of a plain RecursiveIterator must decide whether to recurse, or not, at an element with children.

The designer in me thinks this is all a bit weird. Because PHP defined the basic Iterator as rewind-able, a bunch of stuff that isn’t rewind-able (including IteratorAggregate) can’t be used in places that expect a base Iterator. Like AppendIterator. That in turn exposes a curious lack of lazy iterators. When I wrap an IteratorAggregate in an IteratorIterator, getIterator() is called right then, before the result can even be added to an AppendIterator.

So if I want to fake a SQL union operation by executing multiple database queries in sequence, and I don’t want to call the database before the AppendIterator reaches that point, there’s no simple way to do it with SPL’s built-in tools.

I can build a full Iterator that doesn’t query until current() is actually called, by implementing a handful of functions, each of which must carefully check the current iteration state before returning a value. These would satisfy the native AppendIterator, but be lazy themselves.

Or, I can build a full LazyAppendIterator that accepts Traversable and doesn’t try to resolve anything until the outer iteration actually reaches them. Then I can add IteratorAggregates that perform the query in getIterator(), since I won’t be calling that right away.

Those two choices amount to the exact same amount of work. In each case, I need to build a lazy iterator that tracks the “current iteration state” and launches the expensive call only when starting a new iterable/iteration sequence.

In other languages I’ve used, the basic one-pass/forward-only iterator is the type accepted by all the compositing types, and everyone must live with the idea that the iterators in use may not be seekable/replayable. In PHP, I have to live with the idea that the not all iterable things may work with all Iterators, which seems supremely odd.

P.S. They didn't pack any RegexFilterIterator in the box, either?

Friday, January 11, 2013

Fun, Work, Puzzles, and Programming

Some programming tasks are just more fun than others. The same thing extends to languages—why are Perl and Ruby so much more fun to work with than Python?

I suspect that the answer lies in the scope of the solution space, in a sweet spot between “too straightforward” and “too complex.”

Monday, October 29, 2012

When Layering Goes Bad

A lot of systems are built in layers.  Games are often split into engines and scripts.  Another classic is the "three tier" architecture with data storage, application model, and view-controllers split out onto individual machines.

But more often, I run into systems where code is taking a core sample instead of building on the layers.