According to Wikipedia ,
EKB: FB, I agree with your point. I rewrote this so it reads as documentation, rather than a discussion. Is this OK with you? FB: No problem!
Note that this is not the same as simply putting text inside curly braces. It might seem like it since, for example, the Ruby example from the Wikipedia article:
puts <<GROCERY_LIST Grocery list ------------ 1. Salad mix. 2. Strawberries.* 3. Cereal. 4. Milk.* * Organic GROCERY_LIST
can easily be implemented in Tcl:
puts {Grocery list ------------ 1. Salad mix. 2. Strawberries.* 3. Cereal. 4. Milk.* * Organic}
But a "pure" heredoc is format-agnostic. The example above will fail if the string includes an unbalanced brace, e.g.:
Ruby:
puts <<GROCERY_LIST Grocery list } ------------ 1. Salad mix. 2. Strawberries.* 3. Cereal. 4. Milk.* * Organic GROCERY_LIST
Tcl:
puts {Grocery list } # everything below is a syntax error because of the above close brace. ------------ 1. Salad mix. 2. Strawberries.* 3. Cereal. 4. Milk.* * Organic}
So in Tcl you have several ways of specifying string litterals:
Tcl doesn't provide an heredoc like feature, because all quoting rules require the user to escape all significant characters. This is a need that FB tries to address in Cloverfield with the {data} word modifier (see Cloverfield - Tridekalogue, section Word modifiers, item Raw data). The above example becomes:
puts {data}GROCERY_LIST Grocery list } ------------ 1. Salad mix. 2. Strawberries.* 3. Cereal. 4. Milk.* * Organic GROCERY_LIST
which is very similar to the Ruby version. The real strength of heredoc is to let the user supply an arbitrary delimiter (here GROCERY_LIST) to circumvent the regular formatting rules.
BTW, the present Wiki provides heredoc-like markup with the six- and three-equal sign sequences (see Wiki formatting rules). Of course they are not real heredocs because one cannot use these sequences within the quoted text, but the concept is quite similar.
dbohdan 2015-08-06: What follows is a rough sketch of a preprocessor that lets you embed heredocs in Tcl source code. I have not seriously tested it; please fix any bugs you find. Note that with this preprocessor each heredoc must start with the text <<<(LABEL) on a line of its own.
# v0.0.1 package require fileutil namespace eval ::heredoc {} # Extract a heredoc from Tcl source code. proc ::heredoc::extract {source label} { set lines [split $source \n] set heredoc {} set offset [lsearch -exact $lines "<<<$label"] if {$offset == -1} { error "can't find a heredoc with label $label" } set line {} for {set i $offset} {$line ne $label} {incr i} { set line [lindex $lines $i] lappend heredoc $line } return [join [lrange $heredoc 1 end-1] \n] } # Convert Tcl source code with embedded heredocs to standard Tcl. proc ::heredoc::embed-all source { set lines [split $source \n] set result {} set label {} set on 0 foreach line $lines { if {$on} { if {$line eq $label} { set on 0 lappend result "\[join [list $acc] \\n\]" } else { lappend acc $line } } else { if {[regexp ^<<<(.*)$ $line _ label]} { set on 1 set acc {} } else { lappend result $line } } } return [join $result \n] }
puts \ <<<HEREDOC1 Hello, World! {{{ }} HEREDOC1 set a \ <<<HEREDOC2 Blah! HEREDOC2 puts $a
puts \ [join {{Hello, World!} \{\{\{ \}\}} \n] set a \ [join Blah! \n] puts $a
aspect .. by looking at info frame, one can do (arguably) slightly better:
proc <<< args { if {[llength $args] < 2} {error "incorrect args: expected \"<<< cmd ?arg ...? marker\""} set marker [lindex $args end] set herecmd [lrange $args 0 end-1] set frame [info frame -1] dict with frame {} if {$type ne "source"} {error "Invalid location for <<<"} ;# not safe set fd [open $file r] for {set i 0} {$i < $line} {incr i} { ;# skip what's already been evaluated append script [gets $fd] } if {![info complete $script]} {error "invalid location for <<<"} ;# definitely not safe! while {[gets $fd line]} { ;# get the heredoc if {$line eq $marker} break lappend heredoc $line } set heredoc [join $heredoc \n] set script [read $fd] ;# rest of the script close $fd uplevel 1 $herecmd [list $heredoc] uplevel 1 $script return -code return ;# tell our caller (source) that it's done } puts starting <<< set xxx _END_ Hello, World! {{{ }} _END_ puts $xxx puts etc
Of course this breaks horribly if you try to put multiple here-docs in the same file, and (for the same reason) anything after the heredoc will lie in error traces about where it was defined. These could be worked around by mounting and sourcing a vfs proxy of the original file, but that's some pretty serious interpreter abuse and probably illegal in some places.
PYK 2015-08-08:
Heredocs are in the Tcl doesn't have that because it would be a misfeature category. Other languages need heredocs because their syntax is more irregular. Tcl doesn't have that problem. Anything that can be accomplished with a heredoc can be accomplished just as easily with standard Tcl syntax:
puts " Hello, World! {{{ }} "
string cat or append can be used to make easy work of more complicated text:
string cat {Hello, World you owe me $5! } "{{{ }}"