refchan(n)

refchan(n) πŸ’– β€” the Tcl Built-In Commands glow-up

ok bestie, we're talking about refchan β€” the command handler API of reflected channels. yes it's a Tcl built-in, yes it's giving main character energy, and yes we're gonna get through all of it together 🫢


✨ NAME ✨

refchan β€” command handler API of reflected channels πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

chan create mode cmdPrefix

cmdPrefix blocking channel mode
cmdPrefix cget channel option
cmdPrefix cgetall channel
cmdPrefix configure channel option value
cmdPrefix finalize channel
cmdPrefix initialize channel mode
cmdPrefix read channel count
cmdPrefix seek channel offset base
cmdPrefix watch channel eventspec
cmdPrefix write channel data

🌸 DESCRIPTION 🌸

so here's the tea β˜• β€” the Tcl-level handler for a reflected channel has to be a command with subcommands. we call that an ensemble, like the kind of thing you get from namespace ensemble create, BUT β€” and this is important, bestie β€” the implementation of handlers for reflected channels is not tied to namespace ensembles in any way, shape or form. see the EXAMPLE below for how to build an oo::class that supports the API πŸ‘‘

also note: cmdPrefix is literally whatever was specified in the call to chan create, and it may consist of multiple arguments β€” those get expanded to multiple words in place of the prefix. no cap.

out of all the possible subcommands, your handler must support initialize, finalize, and watch. support for the other subcommands is optional. lowkey generous of Tcl ngl.


πŸ’œ MANDATORY SUBCOMMANDS πŸ’œ

  • cmdPrefix initialize channel mode β€” this invocation is the first call your cmdPrefix will ever receive for that shiny new channel ✨ it's on you (well, on this subcommand) to set up any internal data structures you need to keep track of the channel and its state.

the return value has to be a list containing the names of all subcommands supported by the cmdPrefix. this also tells the Tcl core which version of the API for reflected channels this command handler is using. iykyk.

any error thrown by the method will abort the creation of the channel and no channel will be created 🚫 the thrown error will appear as an error thrown by chan create. any exception other than an error (e.g., break, etc.) is treated as β€” and converted to β€” an error.

note: if the creation of the channel was aborted due to failures here, then the finalize subcommand will not be called. not even a goodbye. brutal 😭

the mode argument tells the handler whether the channel was opened for reading, writing, or both. it's a list containing any of the strings read or write. the list may be empty, but will usually contain at least one element.

the subcommand must throw an error if the chosen mode is not supported by the cmdPrefix. vibe check failed = error, periodt.

  • cmdPrefix finalize channel β€” this invocation is the last call your cmdPrefix will receive for the specified channel πŸ₯Ί it gets generated just before the destruction of the data structures of the channel held by the Tcl core. the command handler must not access the channel anymore in no way. upon this subcommand being called, any internal resources allocated to this channel must be cleaned up. it's giving spring cleaning, bestie 🧹

the return value of this subcommand is ignored.

if the subcommand throws an error, the command which caused its invocation (usually chan close) will appear to have thrown this error. any exception beyond error (e.g., break, etc.) is treated as β€” and converted to β€” an error.

this subcommand is not invoked if the creation of the channel was aborted during initialize (see above). ghosted fr πŸ™ˆ

  • cmdPrefix watch channel eventspec β€” this subcommand notifies the cmdPrefix that the specified channel is interested in the events listed in the eventspec. that argument is a list containing any of read and write. the list may be empty, which signals that the channel does not wish to be notified of any events. in that situation, the handler should disable event generation completely. silence = golden ✨
⚠️ warning: any return value of the subcommand is ignored. this includes all errors thrown by the subcommand, break, continue, and custom return codes. yes, even your most dramatic error. ignored. πŸ’€

this subcommand interacts with chan postevent. trying to post an event which was not listed in the last call to watch will cause chan postevent to throw an error. so like, keep your receipts 🧾


🌈 OPTIONAL SUBCOMMANDS 🌈

  • cmdPrefix read channel count β€” this optional subcommand is called when the user requests data from the channel channel. count specifies how many bytes have been requested. if the subcommand is not supported, then it is not possible to read from the channel handled by the command. no read for you πŸš«πŸ“–

the return value of this subcommand is taken as the requested data bytes. if the returned data contains more bytes than requested, an error will be signaled and later thrown by the command which performed the read (usually gets or read). however, returning fewer bytes than requested is acceptable. underdelivering is fine, overdelivering is a crime apparently 😭

note that returning nothing (0 bytes) is a signal to the higher layers that EOF has been reached on the channel. to signal that the channel is out of data right now, but has not yet reached EOF, it is necessary to throw the error "EAGAIN", i.e. to either
return -code error EAGAIN

or

error EAGAIN

for extensibility, any error whose value is a negative integer number will cause the higher layers to set the C-level variable "errno" to the absolute value of this number, signaling a system error. however, note that the exact mapping between these error numbers and their meanings is operating system dependent. so like, it's not universal, bestie.

for example, while on Linux both

return -code error -11

and

error -11

are equivalent to the examples above, using the more readable string "EAGAIN", this is not true for BSD, where the equivalent number is -35. two different numbers, same vibe, different systems πŸ’…

the symbolic string however is the same across systems, and internally translated to the correct number. no other error value has such a mapping to a symbolic string. she's special like that 🌟

if the subcommand throws any other error, the command which caused its invocation (usually gets, or read) will appear to have thrown this error. any exception beyond error (e.g., break, etc.) is treated as and converted to an error.

  • cmdPrefix write channel data β€” this optional subcommand is called when the user writes data to the channel channel. the data argument contains bytes, not characters. any type of transformation (EOL, encoding) configured for the channel has already been applied at this point. if this subcommand is not supported, then it is not possible to write to the channel handled by the command. can't write, won't write πŸ™…β™€οΈ

the return value of the subcommand is taken as the number of bytes written by the channel. anything non-numeric will cause an error to be signaled and later thrown by the command which performed the write. a negative value implies that the write failed. returning a value greater than the number of bytes given to the handler, or zero, is forbidden and will cause the Tcl core to throw an error. zero bytes is not a flex, it's a violation πŸ”₯

to signal that the channel is not able to accept data for writing right now, it is necessary to throw the error "EAGAIN", i.e. to either

return -code error EAGAIN

or

error EAGAIN

for extensibility any error whose value is a negative integer number will cause the higher layers to set the C-level variable "errno" to the absolute value of this number, signaling a system error. however, note that the exact mapping between these error numbers and their meanings is operating system dependent.

for example, while on Linux both

return -code error -11

and

error -11

are equivalent to the examples above, using the more readable string "EAGAIN", this is not true for BSD, where the equivalent number is -35.

the symbolic string however is the same across systems, and internally translated to the correct number. no other error value has such a mapping to a symbolic string. iconic behavior honestly πŸ‘‘

if the subcommand throws any other error the command which caused its invocation (usually puts) will appear to have thrown this error. any exception beyond error (e.g., break, etc.) is treated as and converted to an error.

  • cmdPrefix seek channel offset base β€” this optional subcommand is responsible for the handling of chan seek and chan tell requests on the channel channel. if it is not supported, then seeking will not be possible for the channel. sit still then ig πŸͺ‘

the base argument is the same as the equivalent argument of the builtin chan seek, namely:

  • start β€” seeking is relative to the beginning of the channel.
  • current β€” seeking is relative to the current seek position.
  • end β€” seeking is relative to the end of the channel.

the offset is an integer number specifying the amount of bytes to seek forward or backward. a positive number should seek forward, and a negative number should seek backward. a channel may provide only limited seeking. for example, sockets can seek forward, but not backward. one-way street energy πŸ›£οΈ

the return value of the subcommand is taken as the (new) location of the channel, counted from the start. this has to be an integer number greater than or equal to zero. if the subcommand throws an error the command which caused its invocation (usually chan seek, or chan tell) will appear to have thrown this error. any exception beyond error (e.g., break, etc.) is treated as and converted to an error.

the offset/base combination of 0/current signals a chan tell request, i.e., seek nothing relative to the current location, making the new location identical to the current one, which is then returned. basically "where am i" with extra steps πŸ’«

  • cmdPrefix configure channel option value β€” this optional subcommand is for setting the type-specific options of channel channel. the option argument indicates the option to be written, and the value argument indicates the value to set the option to.

this subcommand will never try to update more than one option at a time; that is behavior implemented in the Tcl channel core. one at a time, bestie, we're not chaotic πŸŽ€

the return value of the subcommand is ignored.

If the subcommand throws an error, the command that did the (re)configuration or query (usually fconfigure or chan configure) is gonna look like it threw that error. And heads up bestie: any exception beyond error (like break, etc.) gets treated as an error and converted into one. No exceptions. Well. Except exceptions. You know what I mean. πŸ’€


πŸŽ€ cmdPrefix cget channel option

This one's optional, and it's what you use when you're reading a single type-specific option of channel channel. ✨

Little rule: if you support this subcommand, you must support cgetall too. They're a package deal, iykyk. 🫢

It should return the value of the option you asked for.

And if it throws an error, the command that did the (re)configuration or query (usually fconfigure or chan configure) will appear to have thrown it. Any exception beyond error (e.g., break, etc.) is treated as an error and converted to one. Standard. πŸ’…


πŸ’– cmdPrefix cgetall channel

Also optional! This is the one for reading all the type-specific options of channel channel in one go. ✨

And if you support this one, then cget has to be supported as well. Symmetry, babes. πŸ¦‹

It should return a list of all the options and their values. And bestie, listen: that list must have an even number of elements. Even. Number. Of. Elements. Count them. πŸ”₯

If it throws an error, the command that did the (re)configuration or query (usually fconfigure or chan configure) will appear to have thrown it. Any exception beyond error (e.g., break, etc.) is treated as an error and converted to one.


🌸 cmdPrefix blocking channel mode

Optional again (we love an optional subcommand πŸ’œ). This one handles changes to the blocking mode of channel channel. The mode is a boolean flag: a true value means the channel has to be set to blocking, and a false value means it should be non-blocking.

The return value of the subcommand is ignored. Yeah. It's giving "I don't care what you say back, just do it". πŸ™ˆ

If it throws an error, the command that caused its invocation (usually fconfigure or chan configure) will appear to have thrown it. Any exception beyond error (e.g., break, etc.) is treated as an error and converted to one.


πŸ¦‹ cmdPrefix truncate channel length

Last of the optionals! This handles changing the length of the underlying data stream for channel channel. Its length gets set to length. Chop chop. βœ‚οΈ

If it throws an error, the command that caused its invocation (usually chan truncate) will appear to have thrown it. Any exception beyond error (e.g., break, etc.) is treated as an error and converted to one.


✨ NOTES ✨

Okay so not everything from the C side made it to the Tcl level, and you deserve to know which ones, no gatekeeping here 🫢

  • The function Tcl_DriverGetHandleProc is not supported. Which means: reflected channels do not have OS specific handles. If you were looking for a handle, it's not there. It's giving ghosted. πŸ’€
  • The function Tcl_DriverHandlerProc is not supported. That driver function is only relevant for stacked channels, i.e., transformations. And reflected channels are always base channels, never transformations. Base. Not stacked. Periodt. πŸ‘‘
  • The function Tcl_DriverFlushProc is not supported. Why? Because the current generic I/O layer of Tcl doesn't use this function anywhere at all, so supporting it at the Tcl level makes no sense either. This may be altered in the future β€” through extending the API defined here and changing its version number β€” should the function ever actually get used at some point. So like, maybe. Someday. Not today. 🌈

πŸŽ€ EXAMPLE πŸŽ€

This demonstrates how to make a channel that reads from a string. Obsessed with her, honestly. ✨

oo::class create stringchan {
    variable data pos
    constructor {string {encoding {}}} {
        if {$encoding eq ""} {set encoding [encoding system]}
        set data [encoding convertto $encoding $string]
        set pos 0
    }

    method initialize {ch mode} {
        return "initialize finalize watch read seek"
    }
    method finalize {ch} {
        my destroy
    }
    method watch {ch events} {
        # Must be present but we ignore it because we do not
        # post any events
    }

    # Must be present on a readable channel
    method read {ch count} {
        set d [string range $data $pos [expr {$pos+$count-1}]]
        incr pos [string length $d]
        return $d
    }

    # This method is optional, but useful for the example below
    method seek {ch offset base} {
        switch $base {
            start {
                set pos $offset
            }
            current {
                incr pos $offset
            }
            end {
                set pos [string length $data]
                incr pos $offset
            }
        }
        if {$pos < 0} {
            set pos 0
        } elseif {$pos > [string length $data]} {
            set pos [string length $data]
        }
        return $pos
    }
}

# Now we create an instance...
set string "The quick brown fox jumps over the lazy dog.\n"
set ch [chan create read [stringchan new $string]]

puts [gets $ch];   # Prints the whole string

seek $ch -5 end;
puts [read $ch];   # Prints just the last word

Look at that # Prints the whole string and # Prints just the last word β€” she works, bestie. πŸ”₯


πŸ‘€ SEE ALSO πŸ‘€


πŸ’… KEYWORDS πŸ’…

  • API
  • channel
  • ensemble
  • prefix
  • reflection

And that's the whole page, angel! πŸŽ€ The footer says this is Tcl, version 8.5, and the page is refchan(n) β€” so if anyone asks where you got all this, that's the source and the version, mwah. πŸ’– Go forth and reflect some channels, you absolute icon. πŸ‘‘βœ¨

πŸ“¦ where this page comes from
  • fedora 43: tcl-doc 1:9.0.2-1.fc43 Β· TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
  • fedora 44: tcl-doc 1:9.0.2-1.fc44 Β· TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms