A Boo programozási nyelv

BooManifesto

Ebben a részben a Boo nyelv tervezőjének, Rodrigo Barreto de Oliveira 2004-ben megjelent, "The boo Programming Language" című cikkéről van szó. Ebben leírja a nyelv kialakulásának történetét, valamint elmondja a legfőbb indokait, amiért megalkotta a Boo-t.

A négy, számára legfontosabb szempont volt:


A következőkben ezekről lesz szó.

A kezdőoldalon megtalálható a link a cikkhez (BooManifest.pdf).

Ennek a résznek a szerkezete teljes mértékben a cikkben elhangzottakhoz igazodik, minden idézet is onnan való.

Egyszerűség, tisztaság - "A clean and wrist-friendly syntax"

1.: „Python-like"

A nyelv szintaktikája már első ránézésre barátságosnak és ismerősnek tűnhet annak, aki ismeri a Python nyelvet. Ami nem csoda, hiszen a nyelv készítőjének az egyik kedvence. Többek között a margószabály-t is onnan vette át.

2.: "Syntactic sugar for common programming patterns"

Fontosnak tartotta, hogy a nyelv teljes mértékben támogassa a legtöbb tervezési mintát. Így azokat könnyne és gyorsan használhatjuk Boo-ban. Ilyen például a lista, vagy a reguláris kifejezések is.

3.: "Automatic Variable Declaration"

Az automatikus változó deklaráció mellett azzal érvelt, hogy nála mindig is működött, szívesen használta.
"It can be good, it can be bad. But it always worked for me."

Ezt leginkább ideiglenes változóknál ajánlott használni, ahol nem kell külön deklarálni őket, a fordító elintézi helyettünk ezt az apróságot.

4.: "Automatic type inference"

Az indoklás így hangzik: "Nothing more tiresome than writing the same type name over and over just to make the compiler happy."

Nézzünk erre példát:
Amit szeretnénk:

def one(): return 1 um = one()

Tisztán látszik, hoyg a függvény integer értéket ad vissza. Az újonnan deklarált változón (um) is jól látszik, hogy egy integer értéket fog eltárolni. Így a fordítótól elvárható, hogy kiegészítse a számunkra:

def one() as int: return 1 uno as int = one()


5.: "Automatic type casting"

További időspórolás és csuklókímélés, ha nem kell mindene esetben explicit módon castolnunk, hanem azt a fordítóra bízzuk.

Az indoklása így hangzik: „If a type casting operation could succeed in runtime I don't want to write it. I'll rely on unit tests to make sure my code works”

6.: "Classes are not needed"

Boo-ban a Hello World! program nagyon egyszerűen néz ki (lásd: Alapdolgok a Boo-ról / Hello World!)

Amiért ezt ilyen egyszerűen leírhatjuk, az annak köszönhető, hogy a nyelv alkotója így vélekedik: "The guys who came up with “public static void main” were probably kidding, the problem is that most people didn't get it was a joke."

Kifejezőképesség - "Expressiveness"

1.: First class functions

Ennek három fontos következménye van:



Példa a visszatérési értékre:

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élda fv. argumentumra:

def x2(item as int): return item*2 print(join(map(x2, range(11))))

Példa változóban tárolt függvényre:

p = print p("Hello, world!")


2.: Generátorok:

A generátorokról már volt szó korábban. Fontos, hogy egynél több értéket állít elő. A legtöbbször Iterációban használva (pl. „for in” ~ foreach) fordul elő.

3.: Egy generátor kifejezés így néz ki:

for in [if|unless ]

Visszatérési értékként:

def GetCompletedTasks(): return t for t in _tasks if t.IsCompleted

Eltárolhatjuk változóban:

oddNumbers = i for i in range(10) if i % 2

fv. argumentumként:

print(join(i*2 for i in range(10) if 0 == i % 2))

4.: Generátor metódus:

A yield kulcsszóval.

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}")

A generátor nincs bekorlátozva, de zip miatt nem fog többet kérni, 5-nél

5.: Duck typing

A kacsa teszt: "Ha úgy néz ki mint egy kacsa, úgy úszik mint egy kacsa, és úgy hápg mint egy kacsa, akkor az valószínűleg egy kacsa."
A duck típusú kifejezéseknél, hogy az micsoda, az futási időben derül ki.

Például külső komponenseknél jól használható. (pl.: COM)

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.go-mono.com/monologue/") Thread.Sleep(50ms) while ie.Busy document = ie.Document print("${document.title} is ${document.fileSize} bytes long.")


Kiterjeszthetőség - "Extensibility"

1.: Szintaktikus attribútomok:

Mikro kód minták automatizálására használható. A példában A getter és a required szintaktikus attribútumként kezeli a fordító. Ezek az attribútum osztályok az IAstAttribute interface-t implementálják.

Amit a programozó írhat:

class Person: [getter(FirstName)] _fname as string [getter(LastName)] _lname as string def constructor([required] fname, [required] lname): _fname = fname _lname = lname

Ahogyan azt a fordító érti:

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

2.: Szintaktikus makrók:

Példa:

using reader=File.OpenText(fname): print(reader.ReadLine())

A using nincs beépítve a nyelvbe, ez egy szintaktikus makró.
Ahogyan ezt a fordító érti:

try: reader = File.OpenText(fname) print(reader.ReadLine()) ensure: if (__disposable__ = (reader as System.IDisposable)) __disposable__.Dispose() __disposable__ = null reader = null

3.: Maga a fordítás menete is kiterjeszthető:

Ezt "Extensible Compilation Pipeline"-nak nevezik.

Ne csak a szintaxis legyen kiterjeszthető, hanem maga a fordítás menete is.
Sok mindenre használható, például:

Ez hoygan lehetséges? A fordítás különböző lépésekből áll:

Nézzünk erre egy példaprogramot. A példában egy új lépést (step) definiálunk, ami ellenőrzi, hogy minden class nagy betűvel kezdődik-e.
A kód egy kísérő (accompanying) pipeline-t is definiál, mint egy kiterjesztés a standard CompileToFile pipeline-hoz.

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())

4.: CLI:

A Common Language Infrastructure, mert: