The current Yuma framework has three interfaces built in. The first is Readable:
Function Read( count As Integer ) As String
Function EOF() As Boolean
Function ReadError() As Boolean
End Interface
As you can see, Readable defines three methods: Read, EOF, and ReadError. Any class that implements the Readable interface will have (at least) these three methods. That means that you can make a function that works with any Readable.
For example, let's say you need a function that reads a set of fixed-width fields from a file and returns them as a string array, like this:
// Read one line of data in our MoldyData format.
// Each line consists of 5 fields, each containing 20 bytes.
Dim out() As String
for i As Integer = 0 to 4
if source.EOF then exit for
out.Append source.Read(20)
next
call source.Read(1) // (read and discard the line break)
return out
End Function
Now, here's the cool thing: you can pass any Readable object to your ReadFields method. That includes the built-in classes TextInputStream and BinaryStream, as well as any classes you might define yourself.
This can be especially handy for unit testing. It's inconvenient and slow to have an actual file with which to test something like the function above. But test it you certainly should anyway! So, you can make your own test class that defines Readable, and implements the three Readable methods in order to feed the caller whatever data you want to test with. Then pass an object of that class to your ReadFields method, and sleep well at night knowing that your code works as intended.
The second interface defined in the Yuma framework is Writeable:
Sub Write( data As String )
Sub Flush()
Function WriteError() As Boolean
End Interface
Nothing mysterious here; it's pretty much parallel to Readable. The Writeable interface is implemented by TextOutputStream and BinaryStream. Again, you can define your own Writeable class to do whatever you want with the data being written, and pass any of these to any method that works on a Writeable.
(Notice that BinaryStream implements both Readable and Writeable. This illustrates an advantage of interfaces over a regular superclass: a class can have only one superclass, but can implement any number of interfaces.)
Finally, there's one more interface in the current Yuma framework:
Sub Close()
End Interface
This is the simplest interface of all, and it's not actually used by anything publicly exposed (it's used internally by the Session module). But you're welcome to use it yourself on any class you define with a Close method. Here's an example of how this may be useful: you could define a list of closeable objects:
And then as your Yuma program runs, whenever it creates something that will need to be closed later, it can throw it onto this list. Finally, at the end of the program, it could close everything on the list.
// Create a new Whatzit, and remember to close it later
Dim foo As New Whatzit
thingsToClose.Append foo
...
// Our work here is done, but remember to close things before we quit
for each item As Closeable in thingsToClose
item.Close
next item
So now you know about class interfaces in Yuma, and why they're so handy. We love them, and will probably be adding more (and implementing them wherever they make sense) in the future. Stay tuned, and if you have any suggestions, please let us know!
I am still struggling to grasp OO concepts in RB, and examples really help. So, with the help of your example, I understand how to use Closeable, but your Readable and Writeable examples introduce several concepts that are new to me, making it hard to figure out what is going on. In the line;
if out.EOF then exit for
Is the EOF function coming from the Readable interface? If so, how did the locally defined "out" string get associated with Readable Source? It would make more sense if it were;
if Source.EOF then exit for
but otherwise I am puzzled.
Oops — good catch, David! That was a typo; it should indeed be "if source.EOF". I'm sorry for the confusion. (I've corrected the post to avoid confusing any future readers.)
call out.Read(1) // (read and discard the line break)
This line of code with its bald assumption that a linebreak is one character long ;) reminds me that last time I tried it was not possible to use the lone keyword "endOfLine"
I appreciate that web development makes that a very dubious thing to define, as the server may be on a different OS from the browser but it is a sizeable code-portability issue.
Are there any plans to define an arbitrary meaning for EndOfLine? If not, have you any advice about the issue?
You raise a good point: my simple example not only assumes that all lines are 5 20-byte fields long, but that they're separated with a 1-byte carriage return. If you're dealing with the sort of ancient file format that's likely to have fixed-width fields, you can be fairly confident of knowing what your line endings are too. The example is a bit contrived, but has the benefit of being short.
As to EndOfLine: in b3 you actually can use EndOfLine by itself; what you can't do is add it to a string. That's already fixed for b4 (which we expect to have out soon, perhaps Monday).
Oh, and about the default meaning of EndOfLine: in Yuma, it is equivalent to EndOfLine.HTTP, which is the line break used by the HTTP protocol. This was chosen because perhaps the most common use of it will be with the "Print" command, and that's the line ending you would want to print to get a proper line break in the HTML source seen by the client. If you were writing to a file, you'd probably use something else (perhaps EndOfLine.Unix, or whatever's appropriate for the file format you're writing).
As another teaser, the next beta will also include EndOfLine.HTML, which equals "<br />". This is what you'd use if you wanted to print an HTML line break, i.e. to make a break seen when viewing the page (rather than the source) in the client.

