<<option chkOpenInNewWindow>> OpenLinksInNewWindow\n<<option chkSaveEmptyTemplate>> SaveEmptyTemplate\n<<option chkToggleLinks>> Clicking on links to tiddlers that are already open causes them to close\n^^(override with Control or other modifier key)^^\n\n<<newTiddler>>\n
The Book of Boo
A TiddlyWiki about Boo
StartHere
Methods can be added to existing types.\n\nExample StreamIo library.\n
A common situation is when a property is read-only. There is only a getter function defined:\n{{{\n Name:\n get\n return _name\n}}}\nBoo provides the {{{getter}}} attribute as a shorthand for this code:\n{{{\n [getter(Name)]\n _name as string\n}}}\nGenerally, it it's a good idea to catch bad input as early as possible. This really simplifies your life later; the rest of the system can then assume your data is valid, because there is a consistent 'firewall' between it and the world. For instance, our Person class can be made responsible for preventing names being set to empty or null strings. The {{{property}}} attribute takes a very useful optional parameter. You can supply a //precondition// that must be true, otherwise the setter operation fails. \n{{{\n [property(Name,value is not null and len(value) > 0)]\n _name = "que?"\n}}}\nis shorthand for\n{{{\n _name = "que?"\n Name:\n get:\n return _name\n set:\n assert value is not null and len(value) > 0\n _name = value\n}}}\nThat does save space, but the object is not to save lines. Otherwise, we would end up doing silly things like placing multiple assigments etc on the same line. The benefit here is mostly that the code signals the //programmer's intention// better. In CustomAttributes, I'll show a new attribute NonEmptyString which makes the intention of the code even easier to read, as well as being easier to type.\n
Note that to access a property value involves implicitly calling a function, so property access can be significantly slower than accessing public fields (But, PrematureOptimization). But there are advantages. Firstly, properties become publically available to the rest of the framework. A nice example of this is the {{{PropertyGrid}}} control in Windows Forms. \n{{{\n>>> import System.Windows.Forms from 'System.Windows.Forms'\n>>> f = Form()\nSystem.Windows.Forms.Form, Text: \n>>> pg = PropertyGrid(Dock : DockStyle.Fill)\nSystem.Windows.Forms.PropertyGrid\n>>> f.Controls.Add(pg)\n>>> f.Show()\n>>> pg.SelectedObject = f\nSystem.Windows.Forms.Form, Text: \n}}}\nNow that //is// cool; you can inspect //and// change all the properties of the form you have just created. \n\nSecondly, if you do need to change the implementation of a property, it doesn't affect any other clients of your library. Consider these two ways of begining a {{{Bill}}} class:\n{{{\n class Bill:\n public DateDue as DateTime\n public Amount as double\n public Debtor as Customer\n ...\n \n class Bill:\n [property(DateDue)]\n _dateDue as DateTime\n [property(Amount)]\n _amount as double\n [property(Debtor)]\n _debtor as Customer\n ...\n}}}\nThe first way may seem adequate. But if you suddenly want to put some checking on these values (see GettersAndPreconditions) you have to change to the second style. If the {{{Bill}}} class is part of the public interface of one of your system's assemblies, then everything is broken and needs to be recompiled. This is particularly nasty if the assemblies are sitting on a user's machine, and basically makes it hard to do incremental upgrades.\n\n
There are two kinds of values in a CLI program, as discussed in CopyingReferences. In arithmetic expressions, values are copied, not the references. That is what assignment means for numbers, and it is a cheap operation since numbers occupy a few bytes. Usually you don't want this to happen with objects, but sometimes it's necessary to force a type to copy by value.\n{{{\nstruct Point3D:\n public X as double\n public Y as double\n public Z as double\n \n def constructor(x as double, y as double, z as double):\n X = x; Y = y; Z = z\n \n def Add(p as Point3D):\n return Point3D(X + p.X, Y + p.Y, Z + p.Z)\n \n override def ToString():\n return "(${X},${Y},${Z})"\n \np1 = Point3D(10.0,20.0,30.0)\np2 = Point3D(1.0,1.0,2.0)\nprint p1,p2,p1.Add(p2)\n}}}\n<<<\n(10,20,30) (1,1,2) (11,21,32)\n<<<\n\nOverloadingOperators\n
Occaisionally it makes perfect sense to change the meaning of {{{x + y}}}. For example, our {{{Point3D}}} class can represent vectors in three-dimensional space, and you can add vectors. That addition operation will be mathematically written using the same symbol, will have the same operator precedence, etc. (The same goes for complex numbers and matrices.). To overload {{{+}}} for 3D vectors, replace the {{{Add}}} method with the following static method:\n{{{\n static def op_Addition(self as Point3D, p as Point3D):\n return Point3D(self.X + p.X, self.Y + p.Y, self.Z + p.Z)\n}}}\nThere are two things to note - these have to be static methods, and one has to use the internal name of the operator.\n\nAn important point is that once you start overloading, it's a good idea to do all the related arithmetic operations. If you do addition, you must do subtraction, unary minus; if you do multiplication, you must do division.\n\nThese are the names of the operators you can overload, as of Boo 0.7.5:\n*op_Addition + \n*op_Subtraction -\n*op_Multiply *\n*op_Division /\n*op_Modulus %\n*op_Exponentiation **\n*op_Equality == \n*op_LessThan <\n*op_LessThanOrEqual <=\n*op_GreaterThan >\n*op_GreaterThanOrEqual >=\n*op_Match =~\n*op_NotMatch not =~\n*op_Member in\n*op_NotMember not in\n*op_BitwiseOr |\n*op_BitwiseAnd &\n*op_UnaryNegation -\n\nSince {{{x += y}}} is equivalent to {{{x = x + y}}}, overloading {{{+}}} will automatically overload {{{+=}}}. ''But'', OverloadInPlaceAddition.\n\nIf you are in any doubt as whether to overload, don't. You are in danger of inventing a notation which will confuse other people and make your programs more obscure. For example, the word 'add' doesn't always mean addition. Adding a customer to the list of customers is not a candidate for overloading {{{+}}}, because it has different semantics - it does not produce a new list.\n\n
It would probably be useful to allow binary operations like ~InPlaceAddition to be overloaded directly, because just relying on the usual {{{x += y ==> x = x + y}}} leads to potentially inefficient code for value types.\n\nThe question is, why restrict overloading //at all//?
Sometimes we need a set of constants to indicate state. For instance, a television may be off,on or on standby. You know better than to use MagicNumbers, and can define BooConstants.\n{{{\nclass TvState:\n static final Off = 0\n static final On = 1\n static final Standby = 2\n}}}\nWhich is fine, but a lot of typing. Enums (short for //enumerations//) are a useful way to create a //new type// with a defined set of values.\n{{{\nenum TvState:\n Off\n On\n Standby\n\nstate = TvState.Off\nprint "state was",state\n}}}\n<<<\nstate was Off\n<<<\nNote that enum values know how to print themselves out nicely. You can also easily convert these strings back into enum values. As usual, if you send a string to {{{Enum.Parse}}} which is not one of the values, an exception will be thrown.\n{{{\n>>> import System\n>>> t = Enum.Parse(TvState,"Off")\nOff\n>>> t.GetType()\nTvState\n}}}\nEnums are type definitions, and can appear outside classes. But they are often found inside classes, and serve to specify arguments.\n{{{\nclass TvController:\n enum TvState:\n Off\n On\n Standby\n \n [property(State)]\n _state as TvState\n\n def ResetState(state as TvState):\n ...\n}}}\nThe greatest advantage to using enums is that they describe self-documenting and limited sets of values. If it was {{{def ResetState(state as int)}}} we would have no idea what the valid integers were, (out of four billion or so). We would have to depend on some kind person's comments. \n\nEnumsAsIntegers\n\n
Boo uses Python syntax and a lot of cool Python features like string and array slicing, list comprehensions, etc. But it is a very different animal, in the same way that Java is obviously based on C++ syntax but isn't C++. In a way, syntax isn't that important, it's just the skin of the language. Python is a dynamically-typed language, Boo is mostly a statically typed language (but see DuckTyping) that cleverly uses type inference to avoid having to specify types explicitly in most cases.\n\n
The {{{-wsa}}} switch makes Boo behave like languages like Ruby or Lua, which require an {{{end}}} to finish each block.\n{{{\n# @compile{booc -wsa wsa.boo}\ni = 0\nwhile i < 10:\n if i > 5:\n print i\n end\n if i <= 5:\n print '-'\n else:\n print '*'\n end\n i = i + 1\nend\n}}}\n
Boo comes with a command-line interpreter, {{{booish}}}.\n\nA "graphical" prompt is more useful, since you can work meaningfully with Forms. The Boo plugin for SharpDevelop has a nice prompt; ScibooEditor also offers one. The last gives the option of printing out the type as well as the value of an expression, which is why I've used it in this tutorial.\n\nThe ScibooEditor's Boo prompt has some extra commands begining with a slash:\n{{{\n>>> /pwd\nD:\sstuff\ssciboo\ssciboo\n>>> /cd ..\n>>> /pwd\nD:\sstuff\ssciboo\n>>> /edit readme.txt\n>>> help(Math) @ edit\n}}}\nThe {{{@}}} is used to redirect output of an expression into an editor buffer, which is particularly useful for {{{help}}} and anything which generates a lot of output.\n\n\n
All objects in Boo are garbage-collected. If an object is just hanging around and isn't attached to a variable or another object, then it's considered garbage and will be collected. \n
Boo supports //slicing// on strings. This is a nice feature borrowed from Python; you can specify a range of indices to be extracted as a substring. If the upper bound isn't specified, then it's the rest of the string, and if there's no lower bound, then it is everything up to the upper bound. -1 means the last position, -2 is the second-last position, etc.\n{{{\n>>> s[0:1]\n(System.String) 'H'\n>>> s[1:2]\n(System.String) 'e'\n>>> s[1:]\n(System.String) 'ello, World!'\n>>> s[:-1]\n(System.String) 'Hello, World'\n}}}\n
A common operation is splitting a string into an array of strings. The basic{{{String.Split}}} method is passed one or more //delimiter// characters:\n{{{\n>>> s = "one two three four"\n(String) 'one two three four'\n>>> s.Split(char(' '),char('\st'))\n(String[]) ('one', 'two', 'three', 'four')\n>>> "jane,jimmy,alfred".Split(char(','))\n(String[]) ('jane', 'jimmy', 'alfred')\n}}}\n<<<\nNote for those who know this one from C#; you cannot pass {{{null}}} to this method. \n<<<\nThere is a very useful overloaded version of {{{String.Split}}} which takes an extra argument, which is the maximum number of elements in the split array. It can separate a string into the first word and the 'rest' easily:\n{{{\n>>> s.Split((char(' '),char('\st')),2)\n(String[]) ('one', 'two three four')\n}}}\nThe first argument is confusing; in the first case, it is expecting an indefinite number of characters to use as delimiters, and in the second case it is expecting an array of characters. It's particularly awkward when there's only one delimiter:\n{{{\n>>> names.Split((char(','),),2)\n(String[]) ('jane', 'jimmy,alfred')\n>>> names.Split(",".ToCharArray(),2)\n(String[]) ('jane', 'jimmy,alfred')\n}}}\nHere I've used two ways to construct an array consisting of one character; note the extra comma so that Boo knows that this is an array literal!\n\nThere is a serious "gotcha" when using {{{String.Split}}}; \n{{{\n>>> input = "20 4 2 4"\n(String) '20 4 2 4'\n>>> input.Split(char(' '))\n(String[]) ('20', '', '', '4', '', '2', '', '', '', '', '', '4')\n}}}\nThis is often appropriate behaviour (think of comma-separated data) but is probably not what you want with plain old text data. It leads to this kind of code:\n{{{\nfor w in line.Split(char(' ')):\n if len(w) > 0:\n print w\n}}}\n<<<\nNote. In the 2.0 framework, this need has been addressed. (You can of course choose to run BooOnNET2)\n<<<\nAnother way to split strings is to use RegularExpressions. Here the delimiter is specified to be one or more space character: '\ss' will match ' ','\st', etc and '+' means that the pattern '\ss' can match more than once. (If you leave out the '+', then this behaves exactly like the last split.)\n{{{\n>>> out = /\ss+/.Split(input)\n(String[]) ('20', '4', '2', '4')\n}}}\nThere is unfortunately also a gotcha: any whitespace at the start or the end spoils this nice picture.\n{{{\n>>> input = " 20 4 2 "\n(String) ' 20 4 2 '\n>>> out = /\ss+/.Split(input)\n(String[]) ('', '20', '4', '2', '')\n}}}\nGenerally {{{String.Split}}} is faster than {{{Regex.Split}}}.\n\n
Here is a perfectly generic routine which calcualates the sum of a sequence, and returns the number of elements and the sum. By declaring the sequence and the sum to be of type {{{duck}}}, this routine will work for any sequence, of any type that can be converted to double.\n{{{\ndef sum(seq as duck):\n y = 0.0\n k = 0\n for x as duck in seq:\n y += x\n ++k\n return k,y\n}}}\n\n{{{\nimport Tokens\n \nprint "array sum is ",sum((2.3,4.2,5.5))[1]\nprint "integers ",sum((10,20,30,40,50))[1]\ny = sum(Tokenizer("numbers.txt").Numbers())\nprint "num ",y[0],"sum is ",y[1]\n}}}\n\n\nWe can do better than this. This version will work with any type which supports addition\n{{{\ndef sum(seq as duck):\n y as duck\n k = 0\n for x as duck in seq:\n if k == 0:\n y = x\n else:\n y += x\n ++k\n return k,y\n}}}\n
It is important to remember that assigning an object to a variable does not make a //copy// of that object. You can have a number of variables containing a //reference// to the same object.\n{{{\n>>> a1 = (1,2,3)\n(1, 2, 3)\n>>> a2 = a1\n(1, 2, 3)\n>>> a2[0] = 0\n0\n>>> a1\n(0, 2, 3)\n}}}\nThis is really not what you expect from working with numerical types, but copying large objects is expensive compared to copying numbers (which are four or eight bytes usually.) You can define your own ValueTypes in Boo, but there usually has to be a good reason for them.\n \nIf two objects are equal, then they are either the same object, or they are objects which have the same contents. The {{{is}}} operator will tell you when two references are the same.\n{{{\n>>> l1 = [1,2,3]\n(List) [1, 2, 3]\n>>> l2 = l1\n(List) [1, 2, 3]\n>>> l3 = [1,2,3]\n(List) [1, 2, 3]\n>>> l1 == l3\n(Boolean) true\n>>> l1 is l3\n(Boolean) false\n>>> l1 == l2\n(Boolean) true\n>>> l1 is l2\n(Boolean) true\n}}}\n\nSometimes you do want a copy of an object. Arrays have a {{{Clone}}} method, but lists do not (which was probably an oversight.)\n{{{\n>>> a3 = a1.Clone()\n(Int32[]) (1, 2, 3)\n>>> a3 == a1\n(Boolean) true\n>>> a3 is a1\n(Boolean) false\n>>> l1 = [1,2,3]\n(List) [1, 2, 3]\n>>> l2 = l1.Clone()\n------------^\nERROR: 'Clone' is not a member of 'Boo.Lang.List'.\n>>> l2 = l1[:]\n(List) [1, 2, 3]\n}}}\nThe curious expression {{{l1[:]}}} is a slice of //all// the list - this trick works with all sliceable types, such as strings, lists and arrays. \n\n
A Boo program is unfortunately not as free and easy as a Python program. There are some rules which need to be followed - the most irritating of these is that there cannot be any variable declarations before your functions. This will not compile, with the cryptic error message 'expecting "EOF" found 'def':\n{{{\ni = 10\n\ndef f():\n return i\n \nprint f()\n}}}\nBoo is at heart a .NET language and really wants a main class (see BooClasses). Here is one workaround:\n{{{\n[Module]\nclass Globals:\n public static i = 10\n\ndef f():\n return i\n \nprint f()\n}}}\nAnd here is another:\n{{{\ni = 10\n\nf = def():\n return i\n \nprint f()\n}}}\n\n
Boo is like most programming languages and does not insist on a naming convention. In this reference, fields start with an underscore (_) and method names are in 'camel case'. The main thing is to pick a //consistent and documented// naming convention, such as used for other .NET languages.
Classes are the basic tool of ObjectOrientedProgramming. Unlike other .NET languages, it isn't necessary to //always// have a main class in a program.\n\nHere is a class {{{Person}}} representing a person which has two //fields// {{{_name}}} and {{{_age}}} and two //methods//; a constructor and {{{~ToString}}}. A class is a template for creating a new object, in the same way that a star-shaped cookie cutter is a template for creating star-shaped cookies. In this case, the object contains two pieces of information, the name and age of the person. The constructor initializes the object by setting any data, and thereafter you can call the methods of that object, as before.\n{{{\n# class1.boo\nclass Person:\n _name as string\n _age as int\n \n def constructor(name as string, age as int):\n _name = name\n _age = age\n\n def ToString():\n return _name\n\np = Person("john",36)\nprint p.ToString()\n}}}\n<<<\njohn\n<<<\nThis Boo code is entirely equivalent to the following C# program:\n{{{\nusing System;\n\nclass Person {\n protected string _name;\n protected int _age;\n \n public Person(string name, int age) {\n _name = name;\n _age = age;\n }\n\n public string ToString() {\n return _name;\n }\n}\n \nclass TestPerson {\n public static void Main(string[] args) {\n Person p = new Person("john",36);\n Console.WriteLine(p.ToString()); \n }\n} \n}}}\nThe Boo version is obviously shorter, but apart from not needing braces, its shortness comes from making sensible assumptions. Fields are assumed to be [[protected]], methods are assemed to be [[public]], unlike C# where the default is [[private]]. Any code at the end is made into the {{{Main}}} method of an implicit module class, which is generated with the name {{{class1Module}}} in this case. You can make Boo look almost like C# code and explicitly specify what the module class is going to be:\n{{{\nimport System\n[module]\nclass TestMain:\n public static def Main():\n Console.WriteLine("hello, world!")\n}}}\n\nOverridingAndInheritance\nNamingConventions
In the CLI framework, everything ultimately derives from {{{Object}}}. Which is a way of saying that {{{Object}}} defines common behaviour for all objects. The most common behaviour you will need to override is how an object converts itself to a string; this is the {{{~ToString}}} method. Whenever the framework needs a text representation of an object, it will ask this method (this is how {{{print}}} knows how to show values). The base behaviour is simply to return the class name, which is safe and often useful (especially in an interactive session) but one can override {{{~ToString}}} to return anything appropriate.\n\nFor instance, if we had defined {{{~ToString}}} in the {{{Person}}} class like this:\n{{{\n override def ToString():\n return _name\n}}}\nthen the object will know how to print itself out:\n{{{\np = Person("jane",25)\nprint p\n}}}\nThe basic strategy of inheritance is take some existing class and extend it. For instance, an {{{Employee}}} is a {{{Person}}} (well, usually!). It has the same behaviour as a {{{Person}}}, except it has an unique ID as well.\n{{{\nclass Employee(Person):\n _employeeId as int\n \n def constructor(name as string, age as int, id as int):\n super(name,age)\n _employeeId = id\n \n override def ToString():\n return super.ToString() + " id = " + _employeeId\n \ne = Employee("James",47,2333)\nprint e\n}}}\n<<<\nJames id = 2333\n<<<\nPlease note the new keyword {{{super}}}; it refers to the parent class. This is how {{{Employee}}}'s constructor can initialize the {{{Person}}} parts of the object, and how its string can be built from the inherited behaviour.\n\nIt is not necessary to always call the base class' constructor, if that constructor takes no arguments (the so-called //default// constructor). If there is no constructor, then any fields are initialized to zero or null, whatever the sensible default value is.\n{{{\nclass Base:\n public X as double\n \n def constructor():\n X = 1.0\n\nclass Inherits(Base):\n public Y as double\n \nb = Inherits()\nb.Y = 2.0\nprint b.X,b.Y\n}}}\nWe can say that an {{{Inherits}}} object is a kind of specialized {{{Base}}} object.\n<<<\nJava programmers should note that methods are not virtual by default, and you need to explicitly indicate when you are overriding an inherited method. This corresponds closely to C#; knowing what C# will do usually will tell you what Boo's behaviour will be.\n<<<\n\n\n\nObjectProperties
This is a nice example of usefully implementing the {{{~IDisposable}}} interface. Together with {{{using}}}, this gives you a way to redirect the output of {{{print}}} to a file. Please note that {{{Dispose}}} is not a virtual method and does not need {{{override}}}.\n{{{\nclass RedirectOutput(IDisposable):\n _consoleWriter as TextWriter\n _out as TextWriter\n \n def constructor(outf as TextWriter):\n Init(outf)\n \n def constructor(file as string):\n Init(File.CreateText(file))\n \n def Init(outf as TextWriter):\n _consoleWriter = Console.Out\n _out = outf\n Console.SetOut(_out)\n\n # implement IDisposable\n def Dispose():\n Console.SetOut(_consoleWriter)\n _out.Close()\n}}}\nThe basic techique is straightforward; the {{{~SetOut}}} method lets you specify a new {{{~TextStream}}} for {{{Console}}} to write to; we just have to remember what the original {{{~TextStream}}} was, and restore it when the object is disposed.\n{{{\nusing RedirectOutput("out.tmp"):\n print "here's the first line"\n print "and the second"\n\nsw = StringWriter()\nusing RedirectOutput(sw):\n print "val = ",val,"; delta = ",delta\ns = sw.ToString()\n}}}\n
When I first started learning C#, I was suprised that there was no easy way to read in numbers. (Maybe this was considered a very old-fashioned thing for a thoroughly modern language to do; apparently Java has this issue as well.) You have got to split the input up and convert the strings to numbers yourself. Here is a program to read all the numbers from a file and calculate the average.\n{{{\nimport System\nimport System.IO\n\nsum = 0.0\nk = 0\nfor line in Console.In:\n words = line.Split(char(' '),char('\st'))\n for w in words:\n if len(w) > 0:\n try:\n x = double.Parse(w)\n sum += x\n ++k\n except:\n print w,"was not a number"\n return\nprint "numbers " + k + " average was " + sum/k\n}}}\nIt is not a beautiful program, because the 'payload' (the part that does the calculation) is small compared to the surronding machinery.\n\nHere is one way to separate out things, using a generator method that uses {{{yield}}}.\n{{{\nimport System\nimport System.IO\n\ndef Numbers():\n for line in Console.In:\n words = line.Split(char(' '),char('\st'))\n for w in words:\n if len(w) > 0:\n yield double.Parse(w)\n\n\nsum = 0.0\nk = 0\ntry:\n for x in Numbers():\n sum += x\n ++k\nexcept e as Exception:\n print e.Message\n return\nprint "numbers " + k + " average was " + sum/k\n}}}\nYou can make this even simpler if we make the assumption that if {{{double.Parse}}} fails, then the result is zero. Although this seems like foolishly throwing away error information, it's the way some scripting languages like AWK work. Often we have files composed of numbers, with an understood format that won't have suprises (it will often be the output of some other program.) We need to write small scripts to rapidly extract information from them.\n{{{\ndef SafeParse(w as string):\n try:\n return double.Parse(w)\n except:\n return 0.0\n\ndef Numbers():\n for line in Console.In:\n words = line.Split(char(' '),char('\st'))\n for w in words:\n if len(w) > 0:\n yield SafeParse(w)\n}}}\nThe main loop now becomes about as simple as it will get.\n{{{\nsum = 0.0\nk = 0\nfor x in Numbers():\n sum += x\n ++k\nprint "numbers " + k + " average was " + sum/k\n}}}\n\nThere is another approach to splitting up a text stream into strings and numbers, see ReadString.\n\n(To get an even simpler main program, see GenericProgramming)\n\n
The {{{TextReader}}} class doesn't give us the ability to read delimited text, except for lines. You can read characters one by one, and collect the strings yourself. {{{Read}}} returns an integer, which has to be cast to {{{char}}}. It does this because it returns -1 on end of file, which is not a valid character. So we read one character at a time until either we have found a non-whitespace character, or we have run out of characters. Then the characters are read and appended to a {{{~StringBuilder}}} object, which is an efficient way of building up a string.\n{{{\nimport System.Text\nimport System.IO\n\ndef ReadString(tr as TextReader):\n ch = tr.Read()\n while ch != - 1 and char.IsWhiteSpace(cast(char,ch)):\n ch = tr.Read()\n # may have run out of input...\n if ch == -1:\n return null\n # we have a non-whitespace char!\n sb = StringBuilder()\n while ch != -1 and not char.IsWhiteSpace(cast(char,ch)):\n sb.Append(cast(char,ch))\n ch = tr.Read()\n return sb.ToString()\n\ns = """\n1 2.3 hello\n2 5.6 dolly\n"""\n\nsr = StringReader(s)\ns = ReadString(sr)\nwhile s:\n print s\n s = ReadString(sr)\nprint "that's all, folks!"\n}}}\nIt is now straightforward to pull in the next integer, double, etc:\n{{{\ndef ReadInt(tr as TextReader):\n return int.Parse(ReadString(tr))\n \ndef ReadDouble(tr as TextReader):\n return double.Parse(ReadString(tr))\n}}}\n
Lists are indexed collections, like arrays, but unlike arrays they are resizeable. They are also not of a specific type (that is, they are //generic//) and can be a lot slower than arrays. Flexibility generally comes at a price, but often the price is reasonable. Lists are tremendously useful things, and if you later need efficiency, it's easy to convert them to arrays.\n\nList literals are a set of values inside square brackets, like in Python. There are methods to add, remove and insert elements, which operate on the list object itself and don't create new objects, as do the string methods. (The List object is therefore called //mutable//.)\n{{{\n>>> list = [2,4,5,2]\n[2, 4, 5, 2]\n>>> list.Add(10)\n[2, 4, 5, 2, 10]\n>>> list.RemoveAt(3)\n[2, 4, 5, 10]\n>>> list.Remove(2)\n[4, 5, 10]\n>>> list.Insert(2,20)\n[4, 5, 20, 10]\n}}}\nConfusion can sometimes happen between {{{RemoveAt}}} and {{{Remove}}}; the first is passed an index, and the second is passed a value. It's important to get right, because using the wrong method will not give an error.\n\nLike strings, there is an {{{IndexOf}}} method. The {{{Contains}}} method and the {{{in}}} operator are equivalent ways to test for the presence of a particular element in a list.\n{{{\n>>> list.Contains(20)\n(Boolean) true\n>>> 20 in list\n(Boolean) true\n>>> list.IndexOf(20)\n(Int32) 2\n}}}\nYou can concatenate lists together (like arrays) and append new lists. As usual, {{{+=}}} is just a shortcut for the full sum expression. The {{{Extend}}} method doesn't create a new list!\n{{{\n>>> list = list + [30,40]\n(List) [4, 5, 20, 10, 30, 40, 30, 40]\n>>> list += [30,40]\n(List) [4, 5, 20, 10, 30, 40]\n>>> list.Extend([50,60])\n(List) [4, 5, 20, 10, 30, 40, 30, 40, 50,60]\n}}}\nPlease note that the size of a list is {{{Count}}}, not {{{Length}}}! This kind of confusion is traditional in .NET. The Python-style {{{len}}} builtin is more consistent.\n{{{\n>>> len(list)\n9\n>>> list.Length\n---------^\nERROR: 'Length' is not a member of 'Boo.Lang.List'.\n>>> list.Count\n9\n}}}\nYou can convert a list into an array of a specified type, but it won't always succeed. GeneratorExpressions provide a convenient way to specify how you want to convert a list.\n{{{\n>>> a = array(int,list)\n(Int32[]) (4, 5, 20, 10, 30, 40, 30, 40, 50)\n>>> array(string,['one','two','three'])\n(String[]) ('one', 'two', 'three')\n>>> list = [2,4]\n(List) [2, 4]\n>>> array(string,list)\nSystem.InvalidCastException: At least one element in the source array\ncould not be cast down to the destination array type.\n>>> array(string,x.ToString() for x in list)\n(String[]) ('2', '4')\n}}}\n<<<\nIf you already know .NET, note that the List class is similar but not the same as ArrayList. You are free of course to use ArrayList, but will then lose all the nice syntactical support.\n<<<\n\nBooHashes
ReadingConsoleText\nFindingFiles\nReadingFiles\nReadingNumbers\n\n
.NET provides a rich variety of functions for manipulating files and directories. They are mostly in the {{{System.IO}}} namespace. For instance, {{{Directory.GetFiles}}} returns an array containing all the filenames found in a directory. Here "." as usual stands for the current directory, and we use {{{GetFullPath}}} to get it into a sensible form.\n{{{\n>>> import System.IO\n>>> files = Directory.GetFiles(".","*.boo")\n>>> files\n(String[]) ('.\s\sast.boo', '.\s\sAttemptMacro.boo', '.\s\sPlotMacro.boo', \n'.\s\sSampleMacro.boo', '.\s\sTestAttemptMacro.boo', '.\s\sTestPlotMacro.boo',\n'.\s\sTestSampleMacro.boo')\n>>> Path.GetFullPath(files[0])\n(String) 'C:\s\snet\s\ssciboo\s\sexamples\s\smacros\s\sast.boo'\n}}}\n
There is no equivalent to {{{range}}} for floating-point numbers. It would be useful for code like this which runs over a range of numbers with a fractional step:\n{{{\nx = 0.0\nwhile x < 5.0:\n print x\n x += 0.1\n}}}\nIt's not just the extra typing that is a problem here - it is notoriously easy to forget to add the statement that increments your variable, and you then have an infinite loop.\n\nThe clearest way to implement {{{frange}}} is as a //generator method//. This is a function that uses {{{yield}}} instead of {{{return}}}. This code is exactly equivalent to the above, except that we have moved the loop inside {{{frange}}}.\n{{{\ndef frange(x1 as double, x2 as double, xd as double):\n x = x1\n while x < x2:\n yield x\n x += 0.1\n \nfor x in frange(0,5.0,0.1):\n print x\n}}}\n
New variables are created by assigning values to them. They take their type from the expression, although you can declare a type explicitly. There are the numerical types, a string type, and arrays of these types. \n{{{\n>>> z = 1.2\n(Double) 1.2\n>>> 2*z + 1\n(Double) 3.4\n>>> s = "Hello, World!"\n(String) 'Hello, World!'\n>>> s = 10\n--------^\nERROR: Cannot convert 'System.Int32' to 'System.String'.\n}}}\nOnce a variable is declared to have a particular type, Boo will strongly protest at any other kind of value being assigned to that variable! This is what is meant by Boo being a statically-typed language; generally it will look after you and prevent you from (for instance) comparing oranges and apples. After all, what does it mean to convert an integer to a string? {{{Convert.~ToString}}}? But what base? It's good to have that kind of thing explicit. The opposite counterpart of {{{Convert.~ToString}}} is {{{Parse}}}:\n{{{\n>>> i = 10\n(Int32) 10\n>>> i = "2"\n--------^\nERROR: Cannot convert 'System.String' to 'System.Int32'.\n>>> i = int.Parse("2")\n(Int32) 2\n>>> int.Parse("mouse")\nSystem.FormatException: Input string was not in a correct format.\n...\n}}}\nIf {{{Parse}}} fails it will raise a //run-time exception//. (If a user of your software gets to see this message, you have failed to protect her from your program's insides. See BooExceptionHandling.)\n\nYou may declare the type of a variable explicitly, in cases where Boo would not infer the correct type or where you want to be especially clear (e.g. fields within classses.) Such a pure declaration does not need an initial value.\n{{{\nxx as double = 0\ns as string\n}}}\nOnly one variable can be declared per line.\n\nStringHandling\nArraysAndLists\n
The brackets around array literals are not strictly speaking necessary, although useful to show that the numbers, etc., form a group.\n{{{\n>>> x = 1.0\n>>> y = 2.0\n>>> res = x,y\n>>> res\n(Double[]) (1, 2)\n}}}\nBoo supports variable //unpacking//. The left-hand side of an assignment can have more than one variable, and if the expression is some sequence, then the variables will be initialized in turn using that sequence.\n{{{\n>>> a,b = res\n>>> print a,b\n1 2\n>>> y,x = x,y\n>>> print x,y\n2 1\n}}}\nThis provides a convenient way to swop two variables! However, since it involves the creation of a temporary array, it isn't a particularly quick way to do a swop.\n\nThe error message is pretty explicit about what actually happens with these assignments.\n{{{\n>>> a,b = x\n----------^\nERROR: Cannot iterate over expression of type 'System.Double'.\n}}}\n
If you have an array or a list, then it's easy to iterate over the elements. The old-fashioned way involves too much typing:\n{{{\narr = (1,3,20,4,5)\n\nfor i in range(0,arr.Length):\n print i\n}}}\nInstead you can say\n{{{\nfor i in arr:\n print i\n}}}\nwhich is the equivalent of {{{foreach}}} in C# and VB.NET.\nAccessing the elements of a list often involves forcing the loop variable to have a specific type. In this case, Boo can't deduce that the list elements are meant to be integers:\n{{{\nlist = [1,3,20,4,5]\n\nfor i as int in list:\n print 2*i\n}}}\nWe can use array literals in {{{for}}} loops; this can be convenient if you need to do something for a small set of values that don't fit any obvious pattern:\n{{{\nfor i in (1,3,20,4,5):\n print 2*i\n}}}\n<<<\nIf you absolutely need to loop over the elements of an array as quickly as possible, then the {{{range}}} form is still faster. Boo will soon have a specific optimization for the {{{for i in range}}} case which will make it as fast as a {{{while}}} loop.\n<<<\n\n
Guido van Rossum starts his excellent Python book by getting people just to type expressions into the interactive Python prompt. This is excellent advice, which we'll apply to learning Boo as well. Boo (and Python) make good //programmer's// calculators; they understand hexadecimal and bit operations. Even if you're a diehard C++ or C# programmer, having the Boo prompt around is very useful. (BooInteractiveOptions.)\n{{{\n>>> 2.5+2*(1 + 0.234/4)\n(System.Double) 4.617\n>>> 23 + 24 - 4\n(System.Int32) 43\n>>> 0xFF\n(Int32) 255\n>>> 20/3\n(System.Int32) 6\n>>> 20/3.0\n(System.Double) 6.66666666666667\n}}}\nBoo arithmetic is standard computer arithmetic; the operation is done using the largest type present in the expression. Floating-point point calculations are usually done in double-precision, and any integers will be forced (//cast//) to double precision.\n\nWatch out for integer calculations, particularly division by an integer!\n\nNo scientific calculator is complete without transcendental functions. In the CLI, most libraries are in the {{{System}}} namespace, and the mathematical functions are in the class {{{Math}}}. We bring in namespaces with the {{{import}}} statement; classes can also be brought in, further saving our typing fingers.\n{{{\n>>> import System\n>>> Math.Sin(1.4)\n(System.Double) 0.98544972998846\n>>> 2*Math.PI\n(System.Double) 6.28318530717959\n>>> import System.Math\n>>> Sin(PI/2)\n(System.Double) 1\n>>> Min(10,20)\n(System.Int32) 10\n>>> Min(1.2,0.8)\n(System.Double) 0.8\n}}}\nMost of these functions operate on double-precision numbers, except for a few like the very useful {{{Min}}} and {{{Max}}}, which are //overloaded// with different versions for each numerical type. To find out what's contained in {{{Math}}} (or any class) use the built-in function {{{help}}}:\n{{{\n>>> help(Math)\nclass Math(object):\n\n public static E as double\n\n public static PI as double\n\n static def Abs(value as short) as short\n\n static def Abs(value as sbyte) as sbyte\n .....\n}}}\nThere are the bitwise operations, which are like those in C-style languages. {{{Convert.~ToString}}} is useful to see the results in hexadecimal (the second argument is the base).\n{{{\n>>> 1 << 2\n(System.Int32) 4\n>>> 16 >> 1\n(System.Int32) 8\n>>> 0xFFFF & 0x0FF0\n(System.Int32) 4080\n>>> Convert.ToString(4080,16)\n(System.String) 'ff0'\n}}}\nA very nice feature is the ability to write out long numbers with groups of digits separated by an underscore:\n{{{\n>>> 20_000\n(Int32) 20000\n>>> 20_000_000.2\n(Double) 20000000.2\n}}}\nUser-defined functions are easy to define:\n{{{\n>>> def hex(n as int):\n... print Convert.ToString(n,16)\n... \n>>> hex(0xFF << 2)\n3fc\n}}}\n\nBoo (like Python) requires that the body of a function be indented, so hit <tab> before the {{{print}}} statement; leave the block by simply hitting <enter> (that is, an empty line). Unlike Python, Boo usually requires you to declare the //argument type//. (See BooFunctions.)\n\nVariablesAndTypes
Hash tables have a number of names, dictionaries, maps, and associative arrays depending on the language. They behave rather like arrays, except you can index them with any object (not just integers) and they have no fixed size. They are so powerful and useful that a number of languages don't even bother with arrays or lists, and just use associative arrays (for instance, ~JavaScript and AWK.) \n{{{\n>>> a = {}\n>>> a["one"] = 1\n>>> a["two"] = 2\n>>> a[1] = "one"\n>>> a["one"]\n(Int32) 1\n>>> a["two"]\n(Int32) 2\n>>> a.Count\n(Int32) 3\n>>> len(a)\n(Int32) 3\n>>> a\n(Hash) {'two': 2, 1: 'one', 'one': 1}\n}}}\nIn the example, there are three associated pairs of values. The //key// which is used to index the //value// doesn't have to be a particular type (although it's usually useful to be disciplined about this!). In way, the term 'hash' or 'hashtable' is unfortunate. It emphasizes the implementation using hash tables, rather than the interface, which is what matters to the programmer. Python uses //dictionary//, which is better; it is something you use for looking things up.\n\nYou can use hashes as regular arrays, but this is not going to be as efficient.\n{{{\n>>> sqrs = {}\n>>> for i in range(1,10):\n... sqrs[i] = i*i\n... \n>>> sqrs\n(Hash) {9: 81, 8: 64, 7: 49, 6: 36, 5: 25, 4: 16, 3: 9, 2: 4, 1: 1}\n}}}\nConcern for efficiency has its place, but correctness is more important. We are told to get programs right before we get them fast. A better reason for not using hashes here is that people expect an array to be used in this case; to use a hash here is overkill and creates the expectation that you are doing to do some lookup voodoo. Hashes are however perfect for //sparse// arrays, where only a few entries are used, because you do not have to store all the entries whether they're filled or not.\n{{{\n>>> sa = {}\n>>> sa[10] = true\n>>> sa[100] = true\n>>> sa.Count\n(Int32) 2\n}}}\nBoo has a more general hash literal which lets you specify key-value pairs:\n{{{\n>>> ages = {'june':42, 'alice':35, 'peter':28}\n>>> for name in ages.Keys:\n... print name,ages[name]\n... \npeter 28\nalice 35\njune 42\n}}}\nThe {{{Keys}}} property of a hashtable lets you iterate through the keys and so access all the elements. Do not expect any particular sensible order; unlike arrays or lists, hashes are not ordered. The values can also be accessed as a sequence. This allows you to build lists or arrays easily, and these can be sorted.\n{{{\n>>> ls = [n for n in ages.Keys]\n>>> ls.Sort()\n(List) ['alice', 'june', 'peter']\n>>> arr = array(int,age for age in ages.Values)\n>>> arr\n(Int32[]) (28, 35, 42)\n}}}\nIt is possible to add key-value pairs directly, and remove entries by key. Just saying something like "ages['alice'] = null" isn't going to remove the entry - it just makes the value null (and that's a perfectly valid value.)\n{{{\n>>> ages.Add("mike",46)\n>>> ages.Remove("alice")\n>>> ages\n(Hash) {'peter': 28, 'june': 42, 'mike': 46}\n}}}\n\n\n
Boo supplies precisely one built-in function for dealing with input, and that is {{{prompt}}}. It is for prompting a user for input, and only makes sense for interactive console applications:\n{{{\n>>> prompt('enter some text:')\nenter some text:here we go again\n'here we go again'\n}}}\nThe framework supplies the Console object:\n{{{\n>>> import System\n>>> Console.In.ReadLine()\nhere we go again\n'here we go again'\n}}}\nSuprisingly useful programs can be done which filter standard input and write out transformed text. This is a complete program which makes its input uppercase:\n{{{\n# uppercase.boo\ntext = System.Console.In.ReadToEnd()\nprint text.ToUpper()\n}}}\nAfter compiling, it can be used like any other command - here are two options. With the first way, an input file is redirected into the program's standard input, and the program's standard output is redirected to an output file. In the second, {{{uppercase}}} is used to filter the output of {{{sort}}}:\n{{{\nuppercase < myfile.txt > myfile-upper.txt\nsort myfile.txt | uppercase > myfile-upper-sorted.txt\n}}}\nIt is usually a better idea to read text a line at a time. This program applies line numbers to its input:\n{{{\nimport System\nk = 0\nwhile (line = Console.In.ReadLine()) != null:\n print ++k,line\n}}}\nThis program is a little awkward, I think. It's a C# program rewritten in Boo. Much shorter, but the third line isn't that easy to read. (Please note that variable assignment in Boo is an expression, not a statement - it has a value.) Here is a version which shows off a great Boo feature; you can iterate over the lines of a text stream.\n{{{\nimport System\nk = 0\nfor line in Console.In:\n print ++k,line\n}}}\nHere's the two-line version:\n{{{\nfor k,line in enumerate(System.Console.In):\n print k,line\n}}}\nThe {{{enumerate}}} builtin is designed precisely to handle cases where you are iterating through some collection and want to keep track of the index.\n\nHere is a powerful way to get all your data as a string array, nicely chopped up into lines:\n{{{\nlines = array(string,line for line in System.Console.In)\n}}}\n\nReadingFiles\n
Often we want to access arbitrary files; the methods to read data are the same. The difference is that the input text stream has to be opened and later closed. ({{{System.Console.In}}} is always open.)\n{{{\n>>> import System.IO\n>>> fin = File.OpenText("tmp.txt")\n(StreamReader) System.IO.StreamReader\n>>> fin.ReadLine()\n(String) 'Here are '\n>>> fin.ReadLine()\n(String) 'a few lines'\n>>> fin.Close()\n}}}\nHere's yet another version of the line-listing program. This one is smart enough to make some basic sanity checks.\n{{{\nimport System.IO\nif len(argv) == 0:\n print "usage: <text file>"\n return \nif not File.Exists(argv[0]):\n print "file does not exist: ",argv[0]\n return\nfin = File.OpenText(argv[0])\nk = 0\nfor line in fin:\n print ++k,line\nfin.Close()\n}}}\n(Using {{{return}}} to exit from a program seems odd. But remember that this is //implicitly// the main function.)\n\nIt's recommended that you use a {{{using}}} statement. Not only does it look neat (it's clear from the block structure where the file reading is taking place) but it absolutely guarantees that your file will be closed, whatever happens. So the last five lines should be:\n{{{\nusing fin = File.OpenText(argv[0]):\n k = 0\n for line in fin:\n print ++k,line\n}}}\n\nReadingNumbers\nReadString\n\n
Functions can be defined to accept an indefinite number of arguments. Here is a function which can be passed any number of floating-point numbers. These arguments are specified as an array, with the special '*' operator. You can also pass arrays of doubles to {{{Max}}} if you use the //explode// operator, also '*':\n{{{\n>>> def Max(*x as (double)):\n... ret = double.MinValue\n... for val in x:\n... ret = System.Math.Max(ret,val)\n... return ret\n... \n>>> Max(2.4,2,4,5,4)\n(Double) 5\n>>> arr = (1.0,5,6,4,2)\n>>> Max(*arr)\n(Double) 6\n}}}\nNote that inside the function, the multiple arguments are simply treated as an array. And in fact this is how this feature is implemented; it's equivalent to saying something like {{{Max((2.0,4.3,2,0))}}}. \n\nSuch a function may have a number of normal arguments as well, but they must be in front:\n{{{\nimport System\ndef PrintNumbers(s as string, *numbers as (double)):\n Console.Write("{0}: ",s)\n for x in numbers:\n Console.Write("{0} ",x)\n Console.WriteLine()\n\nPrintNumbers("Some numbers",2,3,6,2,1)\n}}}\n
There are two ways to return multiple values from a Boo function. The first is to use reference parameters:\n{{{\ndef Modifies(ref a as int, ref x as double):\n a = 20\n x = 2.4\n \nk = 1\nz = 1.2\nModifies(k,z)\nprint k,z\n}}}\n<<<\n20 2.4\n<<<\nThese work like the {{{ref}}} parms in C#; but you are not required to use {{{ref}}} when passing a parameter. This means that just by looking at code, it's not possible to tell whether any variables are being modified by functions. This is bad news, so use this feature carefully.\n\nAnother way is to return the multiple values as an array.\n{{{\n>>> def ReturnsTwo():\n... return (20,2.4)\n... \n>>> res = ReturnsTwo()\n>>> res\n(Double[]) (20, 2.4)\n>>> x1,x2 = ReturnsTwo()\n>>> print x1,x2\n20 2.4\n}}}\nWe saw that arrays will be //unpacked// into variables, which makes this syntax quite elegant. Different types will be passed back as an array of {{{Object}}}. Unpacking will still work, ''if'' the variables have been previously defined.\n{{{\n>>> def ReturnsAMixedBag():\n... return ("a string",20,2.4)\n... \n>>> s,i1,x1 = ReturnsAMixedBag()\n}}}\n
Anonymous functions are often called //closures//. They bring two things to the party:\n* you don't have to make up a name\n* closures contain the current context\n\nThey tend to be more important in Boo than in Python, because there are no local ("nested") functions in Boo.\n\nHere is a variation on the example in BooFunctions:\n{{{\nline = prompt("enter yes or no:")\nif line == "yes":\n fn = def():\n print "yes was entered"\nelse:\n fn = def():\n print "no was entered"\n \nfn()\n}}}\nNote that closures may have arguments, just like regular functions.\n{{{\nif argv[0] == "sqr":\n fn = def(x as double):\n return x*x\nelif argv[0] == "cube":\n fn = def(x as double):\n return x*x*x\n}}}\nClosures are useful for shortcuts:\n{{{\ngetline = def():\n return System.Console.In.ReadLine()\nwhile line = getline():\n print line\n}}}\nThere is another closure syntax that uses braces. Please note that there is an //implicit// return statement here, although it never hurts to spell it out explicitly:\n{{{\ngetline = { System.Console.In.ReadLine() }\nwhile line = getline():\n print line\n}}}\nThe {{{map}}} builtin operates on any sequence using a specified function. For instance, this generates a sequence containing the squares of the first ten integers:\n{{{\ndef sqr(x as double):\n return x*x\n\niter = map(range(0,10),sqr)\nprint join(iter)\n}}}\nHere closures are particularly useful:\n{{{\niter = map(range(0,10)) def(x as double):\n return x*x\n}}}\nor using the brace syntax:\n{{{\niter = map(range(0,10),{x as double | x*x})\n}}}\nWhich syntax to use? Although you //can// put more than one statement into a brace closure (often called an inline closure) it isn't a good idea. The syntax is clearly meant for simple functions that return values. Whereas the block syntax is good for arbitrary actions.\n\nA closure can access //any// variable in an enclosing scope. This can be a very useful thing.\n{{{\nlist = [1,2,3,4,5]\nsum = 0.0\nl2 = map(list) def(i as int):\n sum += i\n return sum\nprint join(l2) \n}}}\n<<<\n1 3 6 10 15\n<<<\n\n\n
The particular issue with recursive functions in Boo is that they usually need an explicit return type, since it's hard to deduce type recursively. The classic example of a recursive function is the factorial function:\n{{{\ndef fact(n as int) as int:\n if n < 2:\n return 1\n else:\n return n*fact(n-1)\n}}}\n({{{fact}}} is not actually a very useful or efficient function, but it's traditional and makes the point.)\n\nHere is something more useful. Directory trees are naturally recursive structures; directories contain directories, etc. The {{{~FilesInFolder}}} function returns a list of all files matching some pattern in a directory and all subdirectories. It first creates a list containing all the regular files in a directory, and then for each directory found, adds the contents to that list. It terminates because eventually there are directories which only contain files, and so it doesn't call itself forever.\n{{{\nimport System.IO\ndef FilesInFolder(path as string, mask as string) as List:\n files = [file for file in Directory.GetFiles(path,mask)]\n for dir in Directory.GetDirectories(path):\n files.Extend(FilesInFolder(dir,mask))\n return files\n \nres = FilesInFolder(Directory.GetCurrentDirectory(),"*.boo")\nprint join(res,'\sn')\n}}}\n\nThe following function {{{Reverse}}} will work on on lists because they are sliceable; {{{ls[0:1]}}} is a new list containing the first element of {{{ls}}}, and {{{ls[1:]}}} is the rest of the list. (The strange expression {{{ls[:]}}} is the recommended way to make a new copy of a list.)\n{{{\ndef Reverse(ls as List) as List:\n if len(ls) < 2:\n return ls[:]\n else:\n return Reverse(ls[1:])+ls[0:1]\n}}}\n
In BooFunctions, we mentioned that functions may be assigned to variables. But what will be the type of these variables? There are times when it's necessary to spell out the exact type of an object, especially in function parameter lists. It would (in fact) be very useful to be able to pass a function to another function, which would then plot it, integrate it, or one of a million of possible things code can do with a function. \n{{{\ncallable DoubleFun(x as double) as double\n\ndef Dump(fn as DoubleFun):\n for i in range(0,10):\n print i,fn(i)\n \nDump(System.Math.Sin)\n}}}\nThe keyword {{{callable}}} creates a new callable type, and thereafter it can be named. It's quite similar in effect to using {{{typedef}}} in C with function pointers, but with the exception that {{{callable}}} creates a new type, not an alias. Something which is most un-C-ish is that Boo can make fairly smart conversions between callable types. Given the above definition for {{{Dump}}}, it comes as a pleasant suprise that the following code will also work:\n{{{\ndef isqr(i as int):\n return i*i\n\nDump(isqr)\n}}}\nTrying to pass obvious nonsense will give a compile-time error:\n{{{\ndef dbl(s as string):\n return s+s\n Dump(dbl)\n*** Dump(DoubleFun) is not compatible with the argument list\n*** '(callable(System.String) as System.String)'\n}}}\nThis tolerant attitude to callables makes working with fussy libraries very pleasant. For example, when using Winforms I can attach an action to a button by using a [[closure|AnonymousFunctions]]:\n{{{\nbtn.Click += def(o as object, e as EventArgs):\n print "I was clicked"\n}}}\nExcept that in most cases these values aren't used, so specifying them adds no value to the programming experience. Boo will allow you to say this:\n{{{\nbtn.Click += def():\n print "That's better!"\n}}}\n\nICallableInterface\n\n\n
Usually, Boo will let you call CallableTypes, but it's possible to make your own classes callable. All they must do is implement the {{{~ICallable}}} interface. \n{{{\nclass Fred(ICallable):\n def Call(args as (object)) as object: \n return (args[0] as string) + (args[1] as string)\n \nf = Fred()\nassert f('one','two') == 'onetwo'\n}}}\n
StartHere\n[[newTiddler]]\n
Boo strings correspond precisely to the underlying CLI {{{System.String}}} type. If you already have experience with a .NET language, then most of the old tricks still work.\n{{{\n>>> s = "Hello, Dolly!"\n(String) 'Hello, Dolly!'\n>>> s.Length\n(Int32) 13\n>>> len(s) # Python style!\n(Int32) 13\n>>> s[0]\n(Char) H\n>>> s[0] = char('h')\n-----^\nERROR: Property 'System.String.Chars' is read only.\n}}}\nThis is a crucial point; it is said that string objects are //immutable//; once created, the object itself cannot be modified. \n<<<\nIn Python, {{{s[0]}}} will give a string of length one, not the character itself! \n<<<\nAll string operations, like //concatenation//, produce new strings. {{{w += a}}} may at first seem like it's modifying the object (and in C++ this is probably what it would be doing) but it's just a shorthand for {{{w = w + a}}}. The variable {{{w}}} receives a //new// string and the old string is lost. (If this worries you, look at GarbageCollection and EfficientStringHandling.)\n{{{\n>>> w = "World"\n(String) 'World'\n>>> h = "Hello"\n(String) 'Hello'\n>>> h + ", " + w\n(String) 'Hello, World'\n>>> w = w + " + dog"\n(String) 'World + dog'\n>>> w\n(String) 'World + dog'\n>>> w += ' cat'\n(String) 'World + dog cat'\n}}}\nBoo is an entertaining way to play with CLI strings, since it's a good bet that most programs need to handle text data and there are very powerful facilities available. Generally all string comparison is case-sensitive:\n{{{\n>>> s == "Hello, dolly!"\n(Boolean) false\n>>> s.Substring(0,3)\n(String) 'Hel'\n>>> s.Substring(7,3)\n(String) 'Dol'\n>>> s.StartsWith("Hell")\n(Boolean) true\n>>> s.IndexOf("Dolly")\n(Int32) 7\n>>> s.IndexOf("dolly")\n(Int32) -1\n>>> s.Replace("!","")\n(String) 'Hello, Dolly'\n>>> s.Replace("Dolly","dolly")\n(String) 'Hello, dolly!'\n>>> \n}}}\nHow does one do case-insensitive comparisons? The second argument of {{{String.Compare}}} switches off case-sensitivity. This function is like the C function {{{strcmp}}}; it returns 0 for an exact match, and either +1 or -1 depending on whether the string is 'after' or 'before' the other.\n{{{\n>>> string.Compare("One","one",true)\n(Int32) 0\n>>> string.Compare("One","Two",true)\n(Int32) -1\n}}}\n\nStringInterpolation\nPythonStyleStrings\nSplittingStrings\nRegularExpressions
Although not fully available on both Mono and .NET, WinForms is an enjoyable framework for building user interfaces. Most WinForms development is done with a form designer in Visual Studio or SharpDevelop, which makes building applications more efficient because a lot of code gets written for you. But this is not the best way to learn a framework - it is better to understand how things fit together, before trusting the form designer.\n\nA Boo program that puts up a simple form is straightforward:\n{{{\nimport System.Windows.Forms\n\nform = Form(Text : "Hello!")\n\nApplication.Run(form)\n}}}\nGranted, it doesn't do anything interesting, but shows that a basic Windows.Forms application has a very simple structure; you create a form, and pass it to {{{Application.Run}}}. Note the convenience of specifying property values in the constructor call - we don't have to put {{{form.Text = "Hello!"}}} on a separate line.\n\nIt's particularly gratifying to play with WinForms classes from an interactive Boo prompt. (A non-console prompt is needed to do this properly - either SharpDevelop or Sciboo.)\n{{{\n>>> import System.Windows.Forms\n>>> import System.Drawing\n>>> f = Form(Text : "Sample")\n>>> btn = Button(Text : "Click me!")\n>>> f.Controls.Add(btn)\n>>> f.Show()\n}}}\nYou will now have a form floating around, complete with a button. It's easy to attach an action to the button's {{{Click}}} event. Whack the button and see the message:\n{{{\n>>> btn.Click += { print "I've been clicked!" }\n>>> I've been clicked!\n}}}\nThe multiline form of [[closure|AnonymousFunctions]] is more useful. Do note that the previous action will still be called:\n{{{\n>>> btn.Click += def():\n... print "again and again"\n... \n>>> I've been clicked!\nagain and again\n}}}\nThe most entertaining control I know is {{{~PropertyGrid}}}. By setting the {{{Dock}}} property, we make it fill the client area of the form; the {{{~SelectedObject}}} property is the object you wish to inspect. This will give you a browsable set of all the properties of the form.\n{{{\n>>> pg = PropertyGrid()\n>>> pg.SelectedObject = f\n>>> pg.Dock = DockStyle.Fill\n>>> f.Controls.Remove(btn)\n>>> f.Controls.Add(pg)\n}}}\nFor example, toggling the {{{~ControlBox}}} property will make the form lose its control buttons on the right-hand side of the caption bar.\n\n{{{\nimport System\nimport System.Windows.Forms\nimport System.Drawing\n\nform = Form(Text : "Environment Variables")\nlist = ListBox(Dock : DockStyle.Fill)\nform.Controls.Add(list)\nsb = StatusBar(Dock : DockStyle.Bottom)\nform.Controls.Add(sb)\n\nfor name in Environment.GetEnvironmentVariables().Keys:\n list.Items.Add(name)\n \nlist.SelectedIndexChanged += def():\n sb.Text = Environment.GetEnvironmentVariable(list.SelectedItem)\n\nApplication.Run(form)\n}}}\n\n
There are a handful of techiques which can vastly increase your power as a programmer. Regular Expressions are definitely one of these - and it's a cross-language skill; knowing regular expressions (or //regexes//, for short) in Boo transfers across to C# and in fact any language which has access to modern extended regex syntax. There is nothing better for //matching//, //extracting// and //replacing// text. However, there is a learning curve, which an interactive language like Boo makes much easier.\n\nBoo has regex //literals//, which simplify the usage of .NET regular expressions. For example, this is a program which prints out lines which begin with a word:\n{{{\nfor line in System.Console.In:\n if line =~ /^\ss[a-zA-Z]+/:\n print line\n}}}\nWithout regex literals and the match operator, it would look like this:\n{{{\nimport System.Text.RegularExpressions\nwordPattern = Regex("""^\ss[a-zA-Z]+""");\nfor line in System.Console.In:\n if wordPattern.Match(line) != Match.Empty:\n print line\n}}}\nNotice the use of triple double-quote strings to write literal strings containing backslashes; it's the equivalent of C#'s {{{@"...."}}} verbatim strings. It was also necessary to assign the regex to a variable, since it is needlessly inefficient to have to create regexes for each match. I also find it makes more sense to keep the regular expression in the code that uses it, rather than having to hunt for the initial definition.\n\nPlease note that {{{/.../}}} literals may not contain spaces. This is because Boo has to be able to distinguish regexes from arithmetic expressions. {{{x/2 + y/3}}} should be arithmetic, not a regex. Boo allows an extended syntax using @: {{{@/this dog is called \sw+/}}} is an extended regex literal. Usually, it's better to use {{{\ss}}} for whitespace, because it will match both spaces and tabs, which don't usually need to be distinguished.\n\nWhatever your language, Boo is a good tool to explore regexes. Here we are trying to find a regex to match a word followed by an integer:\n{{{\n>>> 'fred 20' =~ /\sw+\ss\sd+/\n(Boolean) true\n>>> 'fred 20' =~ /\sw+\ss\sd+/\n(Boolean) false\n>>> 'fred 20' =~ /\sw+\ss+\sd+/\n(Boolean) true\n>>> '552 20' =~ /\sw+\ss+\sd+/\n(Boolean) true\n>>> '552 20' =~ /[a-zA-Z]+\ss+\sd+/\n(Boolean) false\n}}}\nThe first regex didn't quite get it - it only matches cases where there is one space exactly between the word and the number. Unfortunately, '\sw' is too vague - it will also match a series of digits. So we need something more specific. And so on.\n\nIt is easier to //write// regular expressions than read them.\n\nThe match operator is convenient but often we need more information. Then {{{Regex.Match}}} needs to be called, which returns a {{{Match}}} object.\n{{{\n>>> r = /[a-zA-Z]+\ss+\sd+/\n>>> m = r.Match('so far, we have fred 999')\n>>> m.Value\n(String) 'fred 999'\n>>> m.Index\n(Int32) 16\n>>> m.Length\n(Int32) 9\n}}}\n\nRegular expressions can contain //groups//. Anything inside parentheses is considered a group, and effectively represents a submatch. The {{{Groups}}} property of the match then contains an indexed collection of all the submatches or //captures//. Consider this:\n{{{\n>>> r = /([a-zA-Z]+)\ss+(\sd+)/\n>>> m = r.Match('defininitely johnny 505')\n>>> gg = m.Groups\n>>> gg.Count\n(Int32) 3\n>>> gg[1]\n(Group) johnny\n>>> gg[2]\n(Group) 505\n}}}\n
A //property// of an object is refered to like any public field of that object. In WinForms, we saw that most controls have a {{{Text}}} property. If you change the {{{Text}}} property of a form, the form's caption bar updates. How is that done? The answer is that a property is in general a pair of functions; one is called the {{{getter}}} and returns the value, and the other is called the {{{setter}}} and sets some internal state. So {{{form.Text = "Hello!"}}} is actually {{{form.set_Text("Hello!")}}}. (It's done explicitly like this in Java.). In the {{{Person}}} class we had earlier, the _name field can be made public as a property:\n{{{\n Name:\n get:\n return _name\n set:\n _name = value\n}}}\nThis is such a common situation (why will be made clear just now) that Boo provides a shortcut. Here is a new version of {{{Person}}}:\n{{{\nclass Person: \n [property(Name)]\n _name as string\n\n [property(Age)]\n _age as int\n\n override def ToString():\n return _name\n \np = Person(Name:"john",Age:36)\nprint p\n}}}\nNote we no longer have a constructor to initialize those fields. But since there are now public properties, we can initialize them in the constructor call, and now it's very clear how we are initializing the object. (This is as close as Boo comes to //named arguments//, and can only be done in a constructor call.)\n\nGettersAndPreconditions\nWhyProperties?
There are several ways to build up complex strings in Boo, with various advantages. The first is to repeatedly use string concatenation (the overloaded {{{+}}} operator); the second is to use the framework's {{{Format}}} methods, and the third is Boo //string interpolation//. Certainly the first method isn't as easy to read as the other two!\n{{{\n>>> first = "Bill"\n>>> last = "Gates"\n>>> print "'" + first + "' = '" + last + "'"\n'Bill' = 'Gates'\n>>> print string.Format("'{0}' = '{1}'",first,last)\n'Bill' = 'Gates'\n>>> print "'${first}' = '${last}'"\n'Bill' = 'Gates'\n}}}\nWe'll get back to {{{Format}}} later, since it will give you control on how to display numbers, etc, more precisely. But like C-style {{{printf}}} formating, it moves the variables to the end of the format string, which could be quite long. Boo string interpolation is particularly cool with multi-line strings:\n{{{\nName = "John"\nManager = "Catbert"\nstuff = """\nDear ${Name},\n\nYour application is being considered. Please be patient, and don't phone us.\n\nYours,\n${Manager}\n"""\n\nprint stuff\n}}}\n<<<\nDear John,\n\nYour application is being considered. Please be patient, and don't phone us.\n\nYours,\nCatbert\n<<<\nSometimes we don't want to have string interpolation. In that case, use single-quoted strings.\n\nAny valid Boo expression can be used inside the {{{${}}}}. But longer expressions can be a bit much to chew:\n{{{\n>>> "It is now ${DateTime.Now}, ${Environment.GetEnvironmentVariable('USERNAME')}"\n(String) 'It is now 2/25/2006 3:39:21 PM, steve'\n}}}\nWhen to use single-quote versus double-quote in strings? It's best to pick a style and be consistent; the language doesn't care but your readers may get confused. Single-quote strings can be embedded in double-quote strings without needing nasty C-style escapes.\n\nThe {{{Format}}} method gives you precise control on how numbers are converted to strings.\n{{{\n>>> String.Format("{0:n}",20_433_344)\n(String) '20,433,344.00'\n>>> String.Format("{0:C}",2.45)\n(String) '$2.45'\n>>> String.Format("{0:E},{1:E},{2:E}",1.0,Math.PI,2.3)\n(String) '1.000000E+000,3.141593E+000,2.300000E+000'\n>>> String.Format("Port was {0:X}",0xFF << 4)\n(String) 'Port was FF0'\n>>> String.Format("{0,10}{1,10}",10.99,3.99)\n(String) ' 10.99 3.99'\n>>> String.Format("{0,10:C}{1,10:C}",10.99,3.99)\n(String) ' $10.99 $3.99'\n}}}\nThere is another kind of formating which gives you even more control. For example, this formats a standard 10-digit phone number nicely. Note that {{{ToString}}} is overloaded and understands all the above formats:\n{{{\n>>> num = 0123456789\n>>> String.Format("{0:(0##) ###-####}",num)\n(String) '(012) 345-6789'\n>>> num.ToString("(0##) ###-####")\n(String) '(012) 345-6789'\n}}}\nThese formats also apply to the {{{Write}}} and {{{~WriteLine}}} methods:\n{{{\n>>> for x in (1.0,2,3,5,6):\n... Console.Write("{0:E} ",x)\n... \n1.000000E+000 2.000000E+000 3.000000E+000 5.000000E+000 6.000000E+000 >>> \n}}}\n\n\n
All classes in the CLI derive from {{{Object}}}, which has a virtual method called {{{~ToString}}}. This is used whenever a string representation of an object is needed. It is nearly always useful to override {{{~ToString}}} in your custom classes, since then things like {{{print}}} can be used.\n\nThe default implementation gives the full name of your class.\n\n
Here is a simple custom attribute which extends Boo's {{{property}}} attribute. As with CustomMacros, the naming convention is <attribute>Attribute:\n{{{\n# nonempty.boo\nimport Boo.Lang.Compiler\nimport Boo.Lang.Compiler.Ast\n\nclass NonEmptyStringAttribute (PropertyAttribute):\n\n static preCondition = ast { value is not null and len(value) > 0 }\n \n def constructor(propName as ReferenceExpression):\n super(propName,preCondition.CloneNode())\n}}}\nThe //ast literal// is the expression we want to use as our property precondition; {{{~NonEmptyStringAttribute}}} is a simple subclass of {{{~PropertyAttribute}}}, and fills in the second argument to the base class's constructor - {{{~CloneNode}}} makes a copy of the AST expression.\n\nTo add this to your project, add nonempty.boo to your references:\n{{{\nbooc testnonempty.boo -r:nonempty.dll\n}}}\nHere's a test program to exercise our attribute:\n{{{\nclass Person:\n [NonEmptyString(Name)] # line 4\n _name as string\n \n [property(Age)]\n _age as int\n\n override def ToString():\n return _name\n \np = Person(Name:"john",Age:36)\np.Name = '' # line 14\nprint p\n}}}\n<<<\nUnhandled Exception: System.~ArgumentException: precondition\n '(value is not null) and (len(value) > 0)' failed:\n at Person.set_Name(String value) in C:\snet\ssciboo\sexamples\sprop1.boo:line 4\n at ~Prop1Module.Main(String[] argv) in C:\snet\ssciboo\sexamples\sprop1.boo:line 14\n<<<\nCompare this with the example in GettersAndPreconditions; again, the notation is not only more compact, but it expresses the code's intention better.\n
Basic control statements look very much like Python.\n{{{\na = 10\nif a > 5:\n print "a was ",a\nelif a > 8:\n print "a was too large!"\nelse:\n print "no go!"\n print "a is too small"\n}}}\nThat will run fine as either Python or Boo. Same for this while loop:\n{{{\ni = 0\nwhile i < 10:\n if i > 5:\n print i\n if i <= 5:\n print '-'\n i = i + 1\n}}}\nOf course, there are easier ways to do that.\n\nNote that Boo statements can have modifiers, which can make it look quite Perl-ish.\n{{{\nfor i in range(0,10):\n print i if i > 5\n print '-' unless i > 5\n}}}\n\nThere is also an {{{unless}}} statement, which sometimes reads better than {{{if not}}}:\n{{{\na = 1\nunless a == 2:\n print 'yay'\n}}}\nThe {{{for}}} statement in general will iterate over members of a collection:\n{{{\nimport System.Console\ns = "hello dolly"\nfor ch in s:\n Write(ch) if not char.IsWhiteSpace(ch)\nWriteLine()\n}}}\nIf you don't like the way that Boo blocks 'dangle' Python-style, consider WhiteSpaceAgnosticBoo.\n\n\n
Boo is mainly a statically-typed language, like C#, C++ and so forth. A variable must have a valid type at compile-time, and so any method calls can be resolved by the //compiler//. It can be tedious to spell thing s out like this, but it gives fast programs that will not generally suprise you in the middle of the night with a 'method not found' exception.\n\nWith dynamic typing, it's not possible to know in advance what kind of object a variable may be holding, so the //run-time// has to look up methods on the run. This is often called //late binding//, and is very flexible, but at the cost of efficiency and compile-time checking. Languages like Python consider the flexibility and resulting programmer efficiency to be more important than runtime efficiency, and that static testing is never as good as comprehensive unit testing.\n\nThese are all valid arguments so a programming language should offer both static and dynamic typing, and allow this to be a decision made by the programmer, rather than made by the language designer. Why not have the best of both worlds?\n\nThe term 'duck-typing' has been popularized by the Ruby community. If it walks like a duck and quacks like a duck, the saying goes, then it must be a duck. An obvious case is when a programmer needs to use external objects, particularly COM objects, that will only be available at run-time. Here is the classic example of Boo calling Internet Explorer via its automation interface:\n{{{\nimport System.Threading\n\ndef CreateInstance(progid):\n type = System.Type.GetTypeFromProgID(progid) \n return type() \n\nie as duck = CreateInstance("InternetExplorer.Application")\nie.Visible = true\nie.Navigate2("http://www.go-mono.com/monologue/")\n\nThread.Sleep(50ms) while ie.Busy\n\ndocument = ie.Document\nprint("${document.title} is ${document.fileSize} bytes long.")\n}}}\nThe word that makes it all possible is {{{duck}}}. This represents an object that can have //any// type at run-time. The Boo Codehaus article makes the useful suggestion that you can mentally replace 'duck' with 'any' if it makes more sense. (Boo has a tradition of SillyNames.)\n\nThis example could be done in C#, but would be rather more awkward. COM Interop remains an important technique in the Windows world; all Microsoft Office applications expose rich automation interfaces.\n\nCurrently, Boo does not support generics. But you can do Python-style generic programming with duck types. Consider this function {{{sum}}}, which is passed an initial value and a sequence:\n{{{\ndef sum(val as duck, seq as duck):\n for x in seq:\n val += x\n return val\n \nprint sum(0.0,(1.2,5.2,3.5))\nprint sum(0,[10,20,30])\nprint sum('',('one','two','three'))\n}}}\n<<<\n9.9\n60\nonetwothree\n<<<\n{{{sum}}} is does the job for //any// sequence of objects which understand the addition operator; an array of doubles, a list of ints, an array of strings.\n\n\nIt's important to stress that Boo assemblies using duck typing can still be consumed by other .NET languages. The dynamic method dispatch magic is supplied by {{{Boo.Lang.dll}}}, which is currently required for all Boo applications. (But see BooWithoutBooLang.)\n\nA class can obtain full control over its own method dispatch using the IQuackFu interface.\n\n\n\n
It's sometimes very useful for a class to take charge of its own method dispatch. Any class that implements the {{{~IQuackFu}}} interface has to define three things: how a method is called, how to set a property, and how to get a property. For instance, here is a class which wraps a hashtable and provides ~JavaScript-like access. That is, instead of saying {{{e['Alice']}}} we can say {{{e.Alice}}}.\n{{{\nclass Map(IQuackFu):\n _vars = {}\n \n #implement the IQuackFu interface\n def QuackSet(name as string, value):\n _vars[name] = value\n \n def QuackGet(name as string):\n return _vars[name]\n \n def QuackInvoke(name as string, args as (object)) as object:\n pass\n \ne = Map()\ne.Alice = 32\ne.Fred = 22\ne.John = 42\nprint e.Alice,e.Fred,e.John\n}}}\n
A TiddlyWiki is a personal Wiki which is completely self-hosted. It's all done on the client-side, with ~JavaScript, CSS and HTML, which makes it perfectly portable. This means that you cannot save new content online - you must save this as an HTML file on your computer and then edit it. Perhaps that seems to miss the point of a Wiki, but it is a very easy way to generate hypertext documents.\n\n
The prefered way to handle errors in modern languages is by using exceptions. These are meant to happen in //exceptional// circumstances. Handling exceptions means the error handling of your code is separate from the normal processing.\n\nThe syntax is similar to Python; any statements you wish to protect are put into the {{{try}}} block, and statements to handle the error are put into the {{{except}}} block.\n{{{\nstr as string\ntry:\n str = str.ToUpper()\nexcept:\n print "something happened!"\n}}}\nIf an exception occurs, a {{{try}}} will catch the exception, so that your user will not see the dreaded dialog of death.\n\nIt is often necessary to know what the //precise// exception was:\n{{{\nimport System\nstr as string\ntry:\n str = str.ToUpper()\nexcept e as NullReferenceException:\n print "str was null",e.Message\nexcept e as Exception:\n print "something weird happened!",e.Message\n}}}\nAny {{{try}}} block can be followed by a number of exception handlers. The general rule is this: handle the more specific exception first.\n
Some types will implicitly convert to other types, and so an explicit cast is unnecessary and ugly. Any numerical type will convert to any other numerical type. If a class implements an interface, then it can be automatically cast to that interface type; same for derived types. Your best guide (as always) is the compiler.\n\nBut be aware of some conversions which the compiler will allow but can only be decided at run-time.\n{{{\ndef one(o as object):\n print 'one',o\n \ndef two(s as string):\n print 'two',s\n \ndef three(n as int):\n print 'three',n\n \none("hello")\none(42)\ntwo("dolly")\n# two(66) <= compile-time error - string doesn't cast to int.\n# best overload for the method 'implicitCast1Module.two(System.String)'\n# is not compatible with the argument list '(System.Int32)'\nobj as object\nobj = "hello dolly"\ntwo(obj)\nobj = 42\nthree(obj)\nobj = 'hello'\nthree(obj) <= ok with compiler, but causes an InvalidCastException at run-time.\n}}}\nFunction parameters of type object are will accept all types, but the compiler is equally forgiving of passing plain objects to parameters of other object types. You will only know when the program is run! (Your opinion of this feature will probably be either joy or disapproval; either way this is one of the gotchas you need to remember.)\n\nBy the way, the static compile error reveals several Boo features. One is that {{{int}}} is an alias for {{{System.Int32}}}, and so forth. Second, that a standalone function is really a static method of the automatically generated module class. And third, that functions can be overloaded. This is why we are not simply told that the argument lists don't match.\n\nThere are two ways to //explicitly// cast a type to another in Boo, which come from a basic difference in the way types are handled in NET 1.1. A string is a reference object, and so {{{null}}} is a perfectly valid value for a string variable - it's said to be a //nullable// type. Contrast this with simple value types like integers - they do not have a value which means 'no integer'. Zero is not a good candidate; many meaningful integers are zero ;) \n\nThe first form works with all types, but raises either a compiler or run-time error if the cast is not possible. For instance, a variable of type {{{object}}} can contain any type, but {{{~InvalidCastException}}} will be raised if it doesn't contain the requested type.\n{{{\n >>> s = "Hello, World!"\n>>> n = 10\n>>> cast(double,n)\n(Double) 10\n>>> cast(string,n)\n----^\nERROR: Cannot convert 'System.Int32' to 'System.String'.\n>>> obj as object # declare as object (initial value null)\n>>> obj = "Hello, World!"\n>>> cast(int,obj)\nSystem.InvalidCastException: Specified cast is not valid.\n....\n}}}\n<<<\nNote: Booish is a marvelous tool which I recommend you always have open when learning Boo. But this is one area where it is not a reliable indication of how compiled code will behave, because Booish has DuckTyping switched on by default.\n<<<\n\nThe second form of typecast uses the {{{as}}} keyword as an operator. This example shows {{{as}}} used both in variable declarations and in type casts. These are actually very different usages.\n{{{\ns as object = "hello dolly"\nss = s as string\nprint ss.ToUpper()\n}}}\nYou //could// use {{{cast}}} here, but {{{as}}} doesn't raise an exception on failure. Instead it returns {{{null}}}. For this reason, {{{as}}} cannot be used with value types like numbers, etc. Here are two equivalent ways of saying the same thing:\n{{{\nk as object = 42\nif (ss = k as string) != null:\n print ss.ToUpper()\nelse:\n print "was not a string!"\n\nif k isa string:\n ss = (k as string).ToUpper()\n print ss\nelse:\n print "was still not a string!"\n\n}}}\nThe {{{isa}}} operator is useful for determining types at run-time; personally I find the second form more elegant.\n\n\n
There are times when a function has the same meaning, but a different implementation, for various types. For example, there is a whole host of functions named {{{System.Max}}}, for each of the numerical types. Here are two overloads of a {{{Square}}} function:\n{{{\ndef Square(n as int):\n return n*n\n \ndef Square(x as double):\n return x*x\n \nassert Square(10).GetType() == int\nassert Square(2.3).GetType() == double\n}}}\nIt is true that once {{{Square}}} is defined for a general numerical type like {{{double}}}, then it will work on {{{int}}}, for example. But the result will be always {{{double}}}. This is particularly important in cases like {{{Math.Max}}} where we really want the same type as the parameters.\n\nIt's true that this looks like extra typing (in both the finger and computer sense) and the Pythonistas will not be impressed. (Overloads like this are better expressed as generic functions, but for that we have to wait a bit.)\n\nFunctions with more than one parameter often have sensible defaults for the extra parameters. Boo does not have optional arguments, so overloading is the way to make functions more friendly:\n{{{\ndef DrawBox(pos as Point, size as Size, colour as Color):\n ....\n \ndef DrawBox(pos as Point, size as Size):\n DrawBox(pos,size,Color.Black)\n \ndef DrawBox(pos as Point):\n DrawBox(pos,Size(1,1),Color.Black)\n}}}\n\n<<<\nThe closest Boo comes to named parameters is specifying public properties of an object in the constructor call. For example, {{{btn = Button(Text : "Hello", Location : Position(100,100))}}}.\n<<<\n\nAs a rule of thumb, the parameter types should be as distinct as possible, if there are overloads over methods with the same number of arguments. Be aware that things can get ambiguous:\n{{{\n>>> def f(x as single):\n... return x\n... \n>>> def f(i as int):\n... return i\n... \n>>> f(2.3)\n-----^\nERROR: Ambiguous reference 'f': Input43Module.f(System.Single), Input44Module.f(System.Int32).\n}}}\nHere the rule of thumb is: with numerical arguments, always include {{{double}}}. The problem here is that the compiler can cast {{{double}}} to {{{x}}} as easily as it can cast to {{{int}}}.\n
Functions in Boo start with the {{{def}}} keyword, and the value is explicitly returned with {{{return}}}.\n{{{\ndef sqr(x as double):\n return x*x\n}}}\nThe main difference here with Python is that function //arguments// have usually got particular types. It's important to realize that this is as entirely as statically-typed (and efficient) as the C# equivalent:\n{{{\ndouble sqr(double x) {\n return x*x;\n}\n}}}\nJust as variable types are deduced from their initializing expressions, return types of functions can usually be deduced from the type of the expression they return. (But see RecursiveFunctions)\n\nSome languages take type inference further than this, but Boo (wisely, I think) requires argument types to be specified. If you leave out an argument type, then it's implicitly of type {{{Object}}} and would probably need to be cast to whatever type you wanted. Specifying argument types is good because you can tell just by looking at the function //signature// what arguments to pass. One of the strengths of strong-typing is that the language already documents many things for you. In a dynamic language such information has to be in a comment.\n\nUnlike C# or Java, Boo functions can stand alone. They may not be declared after any variable declarations, which may come to a shock to those expecting a completely free Python-like environment. (But, BooIsNotPython)\n\nThe arguments to a function are passed by value, but do remember that with objects you are passing a reference anyway (ReferencesAndObjects).\n{{{\n>>> res\n(Double[]) (20, 2.4)\n>>> def Fun(x as (double)):\n... x[0] = 1.0\n... \n>>> Fun(res)\n>>> res\n(Double[]) (1, 2.4)\n}}}\n\nFunctions are values, so you can assign them to variables (rather like //function pointers// in C.) They are CallableTypes.\n{{{\ndef yes():\n print "yes was entered"\n \ndef no():\n print "no was entered"\n\nline = prompt("enter yes or no:")\nif line == "yes":\n fn = yes\nelse:\n fn = no\nfn()\n}}}\n\nOverloadingMethods\nPassingMultipleValues\nReturningMultipleValues\nAnonymousFunctions\n\n\n
The best way to see generator expressions in action is to look at //list comprehensions//. This is another Python feature which Boo has borrowed. It is like a {{{for}}} statement inside a list. List comprehensions save us from writing out loops like this:\n{{{\nli = []\nfor i in range(0,10):\n li.Add(i)\n\nli = [i for i in range(0,10]\n}}}\nIn general, it is [//expression// {{{for}}} //var// {{{in}}} //expression// {{{if}}} //condition//].\n{{{\n>>> list = [2,4]\n[2, 4]\n>>> ls = [x.ToString() for x in list]\n['2', '4']\n>>> li = [i for i in range(0,10)]\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n>>> li = [2*i for i in range(0,10)]\n(List) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n>>> li = [i for i in range(0,10) if i % 2 == 0]\n(List) [0, 2, 4, 6, 8]\n}}}\nGenerator expressions actually produce a object, which you can use to iterate. The {{{array}}} builtin can understand an iterable object, so the following works. Note that there are no square brackets needed around the expression.\n{{{\n>>> ls\n(List) ['alice', 'june', 'peter']\n>>> array(string,n.ToUpper() for n in ls)\n(String[]) ('ALICE', 'JUNE', 'PETER')\n}}}\n\nGeneratorMethods\n\n
Some statements in Boo, like {{{print}}} and {{{using}}}, are actually implemented as statement macros. Statement (or syntactical) macros may take a number of arguments, and they may have a following controlled block. The crucial point is that the arguments are //not evaluated// before being passed to the macro; they are compiled to AST (Abstract Syntax Tree) expressions, which can be manipulated. Macros usually //generate// code. They are classes in a DLL which is then referenced by the code that uses the macro. They are 'evaluated' at compile-time and are in effect extensions to the compiler.\n\nConsider this simplified {{{print}}} macro:\n{{{\nimport Boo.Lang.Compiler\nimport Boo.Lang.Compiler.Ast\nimport Boo.Lang.Compiler.Ast.AstUtil\n\nclass PrntMacro(AbstractAstMacro):\n\n override def Expand(macro as MacroStatement):\n li = macro.LexicalInfo\n block = Block()\n for arg in macro.Arguments:\n block.Add(CreateMethodInvocationExpression(li,\n CreateReferenceExpression("System.Console.Write"),\n arg\n ))\n block.Add(CreateMethodInvocationExpression(li,\n CreateReferenceExpression("System.Console.Write"),\n StringLiteralExpression(" ")\n ))\n block.Add(CreateMethodInvocationExpression(li,\n CreateReferenceExpression("System.Console.WriteLine"),\n StringLiteralExpression("")\n ))\n return block\n}}}\nLike with CustomAttributes, the class name of the macro must end in 'Macro' and the name will be the first part in lower case. What the macro does is actually straightforward, but getting there requires a lot of typing. We create an AST Block, and for each argument add a call to {{{System.Console.Write}}} with that argument, followed by a similar call to write out a space; finally we make a {{{System.Console.~WriteLine}}} call to finish the line. \n\nI have a irresistable urge to refactor out common code in cases like this. Here is a macro, {{{display}}}, which is useful in debugging:\n{{{\nimport Boo.Lang.Compiler\nimport Boo.Lang.Compiler.Ast\nimport Boo.Lang.Compiler.Ast.AstUtil\n\nclass DisplayMacro(AbstractAstMacro):\n static Write = "System.Console.Write"\n static WriteLine = "System.Console.WriteLine"\n \n def L(s as string):\n return StringLiteralExpression(s)\n\n def Call(li as LexicalInfo, block as Block, name as string, expr as Expression):\n block.Add(CreateMethodInvocationExpression(li,\n CreateReferenceExpression(name),\n expr\n ))\n\n override def Expand(macro as MacroStatement):\n li = macro.LexicalInfo\n block = Block()\n for arg in macro.Arguments:\n Call(li,block,Write,L(arg.ToString()))\n Call(li,block,Write,L(" = "))\n Call(li,block,Write,arg)\n Call(li,block,Write,L(" "))\n Call(li,block,WriteLine,L(""))\n return block\n}}}\nWith the method invocation code factored out, the main loop becomes much clearer. We write out the argument //as a string//, followed by the argument //as a value//. Here is how you would use it:\n{{{\n# @compile{booc -r:DisplayMacro.dll TestDisplayMacro.boo}\nx = 20\ns = "hello dolly"\nz = 2.3\ndisplay x,s,z+2\n}}}\n<<<\nx = 20 s = hello dolly z + 2 = 4.3 \n<<<\nThere are some important limitations of syntactical macros. They manipulate //syntax//, but have no way to know that (for instance) s was a string variable, and that you therefore should quote the output.\n\nMacros may also be passed a block and perform transformations upon each statement. The task is to implement a {{{with}}} statement that works like the one in VB or Pascal. Unfortunately, we don't have any semantic information at this stage of the compiler pipeline, so we insist that all references are prefixed with '_'\n{{{\naLongVariable = Client()\nwith aLongVariable:\n _Name = "Joe Dog"\n _Age = 34\n}}}\nThe {{{with}}} statement becomes expanded as:\n{{{\naLongVariable.Name = "Joe Dog"\naLongVariable.Age = 34\n}}}\nHere is the code, taken from the {{{examples/macros/with}}} directory:\n{{{\nimport Boo.Lang.Compiler.Ast\nimport Boo.Lang.Compiler.Ast.Visitors\n \nclass WithMacro(AbstractAstMacro):\n \n private class NameExpander(DepthFirstTransformer):\n \n _inst as ReferenceExpression\n \n def constructor(inst as ReferenceExpression):\n _inst = inst\n \n override def OnReferenceExpression(node as ReferenceExpression):\n // if the name of the reference begins with '_'\n // then convert the reference to a member reference\n // of the provided instance\n if node.Name.StartsWith('_'):\n // create the new member reference and set it up\n mre = MemberReferenceExpression(node.LexicalInfo)\n mre.Name = node.Name[1:]\n mre.Target = _inst.CloneNode()\n \n // replace the original reference in the AST\n // with the new member-reference\n ReplaceCurrentNode(mre)\n \n override def Expand(macro as MacroStatement) as Statement:\n assert 1 == macro.Arguments.Count\n assert macro.Arguments[0] isa ReferenceExpression\n \n inst = macro.Arguments[0] as ReferenceExpression\n \n // convert all _<ref> to inst.<ref>\n block = macro.Block \n ne = NameExpander(inst)\n ne.Visit(block)\n return block\n}}}\n\nThe major problem currently with custom macros is that you do need to get a working knowledge of the important AST classes, and the only reference for these is the source. To build expressions and statements, you need to know how the compiler represents them. That's not as bad as it sounds - {{{src/Boo.Lang.Compiler/Ast}}} contains all the classes, one per file.\n\nHere are two neat tricks for discovering the structure of an expression. Use an {{{ast}}} literal to get the AST form of a given expression in Booish, and explore from there.\n{{{\n>>> e = ast {2*x + y}\n>>> e\n(BinaryExpression) (2 * x) + y\n>>> e.Left\n(BinaryExpression) (2 * x)\n>>> e.Right\n(ReferenceExpression) y\n>>> e = e.Left\n>>> e.Left\n(IntegerLiteralExpression) 2\n>>> e.Right\n(ReferenceExpression) x\n}}}\n\nThe second method involves generating an XML representation of the AST. There is a file {{{ast-to-xml.boo}}} in the {{{examples}}} directory which will convert Boo source into XML. This can be very verbose so feed it small snippets at first. The following two lines\n{{{\ns = "hello"\nk = s.Length\n}}}\ngenerated 68 lines of XML, of which I'll only give you the part representing {{{k = s.Length}}}:\n{{{\n <Statements xsi:type="ExpressionStatement">\n <Expression xsi:type="BinaryExpression">\n <Operator>Assign</Operator>\n <Left xsi:type="ReferenceExpression" Name="k" />\n <Right xsi:type="MethodInvocationExpression">\n <Target xsi:type="MemberReferenceExpression" Name="get_Length">\n <Target xsi:type="ReferenceExpression" Name="s" />\n </Target>\n </Right>\n </Expression>\n </Statements>\n}}}\nwhich we can hand translate into Boo calls like so:\n{{{\nstmt = ExpressionStatement(BinaryExpression(\n Operator: BinaryOperatorType.Assign,\n Left: ReferenceExpression("k"),\n Right: MethodInvocationExpression(Target:\n MemberReferenceExpression(\n Name:"get_Length",\n Target: ReferenceExpression("s")\n ))))\n}}}\n\n\n
This TiddlyWiki is intended initially as a standalone reference manual for the Boo Programming Language. Later, as more examples are collected, it's also intended to become a tutorial and a cookbook.\n\n* BooAsCalculator\n* VariablesAndTypes\n* StringHandling\n* ArraysAndLists\n* BooHashes\n* ReferencesAndObjects\n* ControlStructures\n* TypeCast\n* InputAndOutput\n* BooFunctions\n* BooPrograms\n* BooClasses\n* BooInterfaces\n* BooEnums\n* ValueTypes\n* ExtensionMethods\n* CustomAttributes\n* CustomMacros\n
Arrays are //container objects// which efficiently keep an //indexed// collection of the //same type//. In Boo they are compatible with CLI arrays, and always start at index zero.\n{{{\n# an array literal!\n>>> intarr = (1,20,40,2)\n(1, 20, 40, 2)\n>>> intarr.Length\n4\n>>> len(intarr) # Python style\n4\n# indexing\n>>> intarr[1]\n20\n# can modify arrays\n>>> intarr[1] = 40\n40\n>>> intarr\n(1, 40, 40, 2)\n# can slice arrays\n>>> intarr[1:3]\n(40, 40)\n}}}\nBoo is committed to saving your wrist by eliminating //explicit// typing wherever possible. In C#, an array would be created like so:\n{{{\narr = new int[]{1,20,40,2};\n}}}\nIn Boo, the type is deduced from the type of the elements. The //base type// will be the type that can accomodate all the element types. In the following example, all the elements are numbers, but the overall type must be double.\n{{{\n>>> (1,10,2.3)\n(Double[]) (1, 10, 2.3)\n}}}\nThese are both pretty clear cases - the second is an array of array of integers (and why not?).\n{{{\n>>> ('one','two','three')\n(String[]) ('one', 'two', 'three')\n>>> aa = ((1,2),(3,4))\n(Int32[][]) ((1, 2), (3, 4))\n>>> aa[0][1]\n(Int32) 2\n}}}\nBoo can accommodate arrays containing arbitrary types, by going to the lowest common denominator; the {{{Object}}} type.\n{{{\n>>> (1,'one',(1,2))\n(Object[]) (1, 'one', (1, 2))\n}}}\nThere is an explicit array literal for forcing the type:\n{{{\n>>> (of double:1,2,3,4,5)\n(Double[]) (1, 2, 3, 4, 5)\n}}}\nSlicing arrays works just like with strings; indexing an array with -1 will give you the //last// element, so {{{a[-1]}}} is just the same as {{{a[a.Length-1]}}}.\n\nArrays can be directly created with the {{{array}}} builtin function. Please note that the elements will be properly initialized.\n{{{\n>>> nums = array(double,20)\n(Double[]) (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\n}}}\n\nUnpackingValues\nIteratingOverCollections\nSequenceBuiltins\nBooLists\n\n
There are a number of Boo builtin functions which work on enumerable objects.\n\n! join\n{{{join}}} is very useful and used for the same thing as the Python string method of this name; it will construct a string out of the text representation of a sequence of numbers, using the given separator.\n{{{\n>>> a = (10,20,30)\n>>> join(a,',')\n(String) '10,20,30'\n>>> join(x for x in range(0,10))\n(String) '0 1 2 3 4 5 6 7 8 9'\n}}}\n\n! zip\n{{{zip}}} is used to make a single sequence out of two sequences; each element of the new sequence will be a pair containing matching elements from the sequences. The resulting sequence will be as long as the shortest of the two input sequences. Fortunately it's easier to demonstrate than to explain:\n{{{\n>>> a = (10,20,30)\n>>> b = (1,2,3)\n>>> for i,j in zip(a,b): print i,j\n10 1\n20 2\n30 3\n>>> ls = [pair for pair in zip(a,b)]\n>>> ls\n(List) [(10, 1), (20, 2), (30, 3)]\n}}}\n\n! cat\n{{{cat}}} will con''cat''enate two sequences:\n{{{\n>>> join(cat(a,b))\n(String) '10 20 30 1 2 3'\n}}}\n\n! enumerate\n{{{enumerate}}} returns a similar sequence to {{{zip}}}, but the first value of the pair is the index. \n{{{\n>>> for i,s in enumerate(['one','two','three']): print i,s\n0 one\n1 two\n2 three\n>>> inf = StreamReader('/net/boo/examples/macros/with/WithMacro.boo')\n>>> for i,line in enumerate(inf):\n... print i,line\n... \n0 #region license\n1 // Copyright (c) 2003, 2004, Rodrigo B. de Oliveira (rbo@acm.org)\n2 // All rights reserved.\n3 // \n}}}\n\n! iterator\n{{{iterator}}} is only occaisionally used, because it's usually implicitly invoked. It will see if there's an appropriate iterator for an object. In Boo, input streams can be iterated over by {{{for}}}, so to print all lines in a file:\n{{{\nfor line in inf: print line\n}}}\nYou can easily get input as an array of strings using {{{iterator}}}\n{{{\nlines = array(string,iterator(inf))\n}}}\n\n! reversed\nFinally, {{{reversed}}} will return an iterator for a sequence in reverse order.\n{{{\n>>> ls = [1,2,3,4]\n>>> l2 = [n for n in reversed(ls)]\n>>> print l2\n[4, 3, 2, 1]\n}}}\n\n\n\n
An //interface// is like an AbstractBaseClass, except that it provides no functionality whatsoever. If your class //implements// a particular interface, then it's forced to implement the methods and properties of that interface. Any clients of that class then have a guarantee of what methods it will implement.\n{{{\ninterface IAnimal:\n Name as string:\n get:\n pass\n set:\n pass\n \n def Speak()\n \nclass Cat (IAnimal):\n [property(Name)]\n _name as string\n \n def Speak():\n print "miaow"\n \ndef Speaker(x as IAnimal):\n x.Speak()\n \nc = Cat(Name : "Felix")\nSpeaker(c)\n}}}\nPlease note the crucial difference between class and interface definitions; properties and method declarations within an interface have no body, or just {{{pass}}}. Return types must be explicit (if not specified it means {{{void}}}}) since there's no way to infer this type from any actual {{{return}}} statements.\n\nA class implementing an interface must supply implementations for //all// the properties and methods in the interface. They are not virtual methods and so there is no need to say {{{override}}} - this can be a little confusing.\n\nA class cannot inherit from more than one base class, but it may implement multiple interfaces.\n\nInterfaces are widely used in the CLI. For instance, classes that implement {{{IDisposable}}} can do something when their objects are disposed. Although generally the framework looks after memory for you, it does not manage any other resources like open files.\n\nSee RedirectingOutput\n\n