Lunar Programming Language

by David A. Moon
January 2017 - January 2018



Streams

A stream contains a series of data of some type (often characters). An input stream can return a series of data using the in_stream protocol. An output stream can accept a series of data using the out_stream protocol.

Unlike sequence operations, stream operations side-effect the stream. The data can only be read or written once, unless the stream supports some kind of "rewind" operation.

There are several classes that implement one or both stream protocols and they advertise that fact by inheriting from in_stream or out_stream as a superclass.

in_stream and out_stream are generic classes with a generic formal parameter that specifies the type of the data in the stream.

The input stream protocol could have been defined by:

abstract:
defclass in_stream[member_type type]

require more?(s in_stream) => boolean                  ; false if at end of stream
require[type] next(s in_stream[type]) => type | false  ; next datum, or false at end
require[type] next!(s in_stream[type]) => type | false ; next, also advance past that datum
require close(s in_stream)                             ; release resources, if any

Repeated calls to next without calling next! will return the same result.

The output stream protocol could have been defined by:

abstract:
defclass out_stream[member_type type]

require[type] push!(s out_stream[type], x type)    ; output x to stream
require[type] append!(s out_stream[type],          ; output x... to stream
                      x sequence[type])
require close(s out_stream)                        ; release resources, if any

The in_stream pseudo-constructor takes a sequence and produces a stream that returns the members of the sequence. This is especially useful when the argument is a string. It could have been defined by

def[T] in_stream(seq sequence[T]) sequence_in_stream[T](seq)

defclass sequence_in_stream[T type](seq sequence[T]) in_stream[T]
  sequence  = seq
  position := iterate(seq)

def more?(stream sequence_in_stream)
  more?(stream.sequence, stream.position)

def next(stream sequence_in_stream)
  more?(stream.sequence, stream.position) and next(stream.sequence, stream.position)

def next!(stream sequence_in_stream)
  if more?(stream.sequence, stream.position)
    def result = next(stream.sequence, stream.position)
    stream.position := iterate(stream.sequence, stream.position)
    result

def close(stream sequence_in_stream)
  stream.position := false

The out_stream pseudo-constructor takes a type and produces a stream that accepts output. When closed it returns the data that were output to the stream as an instance of the specified type, typically string or list. If the type is not string it must be a constructor that accepts the members as multiple actual parameters. It could have been defined by

def out_stream(result_type type) sequence_out_stream(result_type)

defclass sequence_out_stream(result_type type) out_stream[member_type(result_type)]
  result_type = result_type
  buffer      = stack[member_type(result_type)]()

def push!(stream sequence_out_stream, item) push!(stream.buffer, item)

def append!(stream sequence_out_stream, items) append!(stream.buffer, items)

def close(stream sequence_out_stream)
  def result = if stream.result_type = string then string(stream.buffer)
               else stream.result_type(stream.buffer...)

  ;; release resources
  stream.buffer._contents := list![member_type(result_type)]()
  result

See File IO for related classes for reading and writing files.

See Token Streams for a related class used by the parser.


Previous page   Table of Contents   Next page



Creative Commons License
Lunar by David A. Moon is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Please inform me if you find this useful, or use any of the ideas embedded in it.
Comments and criticisms to dave underscore moon atsign alum dot mit dot edu.