0

For expression parse"x[y]", I think it means a function/map/list application of x on argument y, possibly a projection. Please correct me if I'm wrong.

Now entering into Q console, I get below output.

q)parse"x[y]"
x
y
q)l:parse"x[y]"
q)count l
2
q)type l
0h
q)l[0]
`x
q)l[1]
`y
q)type l[0]
-11h
q)type l[1]
-11h

We see l has type 0h. It has length 2. Both elements have type -11h. Why is the list then, not of type 11h?

kgf3JfUtW
  • 13,702
  • 10
  • 57
  • 80
  • As an FYI - related to this question: https://stackoverflow.com/questions/66304637/kdb-calling-parse-on-a-list-of-variables/66304800 – terrylynch Feb 21 '21 at 17:09
  • @terrylynch In general though, is it then possible for a list to contain atoms of identical types (e.g. symbol), but still for the list to have type `0h`? – kgf3JfUtW Feb 21 '21 at 17:49
  • 1
    In general no, it would usually collapse into a uniform list but there are always weird edge cases and grey areas! Though I don't consider this issue to be weird or an edge case, it's expected behaviour for parse tree generation – terrylynch Feb 21 '21 at 19:16

1 Answers1

0

In short, it's a parse tree signature 'type' construct, very similar to lambda (which would be type 64). k recognises and evaluates expression in parse tree when object reaches call stack, de-referencing symbols-which acts like a pointer.

TL;DR - Step by step breakdown

  1. Basic evaluation constructs

"x[y]" ~ "x y"

q)x:count
q)y: 1 2 3
q)parse "x y"  
x
y
q)x y
3
q)`x y
3
q)eval parse "x y"
3

Simple indexing, 'simplified' 2nd param -> int atom:

q)parse "y 2"  //this nicely shows parse tree
`y
2
q)eval parse "y 2" 
3 
q)eval (`y;2)
3 
q)`y 2
3
q)y 2
3

Both above examples are mixed lists (0h), with actual elements following immediately - where symbols - are references. Instead with normal mixed list construct where all lenghts and types are defined later

  1. Looking at serialised IPC frame helps to understand this construct

Establish what expressions are the same

q)parse["x[y]"] ~ parse "x y"
1b
q)parse["x[y]"] ~ parse "x@y"
0b
q)parse["x[y]"] ~ parse "{x y}" 
0b

Compare byte frames

q)-8!parse "x[y]" 
0x0100000014000000000002000000f57800f57900
q)-8!parse "x y"  
0x0100000014000000000002000000f57800f57900  
q)-8!`x`y 
0x01000000120000000b000200000078007900 
q)-8!enlist `x`y
0x01000000180000000000010000000b000200000078007900 
                                                                                                                 

Compare parse tree output from 1st paragraph with actual obj instead of reference

q)-8!parse "x y"
0x0100000014000000000002000000f57800f57900 
q)-8!parse "x 2"
0x010000001a000000000002000000f57800f90200000000000000

Lambda structure to complete the list for reference

q)-8!{x y}
0x010000001500000064000a00050000007b7820797d
/0x7b "{" ; 0x7d "}"
  1. And finally the IPC frame breakdown

`x`y (symbol list)

q)symlist:`endian`isync`x`y`length`type`attr`msg!sums[0 1 1 1 1 4 1 1] _ -8!`x`y
q)symlist
 endian| ,0x01     (little endian)    
 isync | ,0x00 
 x     | ,0x00   
 y     | ,0x00 
 length| 0x12000000 
 type  | ,0x0b     (11h - symbol list - 1st difference)
 attr  | ,0x00  
 msg   | 0x0200000078007900   

dig into the symlist:

  q)msg:`lenght`msg!sums[0 4] _ symlist`msg 
  q)msg
   lenght| 0x02000000
   msg   | 0x78007900
                                                                                                                 

Here we can clearly see, how null terminated symbol follows length of vector immediately, due to explicit type: 0x0b - 11h - symbol list

  q)`char$msg`msg
   "x\000y\000"

parse "x[y]" - parse tree breakdown

q)o1:`endian`isync`x`y`length`type`attr`msg!sums[0 1 1 1 1 4 1 1]_ -8!parse"x[y]"
q)o1   
 endian| ,0x01            
 isync | ,0x00   
 x     | ,0x00 
 y     | ,0x00   
 length| 0x14000000    
 type  | ,0x00   (could expect 64 - 100h lambda)
 attr  | ,0x00    
 msg   | 0x02000000f57800f57900   

Difference from simple list:

   q)`lenght`type1`msg1`type2`msg2!sums[0 4 1 2 1 ] _ o1`msg
    lenght| 0x02000000
    type1 | ,0xf5        (-11h - symbol atom) - acts as a reference
    msg1  | 0x7800       null terminated "x" 
    type2 | ,0xf5        (-11h - symbol atom)
    msg2  | 0x7900       null terminated "y"  - acts as a reference
bua
  • 4,761
  • 1
  • 26
  • 32