scScript Comparing & Counting
The C programming language has familiar ==
and != operators to compare scalar values as well as
pointers. But scScript does not expose pointers, so provides special
=== and !== operators to compare storage
locations instead. Given:
Var A = "Yes", B = "Yes";
All the following will be true:
(A == B)
(A == "Yes")
(B == "Yes")
because A and B will have the exact same
value, "Yes" (an immutable string).
But all the following will be false:
(A === B)
(A === "Yes")
(B === "Yes")
because A and B are different variables
with different storage locations. Even more, while the value of
A is "Yes", the variable A has its very
own storage location, which is not the same as the literal
string "Yes". In that sense, X === Y really
tests that X is Y. (Recall that X =& Y
makes X become Y.)
While === generally tests if both sides
have the same storage location, it is smart enough to do a value
comparison if one (or both) sides are just constant numbers without a
storage location. So K === 12
returns 1 if the value of K
is 12. Importantly, this test also works
for NaN, since it does a bit-image comparison and
not a numerical one. Therefore K === Math.#Nan is a good
test to see if the value of K has left the realm of
numbers. (Some languages require an obscure K != K test
for this!)
Arrays, unless created with a [] constructor, are created
with missing (unpopulated) cells. Dicts, by definition, only
have a few pairs and are missing a whole infinity of possible key-value
pairs. When comparing or using values, scScript will automatically
populate any missing elts or pairs. It initializes these empty
storage cells to contain the value Int 0,
so == and other operations get proper values to compare and
use. This auto-populate may also involve expanding the array or
dict as necessary.
So a simple test, such as:
(MyDict.George == 0) or
(MyArr[12] == 0)
will in fact add a pair to MyDict and an elt
to MyArr if they did not have them before. Therefore an
equality test for MyArr[240000] will cost an immense amount
of memory as MyArr is expanded!
But things are different for === as it only cares about
storage locations, not values. To that end, ===
does not populate missing elts or pairs; it just treats them as
missing (null) locations. But to get the proper
semantics, === returns 0 if they are missing!
So A[x] === A[y] is always 0 when one
or both are missing. Interestingly a statement of the
form A[x] == A[y] will automatically create both missing
elts (and succeed as both will be 0), but these will still
have different storage locations, so the === test, if
subsequently applied, will once again return 0.
scScript provides two predicates to ascertain the size of an array or dict:
SizeOf(A)returns the number of cells the array or dict can currently hold, even if unpopulated. This number will increase if the array or dict are expanded (capacity of the bus).CountOf(A)returns the number of populated elts/pairs currently in the array or dict. This number will increase as new ones are added or auto-populated (how many in the bus).
Importantly, the special dyadic function CountOf(TheArr,
Index) or CountOf(TheDict, Key) will
return 0 if the indexed elt is not populated or the
indicated pair is not in the dict. But it is imperative to use
this 2-arg format, otherwise CountOf(TheArr[Index])
will automatically populate TheArr[Index] when the argument
for CountOf is being processed!
// Size and Count test! (SCTest.sc) Var A = Array();Var D = Dict(); A[5] = 0; D[5] = 12, D["Yes" ] = 144, D["No" ] ="Yes" ; Writeln("A Size " , SizeOf(A)); Writeln("A Count " , CountOf(A)); Writeln("A[5] Count --> " , CountOf(A, 5)); Writeln("A[4] Count --> " , CountOf(A, 4)); Writeln("-----------" ); Writeln("D Size " , SizeOf(D)); Writeln("D Count " , CountOf(D)); Writeln("D.Yes Count --> " , CountOf(D,"Yes" )); Writeln("D[4] Count --> " , CountOf(D, 4)); Writeln("-----------" ); Writeln("A[5] == A[4] --> " , A[5] == A[4]); Writeln("A[5] === A[4] --> " , A[5] === A[4]); Writeln("A[5] === A[5] --> " , A[5] === A[5]); Writeln("A[5] === A[6] --> " , A[5] === A[6]); Writeln("A[3] === D[3] --> " , A[3] === D[3]); Writeln('D["No"] == "Yes" --> ' , D["No" ] =="Yes" ); Writeln('D["No"] === "Yes" --> ' , D["No" ] ==="Yes" ); Writeln('"Yes" === "Yes" --> ' ,"Yes" ==="Yes" ); Writeln("-----------"); Function Test()(OutA, OutD) {Var LocA =& OutA;Var LocB = LocA; Writeln("OutA === A --> " , OutA === A); Writeln("OutA === LocA --> " , OutA === LocA); Writeln("LocA === A --> " , LocA === A); Writeln("LocB === A --> " , LocB === A); Writeln("-----------" ); LocA[9] =& OutD["Yes" ]; Writeln("LocA[9] --> ", LocA[9]); } Test()(A, D); Writeln("A[9] --> " , A[9]); Writeln("-----------" ); Show.Vars(Show.#MAX)(A, D);
The sample code above, and its output below, illustrates many of the
points made in this section. The Test() function above
demonstrates the implicit alias mechanism of the out arg
list as well as the explicit storage assignment of the =&
operator itself. In both cases, variables are assigned pre-existing
storage locations belonging to another, a relationship that can be
verified using ===.
A Size 8
A Count 1
A[5] Count --> 1
A[4] Count --> 0
-----------
D Size 16
D Count 3
D.Yes Count --> 1
D[4] Count --> 0
-----------
A[5] == A[4] --> 1
A[5] === A[4] --> 0
A[5] === A[5] --> 1
A[5] === A[6] --> 0
A[3] === D[3] --> 0
D["No"] == "Yes" --> 1
D["No"] === "Yes" --> 0
"Yes" === "Yes" --> 1
-----------
OutA === A --> 1
OutA === LocA --> 1
LocA === A --> 1
LocB === A --> 0
-----------
LocA[9] --> 144
A[9] --> 144
-----------
Var (Ref:1) [Entry 000032 (16 Bytes) on Mem:1 (VEnt) Slab:1]
--> Array (Ref:1) [Entry 000064 (16 Bytes) on Mem:1 (VEnt) Slab:1]
--> 10 Entries [Entry 009536 (96 Bytes) on Mem:4 (ADat) Slab:1]
000 ---
001 ---
002 ---
003 ---
004 ---
005 Var (Ref:1) [Entry 000000 (16 Bytes) on Mem:1 (VEnt) Slab:1]
Int 0
006 ---
007 ---
008 ---
009 Pair (Ref:2) [Entry 016608 (32 Bytes) on Mem:2 (BEnt) Slab:1]
Int 144
Var (Ref:1) [Entry 000016 (16 Bytes) on Mem:1 (VEnt) Slab:1]
--> Dict (Ref:1) [Entry 017184 (32 Bytes) on Mem:2 (BEnt) Slab:1]
--> 16 Entries [Entry 009392 (144 Bytes) on Mem:4 (ADat) Slab:1]
Filled Dictionary: 3 of 16
Total Probes:3 (Avg:1.000000)
- * - - - - - - * - - - - *
Pair (Ref:1) 0001 Key:"No" Val:"Yes"
Pair (Ref:2) 0002 Key:"Yes" Val:144
Pair (Ref:1) 0003 Key:5 Val:12