Qu

Data & I/O

Streaming files & URLs

`StreamFile(path)` and `StreamURL(url)` (§ StreamFile/StreamURL polymorphic streams, see docs/qu-language-tour.md §23) are two different constructors that expose the SAME method names -- `read_line`/`read_all`/`eof`/`close` -- so one

catalog/qu_streamfile_streamurl.qu

function written against "a stream" works completely unmodified against either kind. `StreamFile` is literally `fopen`'s own machinery under a second name (a real `Value::File` handle); `StreamURL` makes a real HTTP GET (the same request `http_get` makes, see qu_http_get.qu) and wraps the whole body eagerly in a read-only in-memory cursor answering to the exact same method names.

This demo proves the polymorphism for real: the exact same `drain` function below is called once against a real local file and once against a real network response, with zero branching on which kind it received. The network half is wrapped in try/catch, same honest pattern as qu_http_get.qu -- on a machine with no outbound network access this prints a clear "network unavailable" message instead of crashing, while the StreamFile half (pure local disk I/O) always runs.

What it exercises

How it works

One function, written against "a stream" -- no branching on the

concrete kind of `s` anywhere in this body.

function drain(s)
    total = ""
    n = 0
    while not eof(s)
        line = read_line(s)
        total = total + line + "|"
        n = n + 1
    end while
    close(s)
    return total
end function

StreamFile side: a real local file with three known lines

notes_path = tmp_file()
w = fopen(notes_path, "w")
write_line(w, "alpha")
write_line(w, "beta")
write_line(w, "gamma")
close(w)

a = drain(StreamFile(notes_path))
print("StreamFile drain result: \"{a}\"")

StreamURL side: a real HTTP GET against the same stable target

qu_http_get.qu uses, drained through the IDENTICAL `drain` function above

try
    b = drain(StreamURL("https://example.com/"))
    print("StreamURL drain length: {length(b)} chars")
    print("both streams answered to read_line/eof/close with zero branching in `drain`")
catch err
    print("StreamURL could not reach the network: {err.message}")
    print("this is the expected, honest result in an environment with no outbound network access")
    print("(the StreamFile half above already proved the shared interface on its own)")
end

Results

printed
StreamFile drain result: "alpha|beta|gamma|"
StreamURL drain length: 559 chars
both streams answered to read_line/eof/close with zero branching in `drain`

The whole program

Runnable as it stands: qu run catalog/qu_streamfile_streamurl.qu

# qu_streamfile_streamurl.qu -- `StreamFile(path)` and `StreamURL(url)`

# (§ StreamFile/StreamURL polymorphic streams, see

# docs/qu-language-tour.md §23) are two different constructors that expose

# the SAME method names -- `read_line`/`read_all`/`eof`/`close` -- so one

# function written against "a stream" works completely unmodified against

# either kind. `StreamFile` is literally `fopen`'s own machinery under a

# second name (a real `Value::File` handle); `StreamURL` makes a real HTTP

# GET (the same request `http_get` makes, see qu_http_get.qu) and wraps the

# whole body eagerly in a read-only in-memory cursor answering to the exact

# same method names.

#

# This demo proves the polymorphism for real: the exact same `drain`

# function below is called once against a real local file and once against

# a real network response, with zero branching on which kind it received.

# The network half is wrapped in try/catch, same honest pattern as

# qu_http_get.qu -- on a machine with no outbound network access this

# prints a clear "network unavailable" message instead of crashing, while

# the StreamFile half (pure local disk I/O) always runs.

#

# Constructs exercised (all real, verified-working builtins):

#   StreamFile(path)                  -- fopen's own machinery under a second name

#   StreamURL(url)                    -- eager real HTTP GET wrapped as a read-only stream

#   read_line(s) / eof(s) / close(s)  -- the shared method surface both kinds answer to

#   try/catch                         -- graceful handling of the real network dependency


backend auto

#%% One function, written against "a stream" -- no branching on the

# concrete kind of `s` anywhere in this body.

function drain(s)
    total = ""
    n = 0
    while not eof(s)
        line = read_line(s)
        total = total + line + "|"
        n = n + 1
    end while
    close(s)
    return total
end function

#%% StreamFile side: a real local file with three known lines

notes_path = tmp_file()
w = fopen(notes_path, "w")
write_line(w, "alpha")
write_line(w, "beta")
write_line(w, "gamma")
close(w)

a = drain(StreamFile(notes_path))
print("StreamFile drain result: \"{a}\"")

#%% StreamURL side: a real HTTP GET against the same stable target

# qu_http_get.qu uses, drained through the IDENTICAL `drain` function above

try
    b = drain(StreamURL("https://example.com/"))
    print("StreamURL drain length: {length(b)} chars")
    print("both streams answered to read_line/eof/close with zero branching in `drain`")
catch err
    print("StreamURL could not reach the network: {err.message}")
    print("this is the expected, honest result in an environment with no outbound network access")
    print("(the StreamFile half above already proved the shared interface on its own)")
end