K language: Display GUI from data
- Tutorial
As always, I’m talking about APL, and more specifically about the old version of K , which contained a GUI, with a very unusual approach to it.
Unfortunately, new versions of the K language decided to focus only on data processing and excluded the GUI, so this approach remained in history, but maybe someone will tell similar modern frameworks - it would be very interesting to see.
Let's get started. A brief description of the API that is available to us:
That's all, there is nothing more. Those. The main feature is that the GUI in K is a direct mapping of data in memory. And now how to work with it conveniently.
First, let's try the simplest:
A table appears on the screen with a list.

Any value is editable, change 35 to 135 and this change immediately changes the value in the list:
If we change the value in the list, then it is also updated in the interface.
Listing a small list is not a problem, but what if there is a lot of data? let there be a lot:

No problem - everything is quickly displayed, scrolled and edited.
We name the columns: it is logical that the column name is the key, and the list is the value from hashtable:

But this is all very simple, we look what else. attributes and triggers - in fact it’s just a key-value in a hashtable attached to a variable, depending on whether there is such a value or not - different actions occur:
The simplest example: adding a label.

The following attributes affect the display in gui:
I will not describe the detailed features of each of the attributes, since most of them are obvious from the description and I do not want to make a similarity to the manual.
For ease of creating a dictionary - the language allows you to work in context within the dictionary - i.e. analogy with folders and modules that are just hash tables:
Attribute ..a set the display order.

..a can be of any form. For example, add a couple of buttons.

Those. the point is that the entire GUI is described by the primitive structures of the language and is their direct mapping. You can include hash in hash, i.e. incorporate form into form composing elements, etc.
Well, now the most interesting, namely a few examples:
Calculator:

You can draw graphs:

Or highly artistic daub:

And now an amazing thing that once so surprised with its brevity and clarity (with a minimum knowledge of the dictionary of course) that I decided to start exploring K deeper:
Broadcast server:
Client:
These few lines create a server with a simple list as data. And as many customers as you like join it and have a jointly edited list with real-time updates, just 9 lines. A similar code (without a GUI of course) is currently used on many of the largest exchanges for transport and balancing nodes that serve Q database instances (new version K).
The picture of course does not convey how it works in dynamics.

Unfortunately, new versions of the K language decided to focus only on data processing and excluded the GUI, so this approach remained in history, but maybe someone will tell similar modern frameworks - it would be very interesting to see.
Let's get started. A brief description of the API that is available to us:
`show$`v show variable v
`hide$`v hide variable v
That's all, there is nothing more. Those. The main feature is that the GUI in K is a direct mapping of data in memory. And now how to work with it conveniently.
First, let's try the simplest:
C:\>k
K 3.1 2004-01-28 Copyright (C) 1993-2004 Kx Systems
WIN32 2CPU 4030MB ws-1341.x.com 0 EVAL
a:10 _draw 100 / list
a
20 51 12 34 31 51 29 35 17 89
`show$`a
A table appears on the screen with a list.

Any value is editable, change 35 to 135 and this change immediately changes the value in the list:
a
20 51 12 34 31 51 29 135 17 89
If we change the value in the list, then it is also updated in the interface.
Listing a small list is not a problem, but what if there is a lot of data? let there be a lot:
a:(10 10000000) _draw 100 / 10 списков по 10 миллионов каждый
`show$`a

No problem - everything is quickly displayed, scrolled and edited.
We name the columns: it is logical that the column name is the key, and the list is the value from hashtable:
t:.((`a;10 _draw 100;);(`b;10 _draw 100))
`show$`t

But this is all very simple, we look what else. attributes and triggers - in fact it’s just a key-value in a hashtable attached to a variable, depending on whether there is such a value or not - different actions occur:
The simplest example: adding a label.
val:10
val..l:"Input field"
`show$`val

The following attributes affect the display in gui:
Display attributes (for variables that have class).
x width integer(KFONT width)
y height integer(KFONT height)
a arrangement nest of symbols(class `form)
o options list of symbols(class `radio)
l label string
kl click label string (also klr)
Data-display attributes (for variables that have class `data).
functions (monadic, constant or array) default
e editable 0 or 1 1
f format string from data 11$(11.2$)
g getdata data from string 0$ etc.
u update update[old;new] :
fg foreground integer(rrggbb) 0
bg background integer(rrggbb) -1(808080)
expressions/events (strings)
ins, del, f1 ... f12, ctrl_a ... ctrl_z
k, kr, kk click, click right, double click(precludes e)
c class(display) symbol
`data(default) atom, list, dict, list of lists, dict of lists
`chart as above where atom is list of y values
`plot as above where atom is matrix of (x;y) values
`check 0 or 1
`radio symbol (one of ..o; see below)
`button expression or dictionary of expressions
`form dictionary of entries of any class(incl. `form)
I will not describe the detailed features of each of the attributes, since most of them are obvious from the description and I do not want to make a similarity to the manual.
For ease of creating a dictionary - the language allows you to work in context within the dictionary - i.e. analogy with folders and modules that are just hash tables:
\d form
val:100
incr:"val+:1"
incr..l:"Increment"
decr:"val-:1"
decr..l:"Decrement"
incr..c: decr..c: `button
\d ^
form / хэш ключей-значений и хэшей аттрибутов.
.((`val;100;)
(`incr
"val+:1"
.((`l;"Increment";)
(`c;`button;)))
(`decr
"val-:1"
.((`l;"Decrement";)
(`c;`button;))))
Attribute ..a set the display order.
form..a:`incr`val`decr
form.val..e:0 / отключаем редактирование значения.

..a can be of any form. For example, add a couple of buttons.
form.incr10:"val+:10"
form.decr10:"val-:10"
form.incr10..c : form.decr10..c: `button
form..a:(,`incr;`decr10`val`incr10;,`decr)
form..a
(,`incr
`decr10 `val `incr10
,`decr)

Those. the point is that the entire GUI is described by the primitive structures of the language and is their direct mapping. You can include hash in hash, i.e. incorporate form into form composing elements, etc.
Well, now the most interesting, namely a few examples:
Calculator:
calc..a:(`exp
`va`vb`vc`vd
`n0`n1`n2`n3
`n4`n5`n6`n7
`n8`n9`lp`rp
`fa`fs`fm`fd`fe
`eval`clear) / порядок элементов на форме
calc:@[_n;1_-1_ calc..a;:[;"exp,:(~_v)`l"]] / expressions
calc[.;`l]:"abcd0123456789()+-*%:" / labels
calc.eval:"exp:5:. exp"
calc.clear:"exp:\"\""
calc[.;`c]:`button
calc.exp:calc.exp..l:""
`show$`calc

You can draw graphs:
p..c:`chart
p:(5 5) _draw 100
`show$`p

Or highly artistic daub:
`show$.,((`p;({[x] (2 30)_draw 30}'!10);.,(`c;`plot;)))

And now an amazing thing that once so surprised with its brevity and clarity (with a minimum knowledge of the dictionary of course) that I decided to start exploring K deeper:
Broadcast server:
d:10 _draw 10
w:!0 / empty client list
.m.g:{w,:_w;d} / return data
.m.c:"w@:&~w=_w" / retain clients
.m.s:{. x;w 3:\:x;} / (log `l 5:,x) apply and broadcast
\m i 1 listen on port 1
Client:
h:3:(`;1) / connect to server
d:h 4:_n / get database
d..t:"if[0=_w;h 3:(_v;_i;:;_v ._i)]" / send my updates
`show$`d
These few lines create a server with a simple list as data. And as many customers as you like join it and have a jointly edited list with real-time updates, just 9 lines. A similar code (without a GUI of course) is currently used on many of the largest exchanges for transport and balancing nodes that serve Q database instances (new version K).
The picture of course does not convey how it works in dynamics.
