Monte Goulding's day off? ; -) mergJSON - Documented Bug or Feature?
Mark Waddingham
mark at livecode.com
Thu Jun 30 05:16:54 EDT 2016
On 2016-06-30 00:06, Monte Goulding wrote:
> I’m sorry mergJSON isn’t working out for you. It sounds to me like you
> actually want to represent your numbers as strings in the JSON. In
> which case mergJSON does have the facility to force things that look
> like numbers to be strings and things that look like sequentially
> indexed arrays to be unordered objects.
This relates to the generation of JSON, I believe?
I think the issue here is the reading of the JSON.
> LiveCode will format numbers using the current numberFormat when the
> user wants to use them as a string. This would probably be a
> reasonable change to the external too. mergJSON is open source so if
> anyone is so inclined they could use EvalExpr to get the numberFormat
> then do something like what the engine does in MCU_r8tos to format the
> string. The repository is at
> https://github.com/montegoulding/mergJson. We might want an extra
> boolean parameter governing whether to apply the numberFormat also I
> think.
I do wonder here whether the problem is that from LiveCode Script's
point of view (and Lagi's use-case, probably others too) that it would
be preferable that all non-object/array/string values in the JSON are
returned as they are in the input file; string values being unescaped
appropriately (the quotes removed, obviously). This means that the
LiveCode engine would then do the conversions as appropriate, during
use.
In particular, this would mean the original representation of numbers as
they are in the JSON would be preserved - i.e. you would get 1.40 if the
value in the JSON was 1.40 - not the result of going string -> double ->
string again.
Unfortunately, from what I can see in the jannson source (the library
used my mergJSON to read the JSON), there is no mode that allows this.
As LiveCode Script can't distinguish between
numbers/strings/null/true/false - all are represented by strings, this
would actually be better than the current situation for many use-cases.
However, it is important to consider the fact that there are use-cases
where you *do* need to distinguish between a string "1.40" in the JSON
input and a number 1.40; as well as a string "true" and the boolean
value true in the JSON input. This is a similar problem to supporting
'NULL' in database columns - LiveCode Script doesn't distinguish between
the empty string "" and no value at all (NULL) - so you have to use a
sideline call to determine if a database field is actually NULL or not.
Prior to LiveCode 7, all values were either strings or arrays - however,
now they can actually be nothing, booleans, strings, numbers, binary
strings or arrays and there are operators to determine what a value's
type 'really' is the 'is strictly' operators. So you can do things like:
put "1.40" into tNumString -- tNumString is strictly a string
put tNumString + 1.6 into tNumber -- tNumber is strictly a number
These could provide a basis for providing a JSON importer which allows
both modes of use:
1) The 'simpler' everything is a string or an array view.
2) The 'faithful' things have a specific type view, where you can use
the 'is strictly' operators to determine the *actual* type of the value
which was specified in the JSON input. e.g.
{
"foo" : true
}
Would return an array with key "foo" mapping to 'string' "true";
but if you test the value with 'is strictly a boolean' it would return
true; if you test with 'is strictly a string' it would return false.
There's still a couple of caveats here...
LiveCode Script (as yet) does not have 'proper lists' - at the moment
'arrays' are used to represent both JSON objects and JSON arrays (JSON
arrays are sequences of values - lists in our parlance) - so you cannot
distinguish between something which is an object in the JSON input and
something which is an array in the JSON input.
I'm not sure yet how we'd make it possible to distinguish between the
number 1.40 and the string "1.40" in the JSON input but still make it so
that you 'see' what the precise input (1.40, in this case) was when the
number is converted to a string. Maybe one option would be to have a new
internal datatype StringyNumber which would be a String, but act like a
Number - basically a pair (string, number) with the invariant that
stringtonum(string) == number (but not the other way around - as that's
ambiguous). Such a beast would return 'false' for is 'strictly a
string', but 'true' for is 'strictly a number'. Of course, the problem
then is that you get an inconsistency with regards things such as 'the
numberFormat'. Whenever the engine formats a number as a string, it uses
the numberFormat to work out how to generate the string representation
of the number. With StringyNumbers, though you get an inconsistency:
put 3.14159 into tStringyNumber
set the numberFormat to "#.##"
put "Number: " & tStringyNumber
-- as tStringNumber is strictly a number you'd expect it to obey
numberFormat and so the output would be:
-- Number: 3.14
-- However, the point of a stringy-number is to preserve the
original string rep, so with the currently proposed logic
-- you would get:
-- Number: 3.14159
This means the 'naive' approach suggested above is perhaps not quite
right as it makes the number/string 'fragile' in the sense that you can
get different outputs depending on what the inputs were (and have no way
to detect that difference will occur). Therefore, I wonder if we can
make the numberFormat logic 'work' on strings, and not numeric
representations... i.e. The operation ConvertToString(StringyNumber ->
String), should use the string part of the StringyNumber together with
the numberFormat part to generate the output String - essentially if the
numberFormat *requires* more trailing decimal places than the string
part of the stringy-number has, then it should extend the string with
those zeros to match; if the numberFormat *forces* less decimal places
than the string part of the stringy-number has then it should format
from the number part of the stringy-number, ignoring the string part
altogether (the other option would be to 'round' the string directly, I
think these two these would be equivalent - but a little bit of maths is
needed to see which is the most appropriate to minimise error).
Anyway, upshot is, mergJSON uses a library which perhaps does not do
things 'quite the best way' for integration with a stringy language like
LiveCode Script (hence the contention Lagi is having); the recent
changes to LiveCode (since 7) could mean we can have the best of both
worlds in the future, although there is a bit of core engine work to do
to make that possible.
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