Previous Entry Share Next Entry
Release -- major Property-access enhancements
jducoeur wrote in querki_project
Today's release is the outgrowth of a conversation I had yesterday with Eric, in which he observed that Model Properties are kinda great and kinda awful. In particular, he was being limited by the fact that a Model Property can't use the other Properties defined on the Thing that is *using* that Model Property. He had a specific, entirely reasonable example of what he wanted to do (outlined below), and made a good case that this was a general problem. I wound up agreeing, and rolled that into some other changes I've been thinking about for a few months now.

The change is primarily about Property Resolution. That is, when I give a Property name in a QL expression, what Thing do I fetch that Property from? Previously, we only had two fairly obvious sources of the resolution: the received and defining contexts. Now, we are adding the lexical context, as well as sometimes walking up the context chain and looking for outer scopes. Let's go into some detail on all this.

There are now four different places where a Property Value can come from, when you are looking at a QL expression. The first is the defining context:
[[My Thing -> My Prop -> Other Thing.Some Text]]
In this example, Other Thing is an explicit defining context -- it says outright where to load Some Text from. This will feed "My Thing.My Prop" into "Other Thing.Some Text". This is newish -- while the defining context has existed in a few restricted circumstances (such as Functions) for a long time, this makes it more generally usable. If there is a defining context, it will be used, and nothing else will be tried.

The most common option is the received context that is passed to the Property:
[[My Thing -> My Prop]]
In this example, My Thing is called the "received context" because My Prop receives it. If My Prop is defined on My Thing, we fetch that. Most QL expressions use the received context, and I expect that will continue to be true -- most of the time, it's the obviously correct answer.

Completely new is the lexical context, which is tried if the previous two fail to find a Property. Say that My Model defines a Function named My Func, and has an instance named My Instance. The latter can now say:
[[Some Other Value -> My Func]]
In this example, Some Other Value will be passed into My Instance's definition of My Func. This is exactly what you would expect, since it is the way most languages function, but it didn't previously work -- until now, you had to explicitly say "My Instance.My Func". So basically, this enhancement means that methods now work as you expect -- it fixes a design bug that bitten *me* on the ass dozens of times, and I suspect would have annoyed the rest of you before long.

Even newer (only designed yesterday) is the truly radical enhancement: outer context scopes. This one gets pretty complicated, but is the one that Eric had run into, and which I've had problems with myself. The problem was mainly in Model Properties -- that is, complex data structures that are defined with a Model. Until now, Texts and Functions in these complex data types had no way of accessing information about the Thing or higher-level Model Properties that contained them. My concern was a bit more abstract than this, but still serious in the long run: there was basically no way to "parameterize" a Model Type, which was ultimately going to limit us a lot.

For an example, let's take the specific problem Eric was dealing with: in his Review Type, he wanted to be able to display the current average value of these reviews. The problem is, the Review Summary (from which you generate the average) is stored on the Thing being reviewed, and wasn't available to the Review itself, since that was a Model Type. Now, however, the Review can say:
Avg: [[Review Summary -> _average]]
That seems intuitively obvious, but what's actually going on here? Review Summary isn't defined on Review -- it's defined at a higher level. So how do we get to it?

The new mechanism is "walking the context chain". To get here, the outer Thing said
My Review -> _edit
My Review, in turn, defines an Instance Edit View that contains the code shown above. So we essentially get a chain of contexts, basically the Querki version of a call stack:
My Thing -> My Review -> _edit -> Instance Edit View -> Review Summary
This chain has always existed internally, but it has never been user-visible before. The new code is specifically designed to allow "enclosed" scopes to access "containing" ones. When it tries to access a Property, if it isn't defined in any of the above-described ways, it steps *backwards* on the stack and tries again. It repeats this until either (a) it reaches the top of the stack, or (b) it reaches a Thing.

Note that this context-walking mechanism isn't perfect -- I can think of a few things it specifically can't do yet. But it should give you most of the concept of "scoping" that Querki has been lacking, and allows inner Types to parameterize themselves by using Properties that they don't define, so that their containers must do so. It's a pure power-user feature, but a major step towards considering Querki a Real Language.

IMPORTANT: These changes are powerful juju -- I've taken one of the relatively ad-hoc aspects of Querki, and made it both much more regular and much more powerful. It would be *astonishing* if there weren't some knock-on bugs remaining -- as it is, I've done four releases today to fix bugs as I've thought of them. The _edit powertrain, in particular, received some critical enhancements. I think that all of this is for the better: I was forced to make some improvements that I've been considering for a long time, in order to pass the context chain around more consistently. But more bugs are likely -- it is possible that some existing code might break, and likely that there are some edge cases remaining where the above logic doesn't work right. Please give a yell if you find problems.

Aside from that huge change, there have been lots of little fixes since 0.8.5. (There have actually been seven releases in the past three days.) These include:

Better handling of zero-length Names: the current UI makes it a lot harder to wind up with a Thing with an empty Name, but it's still possible, and the resulting Things were difficult-to-impossible to navigate to: they existed, but you had nothing to click on to get to them. We now detect this situation more consistently at rendering time, and fall back to showing the Thing's OID as a last-ditch option.

Fixed Model Values when Creating a new Thing: this appears to have been a long-standing bug. If you used the old-style Editor to create a new Thing, and that Thing contained Model Properties, and you set fields in those Model Properties, some of those fields would be semi-randomly lost. The only reasons we hadn't caught this bug before were (a) it only happened on create; (b) it only happened in the old-style Editor, not the newer Instance Editor; and (c) only *some* fields would be lost. So it showed up as an occasional and hard-to-detect "didn't I fill that in?". This should now work correctly.

URLs can now contain %: surprisingly, this has never been allowed before and we hadn't noticed it. This is now properly legal.

_isDefined now works correctly with Tags: my unit tests for _isDefined (which returns true iff the name passed into it is a real Thing) turned out to be insufficient, and it has never worked correctly with the new Tag Type. That is now tested and fixed.

Whitelisted the <br/> tag: with the addition of the !+noLines flag in QText, it becomes useful to be able to insert your own explicit line breaks. This works as expected, *but* please note that you should use the modern XHTML <br/> form, not the older <br> form -- the latter may cause errors because it looks like a mismatched tag.

As a rule, please assume that you must follow XHTML conventions for all explicit tags. Also, please note that the error messages for poorly-formed XHTML are terrible -- I've entered a bug against that, but for now, be careful.

That was a *big* distraction, but I think the improvements should pay off bigtime in the coming months. Please tell me about any problems you find...
Tags: ,


Log in

No account? Create an account