Previous Entry Share Next Entry
What's in a Call?
jducoeur wrote in querki_project
[This one's for the programmers.]

In the wake of our discussion about the new _edit() command the other day (and now that I've implemented that and am rapidly adding more commands), I think it's time to talk a bit about Calls and how they work in the QL language.

If you recall, QL is mainly a pipeline language, passing a "context" from hand to hand:
[[My Thing -> My Property -> ""The property's value is ____""]]
Each of those arrows represents a context being passed from one Stage to the next; each one transforms the context in some fashion and moves on. This example starts by specifying a Thing, fetching a Property from it, and embedding that value inside a text output.

That works well for the 90% case, where we're doing simple transformations -- the result is a language that is extremely light and easy for the most common cases. But how do we deal with less-common ones? That language is still evolving (indeed, I was up until 1am last night sketching out the syntax for closures), but in many cases the answer will be Calls.

While most Stages *look* they are simply naming a Thing, in fact each one is a method call. Simply naming a Thing calls the "apply" method on that Thing (terminology taken from Scala, on the theory of "steal from the best"). Thing.apply() simply returns a pointer to that Thing. Property.apply() expects the incoming context to be a Thing; it fetches this Property's value from that Thing, and passes it into the outgoing context.

Sometimes, though, you need to do something fancier -- for now, that means Internal Methods. These are built-in functions that are available throughout Querki. For the moment, they're all implemented in raw Scala code -- eventually I'll make it more possible to build these things in QL yourself, but that'll require more language refinement. I added two this week, and they illustrate the language in different ways.

The first is _edit(), which we discussed before:
[[My Property._edit]]
(Tangent: since Querki has a flattish namespace, I am promulgating a convention that system names start with an underscore, and that user names shouldn't do so. That's a crude but reasonably clear way to reduce accidental name conflicts.)

That "._edit" is, again, a method call. The really important part, though, is the ".". This is how you identify the method to apply to the named Thing, if you don't want to use apply(). So in this case, we are calling _edit() on My Property, and passing in the root context. (That is, the Thing that we are displaying, which is usually the start of the pipeline.) _edit spits out the necessary HTML to edit that Property on this Thing, with the current or default value filled in, and the AJAX hooks needed for it to update the server when it changes.

That latter bit was my favorite enhancement for the week. For the Wedding RSVPs, I *really* didn't want invitees to have to click a "Done" button -- that just feels clunky. Nowadays, folks expect to be able to click a button or fill in a field online, and have it just *work*. There's no excuse for Querki to not follow suit, so I've now implemented that: the _edit() command is now live-updating. So you can basically make any display of any Thing dynamic, simply by using _edit.

Of course, there's nothing special about _edit from a language point of view -- for instance, you can just use it in a list context and it will Just Work. To take an example that I'm planning for the Wedding App, say that an Invitee can have a list of Children. On the Invitee's page, we can say:
[[Children -> ""* [[Name]] -- [[RSVP._edit]]""]]
That is, for each child, we show a bullet item with their name, and an edit control for their RSVP. That way, parents can handle their children's RSVPs easily. (I'll probably do the same thing for spouses -- expecting both members of a couple to RSVP separately is unrealistic.)

Then there are parameters, which are best illustrated by the _section() command:
[[My List -> _section(HEADER, DETAILS, EMPTY)]]
This deals with what I've found to be an *enormously* common usage in Querki: displaying a List as a section of the page. The three parameters are sort of what you would expect, but there are a bunch of interesting nuances:
  • HEADER is printed first, as the header of the section -- its Context is the list itself, as a whole

  • DETAILS comes next, repeated once for each element in the incoming List as its Context

  • EMPTY is printed instead, if and only if the incoming List is empty
As usual, the objective is to DWIM -- the system should work as easily and intuitively as possible. But that has all sorts of interesting implications.

One of the most important and subtle is that the parameters to _section are (essentially) passed by name, not by value. In a typical programming language, parameters are passed by value -- the language evaluates the parameters *first*, and then calls the outer function call only once all of the parameters have been evaluated, passing in the resulting values of evaluating the parameters.

But that doesn't make sense in Querki, since frequently the point of the call is to be evaluating the parameters with a context constructed by the call. For example:
[[Children -> _section(
""## Your Children ([[_count]])"",
""* ____ -- [[RSVP._edit]]"",
""You don't have any children that I know of"")]]
That is, the whole point of _section is that it is transforming the context, and then evaluating the parameters in the resulting context. So we can't evaluate the parameters *before* making the call -- that would be silly and pointless.

This stuff is still evolving, and may yet become more flexible. When you look at it closely, it becomes clear that _section is more like a macro (in the modern hygenic-macros sense) than a function call -- it's a consistent way of adding a new syntactic structure. I expect that'll be somewhat common in Querki, but maybe not overwhelmingly so. It is fairly straightforward to take a call-by-name and treat it like a call-by-value (just start by evaluating the parameters in the outer context), but if it turns out to also be common to want call-by-value, we may add the ability for a method to declare how to treat its parameters. (Wouldn't be a shocking thing to want, but I'm not going to add it unless it turns out to be needed.)

*Whew* -- okay, enough for today. Congratulations to anybody who followed all of that -- it's the result of weeks of thinking, design and implementation, to figure out the underlying principles of method calls in Querki. It's not done yet, but it's starting to feel and work right. Comments, as always, are invited...

  • 1
I will say that a lot of people are still more comfortable with a done/submit/save type button. It let's them feel a sense of closure that they've completed their task, and also that they have informed the system they have completed the task. IT also provides some reassurance that the system has received their input, and also signals to the system that they are done with the task and can be returned to their previous context.

Also, The macro thing -is- very cool. Just to confirm.

Edited at 2013-05-17 05:18 pm (UTC)

I will say that a lot of people are still more comfortable with a done/submit/save type button.

It's true, and there are some circumstances (eg, anything transactional in nature) where it is a Very Good Idea to do things that way.

Truth to tell, I am still vacillating on this point. I'm reasonably sure that Querki needs to *support* dynamic AJAXy fields, and I think I'm going to make them the default, since they DWIM best. But I suspect we'll also need a very easy way to define a form with a submit button.

(It *may* be sufficient to simply have a [[Done Button]] -- if you include that on your page, it turns into that kind of form. But we're going to need to run a lot of scenarios to see if that works.)

Also, The macro thing -is- very cool. Just to confirm.

Thanks. This is one of the examples of how useful it was, having worked with ProWiki (the prototype) for ten years before starting Querki. I knew that the Section Pattern is *ridiculously* common (I use it not just in every app, but for bloody near every major model), so I needed to make it as simple as possible to do it. From there, it turned into a language-science question of how best to achieve that.

Right now, I'm pondering how we can make it possible to build macros in Querki itself, with as much flexibility as possible. I think it's going to require being able to specify parameter lists in a *lot* of detail (including whether to treat each parameter as call-by-value or call-by-name), but I am suspecting I can make the system almost arbitrarily powerful and at least adequately usable...

The completion button doesn't need to actually be responsible for saving data. And arguably, it shouldn't be. It's a way for the user to signal completion of the task. You can then return them to context or thank them for submission, or whatever, but you can still be saving data on the fly. Lots of comment systems do this for various reasons that I've seen. You can have all the power of saving data on the fly, preventing lost records, etc, while still scratching that psychological itch to put the pencils down.

Hmm -- good point. We'll have to talk about this one over time: I'm not going to try to resolve it this week. I have mixed feelings here -- it ties deeply into questions like how the Undo system works, whether data is saved continuously or transactionally, and so on. Very likely we'll have to do some serious work, and likely at least some paper prototypes, to come up with the right abstractions and recommendations.

For the short term -- the RSVP buttons and such in the Wedding Invite system -- I'm pretty sure that simple dynamic buttons are appropriate. There *should* be a status bar that says "Saving..." / "Saved", a la Google, but I suspect I'm going to need to initially ship without that, since we really need to get the invitations out the door...

  • 1

Log in

No account? Create an account