I've just released SCSS 0.4.0, which brings with it some pretty major changes. For one, like the recent release of SDOM, it repackages the code as an R6RS library. Not having to chase Scheme platform-compatibility issues is an incredible relief. But I also decided to change the way queries to the cascade work.
In previous versions, you'd specify a node and a property
whose value you wanted to obtain for that particular node.
The API guaranteed you a non-null response to your query,
even if satisfying it meant that additional computation had
to be done, like extracting a sub-value from a more general
property for use as the value of a more specific property
that wasn't set (e.g., figuring out
border-top-style from the value of
border); or re-using the result of repeating
the query for an alternate, related property (e.g.,
obtaining the value for
color); or just looking up a default value in a
reference table. To offset the significant cost of repeat
lookups to the cascade, which are not cheap by any means,
I'd devised an elaborate system of cascading caches to store
values that were discovered but not currently required.
This worked reasonably well, but brought with it some
frustrating complexity -- for example, those caches had to
be flushed based on criteria external to SCSS, like the
activation of pseudo-classes and pseudo-elements.
So I've decided to ditch all of that internal complexity at the cost of passing on a fraction of it to the user of the API: I've modified the selection API such that you no longer ask about specific properties, and you get back the complete set of property values that have been assigned to the node. If you need to increase their specificity or look up a default value, there's an auxiliary API for doing those things. It's already had a positive impact in the only client of SCSS that I know of, libRUIN, enabling some more accurate inheritance behavior, and allowing me to scrap a major swath of CSS lookup code that was coupled to assumptions about the way SCSS worked. It would be nice to think that I've reached a point in my development as a software designer that I could afford to make some tentative pronouncements about "best practices." So: APIs that purport to hide, in one shot, all of the complexity that's inherent in a particular source of data are almost certainly not going to be able to make good on that claim. Better to design software that addresses the problem in layers, with each layer solving a very small part.
Another pronouncement I'd like to make is that there's a lot of benefit to be had by taking advantage of language features for structuring data. I'd been relying on Scheme lists for modeling pretty much everything in the system, from the arguments to the value selection calls to the intermediate result values passed around internally. I've since switched those things over to use R6RS records, which makes reasoning about the input and output of functions a lot easier. There used to be a half dozen inputs to the selection API functions, many of them strongly related; I've grouped them into records such that there are now two arguments, one of which will often be invariant over a single application's use of the API.
2.0 is nearly upon us! The release is scheduled for the second week of February. I'm pretty excited about it, given that it represents several years of sporadic work by me, not to mention years of more consistent efforts by lots of brilliant and talented people. We're trying to figure out how to frame the transformative nature of this release -- Guile's finally become what it set out to be, an actual scripting language platform. Now we have to figure out how to communicate that to people. This is where marketing comes in, I suppose.