Penguin
Note: You are viewing an old revision of this page. View the current version.

NiTypesin?

NiStructures?

NiExpressions?

NiIdentifiers?

NiCallBackExample

NiOptimisations?

(So what is this Ni then? A compiled Python?) (If so, do you know about Pyrex? --GlynWebster)

Partially, Ni also has a few other goals. One of the major ones is that programmers introduce bugs, usually at a constant rate per line of code written. By reducing the amount of programming a programmer has to do, and using the compiler to try and detect bugs earlier, more reliable programs can be written. Ni attempts to do this by:

Using pre and post conditions

Functions have pre and post conditions which can be specified by the programmer. The compiler will also look at the pre and post conditions of statements and generate it's own pre and post conditions and try and validate them, warning if they are violated. Thus code like
def foo(int i)
return 5/i

would automatically have the precondition added that i!=0. Thus, if a call is made to foo() where i may be "0", a warning will be generated at compile time. The compiler can also use this information to optimise the program. For instance, foo() above has no side effects, and depends on no other information other than i, therefore it's result can be cached, precomputed, and/or hoisted out of a loop.

Much of this came about after looking at programs which contained comments like
/* ptr cannot be null here, because ... */ assert(NULL != ptr);

Looking at the code generated by the compiler, it was unable to make use of these comments/assertions for optimisation, nor was it able to warn me if I called this function with a constant NULL. Another example in all the m_.c files in ircu, there is a short note mentioning that in the m_ functions, sptr==cptr. The compiler is unable to make use of this hint and will reload all the elements of the structures these point to when the other one changes, not realising that they can be optimised and only loaded once.

Datastructure operations are determined by the compiler.

A lot of programming is spent maintaining various datastructures (hash tables, linked lists etc). Even in langauges which have runtime libraries which provide redblack tree's, hashtables, and the like the programmer still has to decide which of these to use. Many programmers don't know when a redblack tree would be an appropraite datastructure to use. Part of what "Ni" provides built into the language is a "dictionary" structure similar to PHP's array's. These are ordered associative maps. The compiler can look at which operations are used on them and use the most efficient implementation, or, in some cases, more than one implementation, for example

array [? of string data;

for i in range(0,10)
data.append(read_string())

data.sort()

for i in data
print data[i?
First of all the compiler can tell that the data isn't inspected after it's been inserted into the array and before the sort() method call, so it can use a sorted datastructure for the underlying implementation, making the call to sort() a noop and changing the append() into a insertSorted(). The compiler can tell that the data is read out in consequative order, and is never used after that so it can garbage collect data during the for loop, thus reducing the second for loop to
for i in data
print data.pop()

Now, the only used methods are insertSorted() and data.pop(), so the "best" implementation of this would be a PriorityQueue, the memory ca n be statically allocated at 10 items, since we know at compile time that that is the maximum size of the heap.

This leaves the programmer free from having to think about datastructures and just thinking about the "business logic" of their program.