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 clean and wrist-friendly syntax"
- "Expressiveness"
- "Extensibility"
- "The Common Language Infrastructure"
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:
- Egy függvény visszatérési értéke lehet függvény
- Egy függvény argumentuma lehet függvény
- Egy függvényt eltárolhatunk egy változóban
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:
- Dokumentáció és reportok készítése
- Kódolási konvenciók ellenőrzése
- Program-transzformációk a könnyebb debuggoláshoz
- A fordító komponensei is kicserélhetőek, pl. a source code parser
Ez hoygan lehetséges? A fordítás különböző lépésekből áll:
- Steps (lazán kapcsolódó objektumok halmaza)
- compilation context (egy jól definiált adat struktúra)
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:
- Más nyelvekben írt modulokkal jól együtt tudjon működni.
- Egy gazdag programozási környezet, jól átgondolt osztály könyvtárral.
- Több platformon is fusson a program.