Black
From Hobby'dev
|Black< // declaring variables var( int x y str txt func(int) factorial(int) flt unit volume type cat ) /* the general schema is var( type type other type other other ) * one series of "other" identifier is typed by the preceding type or pipe-type * */ // assignment x: 5 txt: "hello" volume: 30.0 cm3 /* programming languages all use = as assignment * using : instead of = is simpler and natural (to me) * there's no space between the left side element and colons * it's easier to parse * */ // function declaration + definition func(int) fib(int n)( ret ife < n 3 1 + fib(- n 1) fib(- n 2) ) /* the type of a function is func() * the type of the return value goes inside parentheses * for example func(int) is a function that returns an int * * everybody knows that variables must have explicit names * x is a bad name, because it doesn't mean anything * who would name a variable "ret"? nobody * so we can use "ret" as keyword instead of "return" * * it would be shorter to write "int fib(int n)" * but it would be inaccurate: fib is a function, not an int * */ // variable declaration + definition int x(7) str txt("hello") /* writing the initial value between parentheses seems weird at first * but it is consistent with the way we write initial value of functions * the "value" of a function is its body * */ // source code types int nacci(12) $int result( fib(nacci) ) put "{$result} = {result}" /* This would print "fib(nacci) = 144" * * $int is the type "source code that yields an int" * $result holds the real value of the variable (the source code "fib(nacci)") * using "result" without dollar executes the source code, returning 144 * */ // type definition type dog( int size(40) int hunger(0) ctrl bark($str speech $int times)( ife >= times 5 do( cls put "woof" ) repeat fib(times) put .. "woof" speech ) func() run(int distance)( hunger: + hunger distance ) ) /* types are a bit like classes, but simpler * all variables are private (size and hunger can't be accessed from outside) * all methods are public * if you need encapsulation, put functions inside functions * * ctrl are half-procedures half-macros * controls don't return values * they don't receive the interpreted value from the caller * instead, they receive the source code from the caller * like arguments on the command-line * */ // instance dog maxy( size: 50 ) /* you can override things at initialization * after that, you can only call methods * */ // accessing methods maxy.bark "hello ruf" 3 maxy.run(4) /* you don't call a control (like "bark") with parentheses * instead, the ctrl arity is used to pick the right number of arguments * "bark" needs 2 arguments, the syntax is light * */ // type composition type pitbull( type(dog) pct ugliness(80%) pct strength(99%) ) /* importing a type inside another is as simple as this * a pitbull can do everything a dog can do * a type could be composed exclusively of type imports * */ // interfaces type Rectangle( flt width height func(flt) area( * width height ) ) type Circle( flt radius func(flt) area( * Pi sqr radius ) ) interface Shape( func(flt) area ) enum ShapeSize(small medium big) func(ShapeSize) classify(Shape shape)( ife < shape.area 10 small ife < shape.area 20 medium big ) /* classify can work on rectangles and circles because they both implement area * as long as a type implements every method of an interface, it's usable * * the area method is without parameters parentheses * this is ok since it has zero parameter, and confusion is impossible * * also, we can omit "ret" if the function is a single expression * in an "ife", the then and the else must have the same type * */ // variable tagging int maxy'bones(2) /* a tag is an additional value sticked to a variable * the syntax is varname'tagname * the tag behaves like a regular variable * */ // tag set and get maxy'bones: + maxy'bones 1 txt: "bones" put maxy'(txt) /* the varname-quote-tagname syntax is ok for constant tagname * there's also a varname-quote-openparen-tagname-closeparen syntax * the value of the expression in parentheses becomes the tagname * */ // pipe-type variables flt unit weight(30.0 Kg) /* a variable can have several types organized in "pipeline" * pipe-type values must be adjacent and space separated * */ // clusters clu stormies 20( obs( siths jedis ) arr(int) foo( repeat 5 rnd(100) ) spr foo on($int msg)( put "Node {my.id} Received {msg}" ret "ok" if > msg 90 emit "some message to observing clusters" ) ) /* stormies is a cluster of 20 nodes * clusters are a program's macro-organization unit * * spr spreads source code in the cluster * ret, in a "on", sends a message back to the msg sender * * spr takes * the message, which is transfered as source code (like ctrl) * if the message is a collection, it spreads items * * obs / unobs takes * the names of the clusters that should be observed / not observed * * emit takes * a value that observers will receive * * on() is a node's message event listener * its argument is used for type matching the message * the body is activated only if message type = argument type * there can be several on(), for different types * * receivers are chosen randomly among those who aren't currently working * */ // common types var( void // nothing enum(r g b) primCol // enumeration int n // integers flt f // floats str t // strings stk(str) s // stacks arr(int) ar // arrays bool b // booleans asso(str int) a // associative arrays pair pa // augmented cons cells poly(int flt) po // sum types pipe(flt unit) pi // product types unit u // units of measurement pct x // percents ) /* short names to make it light * all of this still in evolution * */