-
Notifications
You must be signed in to change notification settings - Fork 223
[[ Feature ]] Array Literals #5824
base: develop
Are you sure you want to change the base?
Conversation
@runrevmark considering you can't set the case sensitivity in script scope I'd say throw an error with exact same case key but treat it as case sensitive otherwise. Probably non-constant array literals should throw a runtime error in the same case and additionally with the if the same key with different casing and the case sensitive is currently false. One thing that would be really cool given this would be referencing previously declared constants. I guess that's going to need some parser support.
|
@montegoulding Yes - having proper expressions in constants would be useful. There's an anomaly there though in that the value of a constant can only be a literal (which means constant kFoo = colon is different from using colon in normal expressions :( ) - http://quality.livecode.com/show_bug.cgi?id=19413. Certainly we can make it so that anything more than a literal is evaluated as an expression, but that would then leave you with:
being different from
However, again, it might be that this is a case where breaking backwards-compatibility is completely justified for the benefit it would bring. I'm wondering lately whether we should start marking stacks with the last engine version they were saved in, and then adding a warning mechanism for subtle changes to things like this. However, the infrastructure needed here isn't insignificant - as we need to make the warnings easily grokable in the IDE. Perhaps this is just another thing we need a 'scriptVersion' type thing for... In terms of the overlapping keys thing then I wonder if that is actually a 'strictness' concern. It needs a bit more thought - however, the underlying implementation to handle the case means we can either make it an error, or make it do 'the right thing' when considered from a strict LTR eval order. i.e. Internally it looks much the same. It very much comes down to whether we want the direct equivalence between:
and
Or not. The advantage of this equivalence, is that existing code can be rewritten to use array literals; rather than lots of puts which has significant performance advantages. |
@runrevmark I assume Anyway, I think I'd be pleased if there were a parser error on multiple case sensitive equal literal keys. That's clearly a user error. As in As far as dynamic or literal keys with different case but in a context we don't know what the case sensitivity might be then I see your point. LTR clobbering of values depending on the current value of |
@montegoulding Yes - that was a typo - now corrected. The keys and values are parsed as expressions which cannot use the ',' operator - just as expressions within a parameter list cannot. So:
Will be a syntax error (missing ':' after tValue2). Whilst we could make it work, you loose the ability to check for missing ':', which is probably more important - as you can just use ( ) to group expressions containing ','. In terms of duplicate keys... How about this:
This does give consistent behavior regardless of case-sensitivity, so it is perhaps the best option - it is also a little easier to implement (as you don't need to keep the order of the constant key/values around). We also now have 'into' forms of union; so you can write 'overlay' type operations in a single line:
|
@runrevmark so do I understand this right:
|
@montegoulding Hmmm - okay - put like that I'm not sure my suggested rules necessarily make sense. How about changing it so that array literals are always built in a case-sensitive fashion? This is closer 'to the truth' - although it is (obviously) opening up a route for coding faults which are hard to spot. Guess this needs a little more thought! |
Hmm... I'll ask this here because I have no idea how long it would take me to work it out from code but is there any level of consistency when you have set an array in a case sensitive context and then access it in a case insensitive one? Any precedence or is it first come first served? What I mean is:
Why I ask is if we have a rule like return the lowercase one or something then we can use that rule to clobber when we setting the array. If there's no rule then perhaps it really should be an execution error to use a case sensitive array in a case insensitive context... |
@montegoulding The caseSensitive property affects the lookup that MCArrayStore/Fetch do - but it all happens with regard hash-order. So, what you get when you lookup a key which has multiple entries (all case-sensitively different), will depend on construction order, array size and what has happened to the array. We perhaps need to define caseSensitive with regards arrays slightly better - if an array has been built case-sensitively, then from a case-insensitive context it isn't a 1-1 mapping any more, but a 1-many mapping - which would suggest it should be an error. Put like this, the error is when you ask for a key case-insensitively which has multiple case-sensitive entries (i.e. quite localized). Of course, this isn't how things have ever worked - so if this is to be considered an error, it is an anomaly. It also suggests the problem comes with set/fetch of arrays; rather than construction - i.e. array literals should always be case-sensitively built; but then consider making it an error for access in the above case at some point. |
If there's no way to know which element you are getting and indeed if the element you get may change if you mutate the array I suggest an execution error would be beneficial to people. But I agree that case sensitive is the only logical way to go for the literals and it's accessing the element that should have the error. |
c9f18b1
to
6ac4983
Compare
This patch adds support for 'array literals' to LiveCode Script:
Literals can be either completely constant, or completely dynamic, or a mixture of both.
In order to be able to detect constancy, a new (general) 'getattrs()' virtual method has been added to the MCExpression AST base class. This allows a node to be asked what attributes it has (the first being 'constant', but there are others which would be useful - like 'pure', or 'waitable'). The constant attribute is used to determine whether compile-time evaluation should be tried on the node - if the latter succeeds it is truly constant, if eval throws an error it is considered dynamic so the error will occur at runtime.
If a literal is constant, then the constant value is uniqued and is directly returned on eval. As the value is uniqued, the same literal can appear repeatedly, but only actually have one value in memory representing it.
If a literal is not constant, then it is stored as a (uniqued) base value with the constant key/values, along with a list of dynamic values. When a non-constant literal is evaluated, a new array value is built based on a copy of the base value; and the dynamic elements evaluated and added to it.
Note: This is an stg stack, hence the lack of commit messages as yet.
Note: Only seq literals can be constant at the moment - to do array literals needs some work to ensure that duplicate keys are handled appropriately. i.e. A duplicate dynamic key which appears before a constant identical key should be ignored, but used instead of a constant identical key if it appears after. This helps preserve a strict left-to-right evaluation order. There is an argument to be had for throwing an error with duplicate keys - although the dynamicity of caseSensitivity of keys suggests that for now, left-to-right evaluation and replacement if it occurs is probably the best path.