Перейти на главную страничку сайта (список статей, файлы для скачивания)
Язык программирования Boo — объектно-ориентированный язык программирования со статической типизацией для Common Language Infrastructure (CLI), т.е. для .NET и Mono, с открытой лицензией, питонообразным синтаксисом и упором на расширяемость компилятора и самого языка. В некотором смысле, Boo — это смесь Python и C#. Полный список отличий от Python можно найти здесь. У Boo есть интерактивный интерпретатор. По мнению некоторых, язык Воо имеет более компактный код и более высокую скорость исполнения, чем Python или IronPython. На Boo можно писать настольные приложения с графическим интерфейсом на основе Windows.Forms / GTK#, а также приложения ASP.NET. Взять язык можно здесь (дистрибутив "binary" на момент написания данной статьи имеет размер порядка 900 Кб).
Автор языка — Родриго Баррето де Оливейра (Rodrigo Barreto de Oliveira). Причины создания Boo его автор объясняет тем, что в Python ему не хватало статической типизации, проверки ошибок времени компиляции и продуманной архитектуры .NET. С другой стороны, синтаксис C# автора тоже полностью не устраивал, как слишком многословный в некоторых случаях. Кроме того, автор хотел иметь язык, который можно расширять собственными конструкциями, а также интерактивный интерпретатор, в котором можно быстро проверить фрагменты кода.
Установка: если вы скачали дистрибутив "binary", просто разархивируйте Boo, и вы получите компилятор booc.exe, интерпретатор booi.exe и интерактивный интерпретатор booish.exe. Естественно, необходимо иметь установленный .NET или MONO. Можете добавить каталог Boo к переменной PATH.
На официальном сайте языка вы найдёте примеры кода, руководства и ссылки на проекты на языке Boo.
Создайте текстовый файл test.boo в кодировке utf-8 следующего содержания:
print("Привет, мир!")
Запустите скрипт на исполнение интерпретатором, командой наподобие следующей:
booi test.boo
Пример чтения с консоли:
import System name = Console.ReadLine() print("Hello, ${name}")
Простейший пример организации GUI (на Windows.Forms):
import System.Windows.Forms f = Form(Text: 'Привет, Boo!') button = Button() button.Dock = DockStyle.Fill button.Text = System.DateTime.Now.ToString() button.add_Click({button.Text = System.DateTime.Now.ToString()}) f.Controls.Add(button) Application.Run(f)
Пример выше выведет окно с единственной кнопкой, на которой отображается текущее время. Нажатие на кнопку будет обновлять время.
Вы можете откомпилировать последний пример командой наподобие следующей:
booc -target:winexe test.boo
Для успешного запуска полученного таким способом test.exe из любого каталога будет достаточно зарегистрировать сборку Boo.Lang.dll из поставки Boo в глобальном кеше сборок .NET (Global Assembly Cashe) с помощью утилиты gacutil.exe, примерно такой командой:
gacutil.exe /i Boo.Lang.dll
Результат — работоспособная исполняемая программа test.exe размером порядка 4 Кб.
Простейший пример использования COM-объекта:
def CreateInstance(progid): type = System.Type.GetTypeFromProgID(progid) return type() # создаём "утку": wsh as duck = CreateInstance("WScript.Shell") # пробуем крякнуть по-утиному (вызвать метод): wsh.popup("Привет, Windows Script Host & Boo!")
Простейший пример использования Win32 API:
import System.Runtime.InteropServices [DllImport("User32.dll", EntryPoint:"MessageBox")] def msgbox(hwnd as int, msg as string, caption as string, msgtype as int): pass def msgbox(msg as string): msgbox(0, msg, "Сообщение", 0) msgbox(0, "вызов MessageDialog", "демонстрация DllImport", 0) msgbox("ещё раз")
Пример выше выведет поочерёдно два окна сообщения.
Пример вызова Win32 API с организацией обратного вызова (callback):
import System import System.Runtime.InteropServices class User32: callable EnumWindowProc(hwnd as IntPtr, lparam as IntPtr) as bool [DllImport("user32.dll")] static def EnumWindows(proc as EnumWindowProc, param as IntPtr) as bool: pass [DllImport("user32.dll", CharSet : CharSet.Auto)] static def GetWindowText(hWnd as IntPtr, [Out] title as string, maxCount as int) as int: pass def proc(hwnd as IntPtr, lparam as IntPtr): if hwnd != IntPtr.Zero: s = string(char(' '), 260) User32.GetWindowText(hwnd, s, 260) s = s.Trim() if len(s) and cast(int, s[0]) != 0: print s return true User32.EnumWindows(proc, IntPtr.Zero)
Пример выше выведет на консоль заголовки окон верхнего уровня, открытых в системе в настоящий момент.
Питонообразность, но со статической типизацией; списки, хеши, итерируемые строки, инициализация объектов, форматирование строк, регулярные выражения. Нет кортежей, но есть массивы в стиле C#, очень на них похожие.
Автоматическое объявление переменных; присваивание вводит новую локальную переменную.
Автоматическая типизация, сокращающая код; например, следующая конструкция явно возвращает целое, и компилятор это понимает:
def one(): return 1 um = one()
С другой стороны, при желании программист должен быть в состоянии точно указать, что он подразумевает:
def one() as int: return 1 uno as int = one()
В этом случае компилятор должен только проверить, имеет ли смысл заявленное. Другими словами, должна ожидаться ошибка компилятора для кода, подобного следующему:
def one(): return "1" ichi as int = one()
Автоматического приведения типов нет; по мнению автора языка, лучше протестировать код, чем полагаться на это.
Классы не являются необходимыми в каждой программе, писать сакраментальные конструкции типа "public static void main" (как в C#) не нужно, простейшая программа будет такой:
print("Hello, world!")
Функции могут использоваться как возвращаемые значения:
def ignore(item): pass def selectAction(item as int): return print if item % 2 return ignore for i in range(10): selectAction(i)(i)
Функции могут присваиваться переменным:
p = print p("Hello, world!")
Функции могут выступать в роли объектов:
print.Invoke("Hello, world!")
Асинхронные вызовы делегатов:
import System def callback(result as IAsyncResult): print("callback") def run(): print("executing") print("started") result = run.BeginInvoke(callback, null) System.Threading.Thread.Sleep(50ms) run.EndInvoke(result) print("done")
Примечание: делегаты можно представлять себе как переменные, в которых можно хранить некоторые функции. Методы делегата BeginInvoke и EndInvoke позволяют вызывать делегат асинхронно. Обратный вызов (callback) позволяет произвести некоторое асинхронное действие для каждого вызова.
Определение вызываемых типов:
callable Malkovich() as Malkovich def malkovich() as Malkovich: print("Malkovich!") return malkovich malkovich()()()
Генераторы (языковые конструкции, способные к производству нескольких значений, когда используются в итеративном контексте):
oddNumbers = i for i in range(10) if i % 2
Такие конструкции могут быть использованы и в качестве аргументов вызываемых функций; во всех случаях оценка каждого внутреннего выражения случается только по требованию, поскольку генератор употребляется в цикле for.
Генераторы с использованием ключевого слова yield:
def fibonacci(): a, b = 0, 1 while true: yield b a, b = b, a+b for index as int, element in zip(range(5), fibonacci()): print("${index+1}: ${element}")
Пример выше выведет первые 5 чисел Фибоначчи.
Генераторные методы:
import System.Xml def selectElements(element as XmlElement, tagName as string): for node as XmlNode in element.ChildNodes: if node isa XmlElement and tagName == node.Name: yield node
Можно не заботиться о типизации (duck typing), если в этом нет необходимости:
import System.Threading def CreateInstance(progid): type = System.Type.GetTypeFromProgID(progid) return type() ie as duck = CreateInstance("InternetExplorer.Application") ie.Visible = true ie.Navigate2("http://www.script-coding.com/") Thread.Sleep(50ms) while ie.Busy document = ie.Document print("${document.title} is ${document.fileSize} bytes long.")
Работа с синтаксическими атрибутами сокращает код:
class Person: [getter(FirstName)] _fname as string [getter(LastName)] _lname as string def constructor([required] fname, [required] lname): _fname = fname _lname = lname
Вышеприведённый код приводит к тому же эффекту, что и следующий, более многословный:
import System class Person: _fname as string _lname as string def constructor(fname, lname): raise ArgumentNullException("fname") if fname is null raise ArgumentNullException("lname") if lname is null _fname = fname _lname = lname FirstName as string: get: return _fname LastName as string: get: return _lname
Синтаксические макросы наращивают язык новыми конструкциями:
import System.IO using reader=File.OpenText(fname): print(reader.ReadLine())
В данном случае "using" — синтаксическая макрокоманда, которая заставляет вышеприведённый код интерпретироваться компилятором как следующий:
try: reader = File.OpenText(fname) print(reader.ReadLine()) ensure: if (__disposable__ = (reader as System.IDisposable)) __disposable__.Dispose() __disposable__ = null reader = null
Процесс самой компиляции расширяем. Например, следующий код определяет новый шаг компиляции, который проверяет, что у каждого класса, определённого в программе, есть свое название, начинающееся с заглавной буквы:
namespace StyleChecker import Boo.Lang.Compiler import Boo.Lang.Compiler.Ast import Boo.Lang.Compiler.Steps import Boo.Lang.Compiler.Pipelines class StyleCheckerStep(AbstractVisitorCompilerStep): override def Run(): Visit(CompileUnit) override def LeaveClassDefinition(node as ClassDefinition): if not char.IsUpper(node.Name[0]): msg = "Class name '${node.Name}' should start with uppercase letter!" Errors.Add(CompilerError(node, msg)) class StyleCheckerPipeline(CompileToFile): def constructor(): self.Insert(1, StyleCheckerStep())
Людоговский Александр, 23.01.2009г.
Перейти на главную страничку сайта (список статей, файлы для скачивания)
© 2007 http://www.script-coding.com При любом использовании материалов сайта обязательна ссылка на него как на источник информации, а также сохранение целостности и авторства материалов.