Chomik is a general-purpose programming language.
It is: lightweight, imperative, interpreted and pretty unusual. Especially suitable as a
Let us begin traditionally with a Hello World program:
execute <print "Hello world">;
<print "Hello world">;
Like in many scripting languages in Chomik comments begin with the character "#" and last till the end of line.
###################################################################
# This is a comment
# Another comment
###################################################################
<print "Hello world">; # We could also write a comment after code.
Are you tired of the languages that force you to imagine beforehand the complex data structures that your program is going to use? The good news is - there are no data structures in Chomik! Due to its powerful concept of the family of variables we can easily assign multiple variables at once.
# we can assign variables directly:
let alpha = value integer 123;
let beta = value float 521.34;
# or we can assign the whole family for any range
let alpha (N:1..10) = value integer 100;
# or we can ask Chomik to create a Cartesian product of multiple ranges for us:
let alpha (A:1..10) beta (B:2..5) = value integer 120;
We got used to the imperative languages that try to "sell" us syntactic sugar as something revolutionary... There is no other reason why many, many constructs in Fortran, Pascal, C, C++ or Java differ among each other. But these syntactical changes just cover the fact they are to a large extent just clones. Chomik is going to change it! Now we are finally dealing with something REALLY new and exciting.
# this is an example of an implicit loop in Chomik
let alpha (N:1..10) = value integer 100;
# now in order to achieve this, we would need two nested loop instructions
# in traditional imperative languages
let alpha (A:1..10) beta (B:2..5) = value integer 120;
# while this Chomik one-liner produces a Cartesian product
# of the sets A x B x C and prints out all its combinations,
# all this without a single loop instruction!
<print (A:1..10) "and" (B:1..5) "and" (C:3..5)>;
As you may have noticed Chomik allows multiple identifiers mixed with literals as variable names. Literals of any type. Why on Earth do we need names of variables consisting of multiple identifiers AND literals? Do not worry, this feature is very useful. We didn't tell you yet that there is a built-in enumeration called 'boolean' did we? Well, if we want to execute a variable of type 'code' (yes, code is just a built-in type) depending on another variable's value then this is what we do:
let alpha false = value code { <print "something is FALSE">; };
let alpha true = value code { <print "something is TRUE">; };
let something = value boolean false;
# now we can evaluate a special expression based on the <> operator
# that we call an evaluation operator:
<alpha <something>>;
The above snippet will check the value of the boolean variable 'something', then take this value and append it to the identifier 'alpha' constructing either 'alpha false' or 'alpha true'. And then, guess what - it will execute either of the code. No IF .. THEN .. ELSE and other horrible constructs like that.
We mentioned text-based games as the field where Chomik is particularily useful, didn't we? Just to have a taste of what is awaiting you in Chomik please take a look at this snippet:
type town = { Washington, Boston, New York, Chicago };
type person = { Tom, Paul, Jerry },
information = { (A:person) likes (B:town) };
expand(2); # we will explain it later
<print (X:information)>;
TomlikesWashington TomlikesBoston TomlikesNewYork TomlikesChicago PaullikesWashington PaullikesBoston PaullikesNewYork PaullikesChicago JerrylikesWashington JerrylikesBoston JerrylikesNewYork JerrylikesChicago
type town = { Washington, Boston, New York, Chicago };
type person = { Tom, Paul, Jerry },
information = { (A:person) likes (B:town) };
expand(2); # we will explain it later
let (X:information)=value boolean true;
<print "Tom likes Washington=" <Tom likes Washington>>;
Did you notice that whenever some technique is introduced in the programming languages they try to gain its reputation by using for it complex names? Preferably coming from the ancient Greek.
type town = { Washington, Boston, New York, Chicago };
type person = { Tom, Pawel, Jerry };
expand(1); # we will explain it later
let (PERSON:person) comes to (TOWN:town) = value code { <print "How beautiful!">; };
let Pawel comes to Washington = value code { <print "It is ugly!">; };
<Tom comes to Washington>;
<Pawel comes to Washington>;
Even though we have assigned the code for all persons and all towns to print out "How beautiful!", we later override one of the codes (for Pawel coming to Washington) so that it prints something else. We do not have any ancient Greek name for this technique.
In most if not all imperative languages there is the convention of passing parameters to "functions" or "procedures". We don't like it. It sounds like early optimization. Take a look at the below snippet:
# in Chomik everything concerning the "parameters"
# happens during the assignment.
let my function (X:1..3) = value code { let alpha = value integer [(X:1..3)]; <print <alpha>>; };
let another function (Y:integer) = value code { let alpha = value integer [(Y:integer)]; <print <alpha>>; };
<my function 2>; # this is one of three codes from the "my function" family
<another function 1537>; # this family is stored in memory in a different way
# who cares ?...
This will quite correctly print out 2 and then 1537. But Chomik is likely to create three copies of the 'my function' family (my function 1, my function 2, my function 3). For the 'another function' it will just store the assignment in memory in a different way. How? Well, you shouldn't care about it.
What you may have noticed in the above code is the operator []. The expression 'value integer [(X:1..3)]' is the integer value of the "parameter" X. And the expression 'value integer [(Y:integer)]' is an integer value of the parameter Y.