Array literals and script only stack initialization (was Re: Developing first on android)
Mark Waddingham
mark at livecode.com
Mon Aug 21 05:58:27 EDT 2017
On 2017-08-21 01:31, Monte Goulding via use-livecode wrote:
> Right now you need to handle preOpenStack in stack A and setup the
> hierarchy because stack B does not retain the behavior property when
> saved and does not get any kind of message when used as a behavior. It
> may actually be a good idea to add a loadBehavior and unloadBehavior
> message sent to the object using the behavior so it can initialise its
> own heirarchy. Still I think saving the behavior property with the
> script only stack is a simpler solution.
I think its been suggested before that a 'loadStack' message might be
quite useful (perhaps it should be 'createStack' - we have 'deleteStack'
which is probably sufficient for the antonym) - allowing a stack to 'do
something' when it is loaded into memory, and then unloaded (equivalent
to OnCreate / OnDestroy in LCB) as loading/unloading is a slightly
different part of the life-cycle compared to opening and closing.
I can certainly see that it would be a 'simpler' solution in some ways
to save the behavior property - however, then it isn't 'just' a script
anymore - it is actually just a cut down object, so that leads us into
having general properties / structures encoded in a 'script only stack'.
I was playing about with prototyping something yesterday - array
literals - it has been suggested before (indeed I thought there was a
partial attempt by someone before - but I couldn't find it) but I
thought it would be interesting to try it:
https://github.com/livecode/livecode/pull/5824
Basically this patch adds JSON-like (which is LCB-like too!) syntax for
sequence (numerically keyed array) and array (associative array)
literals:
put [ 1, 2, [ 3, 4, { "size" : the length of tOtherSeq } ] ] into
tSeqVar
put { "foo" : "bar", "baz" : tMyValue , tMyKey : [ 1, 2, 3 ] } into
tArrVar
The syntax is the same as in LCB - keys and values can be static or
constant. The implementation has the nice property (well, the sequence
version does - the array one isn't quite finished yet) that actual
constant literals (those which have constant key/values which can be
evaluated at compile time) will share the value. i.e.
put [ 1, 2, 3 ] into tSeqVar1
put [ 1, 2, 3 ] into tSeqVar2 -- this will actually share the
in-memory value with tSeqVar1
This means that you can explicitly write the same constant anywhere, as
much as you like in script and still only have one instance of it.
Indeed, the performance of using array literals compared to separate
'put' statements to construct them is quite encouraging:
BenchmarkStartTiming "LegacyCreation"
repeat kRepetitions times
get empty
put true into tLegacyLiteral[1]
put 1 into tLegacyLiteral[2]
put pi into tLegacyLiteral[3]
put "Hello" into tLegacyLiteral[4]
put false into tLegacyLiteral[5]
put 2 into tLegacyLiteral[6]
put pi into tLegacyLiteral[7]
put "World!" into tLegacyLiteral[8]
put it into tLegacyLiteral[9]
end repeat
BenchmarkStopTiming
BenchmarkStartTiming "ConstantCreation"
repeat kRepetitions times
get [ true, 1, pi, "Hello", false, 2, pi, "World!", [ true, 1, pi,
"Hello", false, 2, pi, "World!" ] ]
end repeat
BenchmarkStopTiming
BenchmarkStartTiming "LegacyDynamicCreation"
repeat kRepetitions times
put empty into tLegacyLiteral
put _Identity(true) into tLegacyLiteral[tOne]
put _Identity(1) into tLegacyLiteral[tTwo]
put _Identity(pi) into tLegacyLiteral[tThree]
put _Identity("Hello") into tLegacyLiteral[tFour]
end repeat
BenchmarkStopTiming
BenchmarkStartTiming "DynamicCreation"
repeat kRepetitions times
get [ _Identity(true), _Identity(1), _Identity(pi),
_Identity("Hello") ]
end repeat
BenchmarkStopTiming
Note: In the 'LegacyDynamicCreation' test variables holding actual
numbers and not numeric literals are used as that is a fairer test with
how things work at present (a technical detail - literals such as 1 are
actually stored internally ready for being used as an array key; whereas
dynamic creation has to create a key from the actual index 1).
On my machine I get the following results:
LegacyConstantCreation 3037 ms
ConstantCreation 53 ms
LegacyDynamicCreation 10330 ms
DynamicCreation 6496 ms
So there's certainly a significant performance advantage.
My only concern is introducing more symbols. There is another option
here using ( ) can also be made unambiguous:
( expr ) - grouped expr
( expr , ) - single element sequence
( expr : expr ) - single key/value
However, I wonder if this is a bit too subtle - it would be all too easy
to use ( expr ) for when you actually want a single element list - no
amount of context can really help here.
This also overlaps with recent discussions about strings. The syntax of
literals above is the same as JSON (and can be made compatible with
Python, just by allowing a trailing ',' in lists) *except* that LCS
strings are not escaped so they aren't necessary copy/paste comparison.
Therefore it does suggest that making "..." escaped strings as
cross-compatible with other languages as possible is maybe something to
seriously consider (if we wanted Python cross-compatibility '...' type
strings would have to be too - although Python has about 6 variants of
strings, you can use letter prefixes before the quote to change the
interpretation of the string).
Anyway, getting back to the original point of the original post... The
reason this might be of interest to the problem of script only stacks is
that with a suitable 'loadStack' type method, you could do something
like:
on loadStack
set the properties of me to { \
... key/value pairs of properties ... \
}
end loadStack
Indeed, if we had a better 'properties' property (i.e. as suggested by
me in terms of import/export array - something allowing you to get/set
the core persistent state of an object directly) then you could have
script-only-stacks which *also* contain their state (and, by collorary,
state of objects on the stack) - via having code which does it.
Warmest Regards,
Mark.
--
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps
More information about the use-livecode
mailing list