--- language: neat contributors: - ["Feep", "https://github.com/FeepingCreature"] filename: LearnNeat.nt --- Neat is basically a smaller version of D1 with some experimental syntax and a focus on terseness without losing the basic C-like syntax. [Read more here.](https://github.com/FeepingCreature/fcc/wiki) ```D // single line comments start with // /* multiline comments look like this */ /+ or this /+ these can be nested too, same as D +/ +/ // Module name. This has to match the filename/directory. module LearnNeat; // Make names from another module visible in this one. import std.file; // You can import multiple things at once. import std.math, std.util; // You can even group up imports! import std.(process, socket); // Global functions! void foo() { } // Main function, same as in C. // string[] == "array of strings". // "string" is just an alias for char[], void main(string[] args) { // Call functions with "function expression". writeln "Hello World"; // You can do it like in C too... if you really want. writeln ("Hello World"); // Declare a variable with "type identifier" string arg = ("Hello World"); writeln arg; // (expression, expression) forms a tuple. // There are no one-value tuples though. // So you can always use () in the mathematical sense. // (string) arg; <- is an error /* byte: 8 bit signed integer char: 8 bit UTF-8 byte component. short: 16 bit signed integer int: 32 bit signed integer long: 64 bit signed integer float: 32 bit floating point double: 64 bit floating point real: biggest native size floating point (80 bit on x86). bool: true or false */ int a = 5; bool b = true; // as in C, && and || are short-circuit evaluating. b = b && false; assert(b == false); // "" are "format strings". So $variable will be substituted at runtime // with a formatted version of the variable. writeln "$a"; // This will just print $a. writeln `$a`; // you can format expressions with $() writeln "$(2+2)"; // Note: there is no special syntax for characters. char c = "a"; // Cast values by using type: expression. // There are three kinds of casts: // casts that just specify conversions that would be happening automatically // (implicit casts) float f = float:5; float f2 = 5; // would also work // casts that require throwing away information - // those must always be done explicitly // (conversion casts) int i = int:f; // int i = f; // would not work! // and, as a last attempt, casts that just reinterpret the raw data. // Those only work if the types have the same size. string s = "Hello World"; // Arrays are (length, pointer) pairs. // This is a tuple type. Tuple types are (type, type, type). // The type of a tuple expression is a tuple type. (duh) (int, char*) array = (int, char*): s; // You can index arrays and tuples using the expression[index] syntax. writeln "pointer is $(array[1]) and length is $(array[0])"; // You can slice them using the expression[from .. to] syntax. // Slicing an array makes another array. writeln "$(s[0..5]) World"; // Alias name = expression gives the expression a name. // As opposed to a variable, aliases do not have an address // and can not be assigned to. (Unless the expression is assignable) alias range = 0 .. 5; writeln "$(s[range]) World"; // You can iterate over ranges. for int i <- range { write "$(s[i])"; } writeln " World"; // Note that if "range" had been a variable, it would be 'empty' now! // Range variables can only be iterated once. // The syntax for iteration is "expression <- iterable". // Lots of things are iterable. for char c <- "Hello" { write "$c"; } writeln " World"; // For loops are "for test statement"; alias test = char d <- "Hello"; for test write "$d"; writeln " World\t\x05"; // note: escapes work // Pointers: function the same as in C, btw. The usual. // Do note: the pointer star sticks with the TYPE, not the VARIABLE! string* p; assert(p == null); // default initializer p = &s; writeln "$(*p)"; // Math operators are (almost) standard. int x = 2 + 3 * 4 << 5; // Note: XOR is "xor". ^ is reserved for exponentiation (once I implement that). int y = 3 xor 5; int z = 5; assert(z++ == 5); assert(++z == 7); writeln "x $x y $y z $z"; // As in D, ~ concatenates. string hewo = "Hello " ~ "World"; // == tests for equality, "is" tests for identity. assert (hewo == s); assert !(hewo is s); // same as assert (hewo !is s); // You can do a C for loop too // - but why would you want to? for (int i = 0; i < 5; ++i) { } // Otherwise, for and while are the same. while int i <- 0..4 { assert(i == 0); break; // continue works too } then assert(false); // if we hadn't break'd, this would run at the end // This is the height of loopdom - the produce-test-consume loop. do { int i = 5; } while (i == 5) { assert(i == 5); break; // otherwise we'd go back up to do { } // This is a nested function. // Nested functions can access the surrounding function. string returnS() { return s; } writeln returnS(); // Take the address of a function using & // The type of a global function is ReturnType function(ParameterTypeTuple). void function() foop = &foo; // Similarly, the type of a nested function is ReturnType delegate(ParameterTypeTuple). string delegate() returnSp = &returnS; writeln returnSp(); // Class member functions and struct member functions also fit into delegate variables. // In general, delegates are functions that carry an additional context pointer. // ("fat pointers" in C) // Allocate a "snapshot" with "new delegate". // Snapshots are not closures! I used to call them closures too, // but then my Haskell-using friends yelled at me so I had to stop. // The difference is that snapshots "capture" their surrounding context // when "new" is used. // This allows things like this int delegate(int) add(int a) { int add_a(int b) { return a + b; } // This does not work - the context of add_a becomes invalid // when add returns. // return &add_a; // Instead: return new &add_a; } int delegate(int) dg = add 2; assert (dg(3) == 5); // or assert (((add 2) 3) == 5); // or assert (add 2 3 == 5); // add can also be written as int delegate(int) add2(int a) { // this is an implicit, nameless nested function. return new λ(int b) { return a + b; } } // or even auto add3(int a) { return new λ(int b) -> a + b; } // hahahaaa auto add4 = λ(int a) -> new λ(int b) -> a + b; assert(add4 2 3 == 5); // If your keyboard doesn't have a λ (you poor sod) // you can use \ too. auto add5 = \(int a) -> new \(int b) -> a + b; // Note! auto nestfun = λ() { } // There is NO semicolon needed here! // "}" can always substitute for "};". // This provides syntactic consistency with built-in statements. // This is a class. // Note: almost all elements of Neat can be used on the module level // or just as well inside a function. class C { int a; void writeA() { writeln "$a"; } // It's a nested class - it exists in the context of main(). // so if you leave main(), any instances of C become invalid. void writeS() { writeln "$s"; } } C cc = new C; // c is a *reference* to C. Classes are always references. cc.a = 5; // Always used for property access. auto ccp = &cc; (*ccp).a = 6; // or just ccp.a = 7; cc.writeA(); cc.writeS(); // to prove I'm not making things up // Interfaces work same as in D, basically. Or Java. interface E { void doE(); } // Inheritance works same as in D, basically. Or Java. class D : C, E { override void writeA() { writeln "hahahahaha no"; } override void doE() { writeln "eeeee"; } // all classes inherit from Object. (toString is defined in Object) override string toString() { return "I am a D"; } } C cd = new D; // all methods are always virtual. cd.writeA(); E e = E:cd; // dynamic class cast! e.doE(); writeln "$e"; // all interfaces convert to Object implicitly. // Templates! // Templates are parameterized namespaces, taking a type as a parameter. template Templ(T) { alias hi = 5, hii = 8; // Templates always have to include something with the same name as the template // - this will become the template's _value_. // Static ifs are evaluated statically, at compile-time. // Because of this, the test has to be a constant expression, // or something that can be optimized to a constant. static if (types-equal (T, int)) { alias Templ = hi; } else { alias Templ = hii; } } assert(Templ!int == 5); assert(Templ!float == 8); } ``` ## Topics Not Covered * Extended iterator types and expressions * Standard library * Conditions (error handling) * Macros