Charles.Forsyth20060303-partialeea662d19 years agoHistory
495 lines · 10.8 KB · Text
RawDownload
.TLAddendum to.I "The Limbo Programming Language".AUVita Nuova.br30 March 2005.NH 1Introduction.LPThis addendum provides a brief summary of several language changes toLimbo since.I "The Limbo Programming Language"was last revised:.RS.IP •buffered channels.IP •unrestricted \f5alt\f1.IP •function references.IP •exceptions.IP •exponentiation.IP •fixed-point types.RE.NH 1Buffered channels.LPA buffered channel can now be declared:.P1c := chan[1] of int;.P2Here the buffer size is 1. A send on this channel will succeed immediatelyif there is a receiver waiting or if the buffer is empty. A receive on thischannel will succeed immediately if there is a data item in the buffer. This allows us towrite a very simple locking mechanism:.P1acquire(c: chan of int){	c <-= 0;} release(c: chan of int){	<-c;} new(): chan of int{	return chan[1] of int;}.P2The declaration.P1c := chan[0] of int;.P2is equivalent to .P1	c := chan of int;.P2An attempt to create a channel with a negative buffer size will raisean exception. An attempt to create a channel with a very large buffermay result in an immediate memory exception if there is not enoughroom for the buffer..NH 1Unrestricted.B alt.LPThe implementation has changed to remove the restriction that only one process can bewaiting in an.CW altto send or receive on a particular channel.The busy exception never occurs now. Thus you can do.P1i(){	c := chan of int;	c1 := chan of int;	spawn p(c, c1);	<-c;	spawn p(c, c1);	<-c;	for(i := 0; i < 20; i++)		c1 <-= i;} p(c: chan of int, c1: chan of int){	c <-= 0;	for(;;)		alt{			i := <-c1 =>				;		}}.P2The two spawned processes can both wait on.CW c1without fuss.Processes are queued on a strict FIFO basis so, inthe example above, the two processes receive on.CW c1alternately..NH 1Function references.LPFunction references may be declared as follows:.P1fp: ref fn(s1: string, s2: string): int;.P2Given the function.P1cmp(s1: string, s2: string): int{	if(s1 < s2)		return -1;	if(s1 > s2)		return 1;	return 0;}.P2a reference to it can be created by assignment:.P1fp = cmp;.P2where the name can be qualified by an explicit module reference as usual:.P1fp = mod->cmp;.P2or it can be returned from a function:.P1Cmp: type ref fn(s1: string, s2: string): int; rcmp(s1: string, s2: string): int{	return -cmp(s1, s2);} choose(i: int): Cmp{	if(i)		return rcmp;	return cmp;}.P2(the declaration of the synonym.CW Cmpwas done only for clarity).They may be declared and passed as parameters:.P1sort(a: array of string, f: ref fn(s1, s2: string): int): array of string{	# ...}	# ...b := sort(a, cmp);c := sort(a, rcmp);.P2The function is called via the reference by.P1	r := fp("fred", "bloggs");.P2Otherwise function references behave just like any other reference type..NH 1Exceptions.LPBoth string exceptions and user defined exceptions are now provided.The.CW Sysmodule interface to exceptionshas been removed and replaced by new language constructs in limbo..NH 2String exceptions.LPSimple string exceptions can be raised as follows.P1raise \fIs\fP;.P2where.I sis any value of type string (it need not be constant)..LPException handlers may be attached to a block (or sequence of statements) :-.P1{	foo();	bar();} exception e {"a" or "b" =>	sys->print("caught %s\en", e);	raise;"ab*" =>	sys->print("caught %s\en", e);	exit;"abcd*" =>	sys->print("caught %s\en", e);	raise e;"a*" =>	sys->print("caught %s\en", e);	raise "c";"*" =>	sys->print("caught %s\en", e);}LL:.P2.LPAny exception occurring within the block (and in nested function calls within the block) canpotentially be caught by the exception handler. An exception is caught by a guard exactlymaching the exception string or by a guard\f5\&"\fP\fIs\fP\f5*"\fPwhere.I sis a prefix of the exception string.The most specific match is used. Thus a raise of "a" will be caught by the firstguard and not by the fourth guard. A raise of "abcde" is caught by the third and not the secondor fourth. If a match is found, the sequence of statements following the guard are executed.If not, the system searches for a handler at a higher level..LPAs shown above, the exception is available through the exception identifier (e in this case) if given following the exception keyword..LPThe exception is reraised using.P1raise;.P2or.P1raise e;.P2.LPBoth the block and the exception code will fall through to the statement labelledLL unless, of course, they do an explicit exit, return or raise first..NH 2User-defined exceptions.LPYou can declare your own exceptions:.P1implement Fibonacci; include "sys.m";include "draw.m"; Fibonacci: module{	init: fn(nil: ref Draw->Context, argv: list of string);};.P3 init(nil: ref Draw->Context, nil: list of string){	sys := load Sys Sys->PATH;	for(i := 0; ; i++){		f := fibonacci(i);		if(f < 0)			break;		sys->print("F(%d) = %d\en", i, f);	}}.P3 FIB: exception(int, int);.P3 fibonacci(n: int): int{	{		fib(1, n, 1, 1);	}exception e{	FIB =>		(x, nil) := e;		return x;	"*" =>		sys->print("unexpected string exception %s raised\en", e);	* =>		sys->print("unexpected exception raised\en");	}	return 0;}.P3 fib(n: int, m: int, x: int, y: int) raises (FIB){	if(n >= m)		raise FIB(x, y); 	{		fib(n+1, m, x, y);	}exception e{	FIB =>		(x, y) = e;		x = x+y;		y = x-y;		raise FIB(x, y);	}}.P2.LP.CW FIBis a declared exception that returns two integers. The values are supplied when raising the exception:.P1raise FIB(3, 4);.P2When caught the values can be recovered by treating the declared exception identifieras if it were a tuple of 2 integers:.P1(x, y) = e;.P2In general each exception alternative treats the exception identifier appropriately : as a stringwhen the exception qualifier is a string, as the relevant tuple when the exception is declared..LPIf you do.P1"abcde" or FIB =>	(x, y) = e;	sys->print("%s\en", e);.P2you will get a compiler error as.CW e 'stype is indeterminate within this alternative..LPReraising is the same as in the case of string exceptions..LPNote also the difference between the string guard\&\f5"*"\fP and the guard.CW *inthe function fibonacci.The former will match any string exception, the latter any exception. If astring exception does occur it matches the former as it is the most specific.If an unexpected user definedexception occurs it matches the latter..LPThe main difference between declared exceptions and string exceptions isthat the former must be caught by the immediate caller of a function thatraises them, otherwise they turn into a string exception whose name is derivedfrom that of the exception declaration..NH 2The.CW raisesclause.LPThe definition of the function fib in the above example also lists the user defined exceptions it can raise via the use of a.CW raisesclause. In this case there is just the one exception (\f5FIB\f1). Theseclauses (if given) must be compatible between any declaration and definition of the function..LPThe compiler reports instances of functions which either raise some exception whichis not mentioned in their raises clause or does not raise some exception which ismentioned in their raises clause. Currently the report is a warning..NH 1Exponentiation.LPThe exponentiation operator (written as.CW ** )is now part of the Limbo language.Its precedence is above that of multiplication, division and modulus but belowthat of the unary operators. It is right associative. Thus.P13**4*2 = (3**4)*2 = 81*2 = 162-3**4 = (-3)**4 = 812**3**2 = 2**(3**2) = 2**9 = 512.P2The type of the left operand must be.CW int ,.CW bigor.CW real .The type of the right operand must be.CW int .The type of the result is the type of the left operand..NH 1Fixed point types.LPA declaration of the form.P1x: fixed(0.2, 12345.0);.P2declares.CW xto be a variable of a fixed point type. The scale of the type is1/5 and the maximum absolute value of the type is 12345.0..LPSimilarly.P1x: fixed(0.125, 4096.0).P2specifies a scale of 0.125 and a maximum absolute value of 4096.This requires only 17 bits so the underlying type will be.CW intand the compileris free to allocate the remaining 15 bits to greater range or greateraccuracy. In fact the compiler always chooses the latter..LPThe maximum absolute value is optional :-.P1x: fixed(0.125);.P2is equivalent to.P1x: fixed(0.125, 2147483647.0 * 0.125);.P2and ensures the underlying type is exactly an int ie the compiler hasno scope to add any extra bits for more accuracy..LPA binary fixed point type with 8 bits before the binary point and 24 aftermight therefore be declared as.P1x: fixed(2.0**-24);.P2.LPThe scale must be static: its value known at compile time andit must be positive and real; similarly for the maximum absolutevalue when specified..LPCurrently the only underlying base type supported is.CW int ..LPA shorthand for fixed point types is available through the use of.CW typedeclarations:.P1fpt: type fixed(2.0**-16);.P2We can then do.P1x, y, z: fpt;zero: con fpt(0); x = fpt(3.21);y = fpt(4.678);z = fpt(16r1234.5678);z = -x;z = x+y;z = x-y;z = x*y;z = x/y;sys->print("z=%f", real z);.P2There is no implicit numerical casting in Limbo so we have to use explicitcasts to initialize fixed point variables. Note the use of a base toinitialize.CW zusing a new literal representation..LPGiven.P1fpt1: type fixed(0.12345);x: fpt1;fpt2: type fixed(0.1234);y: fpt2;fpt3: type fixed(0.123);z: fpt3;.P2then.P1z = x*y;.P2is illegal. We must add casts and do.P1z = fpt3(x)*fpt3(y);.P2ie type equivalence between fixed point types requires equivalence of scale(and of maximum absolute value when specified)..LPFixed point types may be used where any other numerical type (byte, int, big, real) can be used. So you can compare them, have a list of them, have a channel of them, cast them to or from string and so on..LPYou cannot use complement(~), not(!), and(&), or(|), xor(^) or modulus(%) on them as fixed point types are basically a form of real type..NH 2Accuracy.LPA fixed point value is a multiple of its scale. Given fixed point values X, Y andZ of scale s, t and u respectively, we can write.P1X = sxY = tyZ = uz.P2where x, y and z are integers..LPFor the multiplication Z = X*Y the accuracy achieved is given by.P1| z - (st/u)xy | < 1.P2and for the division Z = X/Y.P1| z - (s/(tu))x/y | < 1.P2That is, the result is always within the result scale of the correct real value..LPThis also applies when casting a fixed point type to another, casting aninteger to a fixed point type and casting a fixed point type to an integer. Theseare all examples of the multiplication law with t = y = 1 since aninteger may be thought of as a fixed point type with a scale of 1.