A local-package project
examples/shop/
হলো একটা পুরো multi-package project। একটা single ফাইল পেরিয়ে গেলে এটাই পড়ার মতো
উদাহরণ। এটা দেখায় একটা beans.pot manifest, তিনটা package, pub visibility, আর
package-এর সীমানা পেরিয়ে একটা interface আর একটা generic ব্যবহার করা।
এটা তার main ফাইল থেকে চালান:
beansc run examples/shop/main.bগড়নটা
“গড়নটা” সেকশনshop/ beans.pot module shop main.b package main helpers.b package main (same package as main.b) money/ money.b package money util/ util.b package utilনিয়মটা হলো এক folder, এক package। main.b আর helpers.b দুইটাই package main,
কারণ ওরা একই folder-এ বসে আছে, তাই import ছাড়াই একে অন্যের নাম দেখতে পায়। money/
আর util/ হলো sub-folder, তাই ওরা আলাদা package — import হয় shop.money আর
shop.util হিসেবে।
manifest
“manifest” সেকশনshop/beans.pot
মাত্র এক লাইন:
module shopএকটা local project-এর এটুকুই লাগে: একটা নাম। module-টা হলো shop, তাই ওর
sub-package-গুলো import path পায় shop.money আর shop.util।
money package
“money package” সেকশনshop/money/money.b
package money ঘোষণা করে আর exact decimal money-র হিসাব খুলে দেয়:
package money
pub class Money { pub amount: decimal pub currency: string = "USD"
pub fn init(amount: decimal) { self.amount = amount }
pub fn add(other: Money) -> Money { let result: Money = new Money(self.amount + other.amount) result.currency = self.currency return result }
pub fn show() -> string { return "{self.currency} {self.amount}" }}
pub enum Payment { cash card(number: string)}
pub fn total(xs: List<Money>) -> Money { var sum: decimal = 0.00 for m: Money in xs { sum = sum + m.amount } return new Money(sum)}অন্য package-এর জন্য যা যা রাখা, সব pub দিয়ে চিহ্নিত: class-টা, তার field, তার
method, enum, আর total function। pub না থাকলে এগুলো money-র ভেতরেই private
থাকত, বাইরে থেকে চোখেই পড়ত না। খেয়াল করুন — Money decimal ব্যবহার করে, তাই হিসাবটা exact।
util package
“util package” সেকশনshop/util/util.b
package util ঘোষণা করে আর কিছু shared helper রাখে:
package utilimport std.io
pub interface Device { fn label() -> string
// default method: runs for any Device, even ones from other packages fn describe() -> string { return "device: {self.label()}" }}
pub class Logger { pub prefix: string = "[shop]"
pub fn log(msg: string) { io.println("{self.prefix} {msg}") }}
pub fn largest<T implements Order>(xs: List<T>) -> Option<T> { return xs.max()}
pub fn tau() -> f64 { return 6.2831853}
pub enum Level { low high}
// private: visible inside util only; importing packages can't call itfn hidden() -> int { return 42}এখানে দুইটা জিনিস দেখার আছে:
Deviceহলো একটাpub interface, সাথে একটা default methoddescribe()।Deviceimplement করা যেকোনো type এটা পায়, এমনকি অন্য package-এ বানানো type-ও।largest<T implements Order>হলো একটা bound সহpubgeneric function: এটা এমন যেকোনোTনেয় যেটা built-inOrderinterface implement করে, তাই এটা.max()call করতে পারে।hidden()-এ কোনোpubনেই, তাই এটাutil-এর ভেতরেই private। import করা package এটা call করতে পারবে না।
main package
“main package” সেকশনshop/main.b
সব একসাথে বেঁধে দেয়:
package main
import std.ioimport shop.moneyimport shop.util as u
// implementing an interface from another packageclass Till implements u.Device { id: int = 7 fn label() -> string { return "till-{self.id}" }}
fn imported_label<T implements u.Device>(value: T) -> string { return value.label()}import shop.moneymoney package-টা নিয়ে আসে; এটাmoney.Moneyহিসেবে ব্যবহার করা হয়।import shop.util as uএটাকে একটা local aliasuদেয়, যেটা শুধু এই ফাইলেই বাঁচে, তাই লেখা হয়u.Device,u.Logger,u.largest।Till implements u.Device: এখানকার একটা class অন্য package-এর একটা interface implement করে। এটা শুধুlabel()define করে;describe()-টা সে interface-এর default method থেকেই পেয়ে যায়।imported_label<T implements u.Device>হলো একটা generic function, যার bound আরেক package-এর একটা interface। bound-টা alias দিয়ে লেখা হয়েছে,u.Device।
body-টা এই সবই ব্যবহার করে:
let till: Till = new Till()io.println(till.describe()) // the inherited default methodio.println(imported_label(till)) // generic bound satisfied by Tilllet d: u.Device = till // upcast to the interfaceio.println("as a device: {d.label()}")
let xs: List<int> = [3, 9, 4]match u.largest(xs) { some(n) => io.println("largest {n}"), none => io.println("empty"),}দ্বিতীয় main ফাইল
“দ্বিতীয় main ফাইল” সেকশনshop/helpers.b
-ও package main:
// same package as main.b, so no import is needed between files of one packagepackage main
import std.ioimport shop.money
fn banner(title: string) { io.println("== {title} ==")}
class Cart { items: List<money.Money> = []
fn add(m: money.Money) { self.items.push(m) }
fn total() -> money.Money { return money.total(self.items) }}main.b কিছু import না করেই banner(...) call করে আর Cart ব্যবহার করে, কারণ
ওরা একই package-এ। কিন্তু helpers.b তবুও তার নিজের import shop.money লেখে,
কারণ import হয় per file: প্রতিটা ফাইল নিজে যেই package ব্যবহার করে সেটার নাম বলে দেয়।
একটা project বানানো আর চালানো-তে project-এর গড়নের নিয়ম আছে। একে POT কেন বলে-তে module path, import path আর package name বোঝানো আছে, আর Local package আর import-এ import path কীভাবে resolve হয় সেটা আছে। Generic আর Interface আর inheritance-এ এখানে ব্যবহার হওয়া feature-গুলো বর্ণনা করা আছে।