
![]() |
Show Changes |
![]() |
|
![]() |
Recent Changes |
![]() |
Subscriptions |
![]() |
Lost and Found |
![]() |
Find References |
![]() |
Rename |
![]() |
Administration Page |
| Search |
History
| 9/12/2007 4:02:15 PM |
| -10.10.192.22 |
| 8/19/2007 6:56:30 PM |
| -66.78.124.101 |
![]() |
List all versions |
Related Topics
WikiTalk is a pretty simple and straightforward language, which is a good thing for what it does. However in building some data-driven wiki pages I've come to find it a little too simplistic. For example, say i want to conditionally build either a table from an array or a string that says "no data".
Assuming that x generates the array & y generates the table from the array, i can always write something like
{ ... |
x(...).IsEmpty.IfTrue {
y(x(...))
} IfFalse {
"No Data"
}
}
This is well and good, unless x is something that's expensive to compute, at which point i'm being forced to evaluate it twice just to provide good output.
One solution is to nest blocks in order to work around this (thanks to WardCunningham for pointing that out to me). So you could write:
{ ... |
{ x' |
x'.IsEmpty.IfTrue {
y(x')
} IfFalse {
"No Data"
}
}.Value(x(...))
}
(ignoring that ' probably can't be part of a symbol name)
We could even formalize this in a function:
{ ... |
x(...).If {
x' | x'.IsEmpty
} ReturnSelfElse {
"No Data"
}
}
Where IfReturnSelfElse would evaluate the first block on "this" and return either "this" or the value of the second block depending on the result.
As part of my operator exercise to learn the wikitalk code base, i was also considering adding in:
My thinking is that a mutable symbol would be either a block local variable, or one defined in part of a new "mutable" scope using a method similar to the With method. For example, the code could be something like:
{ ... |
Local(Array x') {
x' := x(...);
x'.IsEmpty.IfTrue {
y(x')
} IfFalse {
"No Data"
}
}
}
The ; notation requires a new type of parse tree node that can hold 1 or more expressions together in a chain. It evaluates each in order with the same scope, then returns the value of the last one.
The Local(...) method would create a new type of scope, one that implmented the IMutableScope interface. This has an extra method on it (beyond IScope) that allows the modification of a symbol in the scope.
The := "operator" would expect its lvalue to evaluate to a symbol (or perhaps some day later a property on a symbol, but right now those are jsut methods and are immutable), and the rvalue to be an expression. It would look to see if the current scope implemented IMutableScope and, if it did, would assign the new value to it.
To transfer values back out of scope, you would need to have that value as the last expression in the chain. As a contrived example:
{ ... |
Local(z) {
z := Local(Array x', returnValue) {
x' := x(...);
x'.IsEmpty.IfTrue {
returnValue := y(x')
} IfFalse {
returnValue := "No Data"
};
"||" + returnValue + "||"
}
}
}
DavidOrnstein suggests a syntax that i like much more, though i need to read through the code to see how it's going to work. It also brings up the question of whether block arguments should be mutable, or only block local variables.
Following the arguments for a block, you could have the local variables for a block in parenthesis (or some other character marker). This avoids the extra Local() blobs and keeps all the locals for a block in one spot - between the starting brace and the bar:
{ ..., (String z), (Array x') |
x' = x(...);
x'.IsEmpty.IfTrue {
z := y(x')
} IfFalse {
z := "No Data"
};
"||" + z + "||"
}
Please let me know what you think.