شما پیشتر در channel-chatter از جریانها استفاده کردهاید و در boatswains-bilge آنها را دور انداختهاید. این تمرین نخستین جریان سفارشی شماست: کلاسی که پروتکل را پیادهسازی میکند تا همان کد with-input-stream / read1 / stream-read1 که روی یک <string-reader> کار میکرد، روی جریان شما هم کار کند.
شما TUPLE: child < parent … را از dragons-descendants میشناسید: سلسلهمراتبی تکوالدی که در آن خانهها به پایین میرسند. Factor راه دومی هم برای گسترش گراف کلاسها دارد: میکسینهای باز. MIXIN: m کلاسی را اعلام میکند که هیچ خانهای ندارد و کلاسهای دیگر میتوانند بعدها با INSTANCE: c m به آن بپیوندند. عضویت چندبهچند است: یک کلاس میتواند نمونهی هر تعداد میکسین که بخواهد باشد.
پروتکل جریانها از دو میکسین استفاده میکند تا مشخص کند یک کلاس کدام نیمه از رابط را پیادهسازی میکند:
INSTANCE: my-stream input-stream ! readable
INSTANCE: my-stream output-stream ! writable
یک جریان میتواند یکی از این دو، یا هر دو باشد. متدهای ژنریک روی input-stream (یا output-stream) آنگاه به هر کلاسی که به آن میکسین پیوسته است فرستاده میشوند؛ به این ترتیب است که read1، stream-contents، with-input-stream و غیره، که بهصورت همگانی در دسترساند، راهشان را به کلاس شما پیدا میکنند.
میکسینها باز هستند: میتوانید پس از اعلام میکسین، عضو تازهای به آن اضافه کنید، حتی در یک واژگان دیگر. تفاوت همینجاست با TUPLE: < parent که در آن رابطه هنگام اعلام کلاس فرزند ثابت میشود.
ژنریکهای پروتکل در io قرار دارند:
stream-read1 ( stream -- elt/f )
stream-read ( n stream -- seq/f )
stream-read-unsafe ( n buf stream -- count )
stream-write1 ( elt stream -- )
stream-write ( seq stream -- )
stream-flush ( stream -- )
stream-element-type ( stream -- type )
stream-read1 بایت بعدی را برمیگرداند (یا در پایان جریان f را)؛ stream-write1 یک بایت مینویسد. stream-read-unsafe همان خواندن دستهای سطحپایینتر است که بیشتر جریانهای ورودی فراهم میکنند؛ stream-read روی آن ساخته شده و تخصیص حافظه را مدیریت میکند. stream-element-type میگوید که جریان با بایت (+byte+) سر و کار دارد یا با نویسه (+character+)؛ وقتی جریان دیگری را دربرمیگیرید، سادهترین پیادهسازی فقط کار را به جریان زیرین واگذار میکند.
destructors استجریانها دورانداختنیاند: یک جریان سفارشی disposable را گسترش میدهد و dispose* را پیادهسازی میکند. این همان چارچوبی است از boatswains-bilge که این بار روی یک کلاس جریان اعمال شده است:
TUPLE: my-stream < disposable underlying ;
: <my-stream> ( underlying -- s )
my-stream new-disposable swap >>underlying ;
M: my-stream dispose* underlying>> dispose ;
وقتی این کار انجام شد، همهی ترکیبکنندههای with-… از channel-chatter بهطور خودکار روی جریان شما کار میکنند.
شما اپراتور بیسیم تلگراف روی یک کشتی باری هستید. سیگنال از خطی پرنویز میرسد؛ صدای ماشینآلات کشتی، پارازیت جوّ، گاهی هم صحبتهای بیگانه، همه درهمآمیخته با همان مورسی که در انتظارش هستید. برای گرفتن پیام، سیم را از دستگاهی به نام «نوار» عبور میدهید که هر چیزی جز نمادهای معتبر مورس (.، - و فاصلهای که حروف را از هم جدا میکند) را حذف میکند.
کار شما این است که نوار را به عنوان یک جریان ورودی سفارشی Factor بسازید.
یک تاپل tape تعریف کنید که از disposable ارثبری میکند و یک اسلات به نام wire برای جریان ورودی زیربنایی در خود نگه میدارد.
TUPLE: tape < disposable wire ;
سپس سازندهی <tape> ( wire -- tape ) را بنویسید. از new-disposable (نه new) استفاده کنید تا چارچوب تخریبگر نوار را ثبت کند، و جریان زیربنایی را در اسلات wire ذخیره کنید.
tape را به عنوان یک input-stream اعلام کنید:
INSTANCE: tape input-stream
این کار باعث میشود ترکیبگرهای پیشفرض پروتکل به کلاس شما فرستاده شوند.
M: tape stream-read1 ( tape -- elt/f ) را پیادهسازی کنید. بایتهایی را از سیم زیربنایی بخوانید تا به یکی از CHAR: .، CHAR: - یا CHAR: \s (فاصله) برسید. همان بایت را برگردانید. اگر سیم f را برگرداند (پایان جریان)، شما هم f را برگردانید؛ کار نوار تمام است.
"x.y -ab cz" <string-reader> <tape>
[ stream-read1 ] [ stream-read1 ] [ stream-read1 ] tri
! => CHAR: . CHAR: - CHAR: \s
M: tape stream-element-type ( tape -- type ) را با واگذاری به سیم پیادهسازی کنید؛ نوار نوع عناصری که خوانده میشوند را تغییر نمیدهد.
M: tape dispose* ( tape -- ) را پیادهسازی کنید. چارچوب متد شما را دقیقاً یک بار به ازای هر dispose فراخوانی میکند؛ فقط سیم زیربنایی را آزادسازی کنید.
با آماده بودن این پنج قطعه، نوار مانند یک جریان ورودی معمولی کار میکند؛ with-input-stream، stream-read و دیگر واژههای پروتکل همگی بهطور خودکار به متدهای شما فرستاده میشوند.