'''[xk2600]''' I wanted the ability to provide a constant "keyed" string mechanism (similar to enums) and liked this concept... I need to convert it into a proc which can create these on demand. The premise is simple, dynamically write a proc that contains a switch which based on a single arg returns a result. **Static Constant Enumerated Strings** ====== namespace eval httpd [list proc status {code} {switch -exact -- $code} ] foreach {code message} { 100 Continue 101 {Switching Protocols} 102 Processing 200 OK 201 Created 202 Accepted 203 {Non-Authoritative Information} 204 {No Content} 205 {Reset Content} 206 {Partial Content} 207 Multi-Status 208 {Already Reported} 226 {IM Used} 300 {Multiple Choices} 301 {Moved Permenantly} 302 Found 303 {See Other} 304 {Not Modified} 305 {Use Proxy} 306 {Switch Proxy} 307 {Temporary Redirect} 308 {Permenant Redirect} 400 {Bad Request} 401 Unauthorized 402 {Payment Required} 403 Forbidden 404 {Not Found} 405 {Method Not Allowed} 406 {Not Acceptable} 407 {Proxy Authentication Required} 408 {Request Timeout} 409 Conflict 410 Gone 411 {Length Required} 412 {Precondition Failed} 413 {Payload Too Large} 414 {URI Too Long} 415 {Unsupported Media Type} 416 {Range Not Satisfiable} 417 {Expectation Failed} 421 {Misdircted Request} 422 {Unprocessable Entity} 423 Locked 424 {Failed Dependancy} 426 {Upgrade Required} 428 {Precondition Required} 429 {Too Many Requests} 431 {Request Header Fields Too Large} 451 {Unavailable For Legal Reasons} 500 {Internal Server Error} 501 {Not Implemented} 502 {Bad Gateway} 503 {Service Unavailable} 504 {Gateway Time-out} 505 {HTTP Version Not Supported} 506 {Variant Also Negotiates} 507 {Insufficient Storage} 508 {Loop Detected} 510 {Not Extended} 511 {Network Authentication Required} } { # This appends case + body onto the switch in the proc body # eventually resulting in a proc that looks like this: # proc ::httpd::status {code} { # switch -exact -- $code \ # 100 { # return {100 {continue}} # } \ # ... # 511 { # return {511 {Network Authentication Required}} # } # } # # ...and is pretty slick if I say so myself! namespace eval httpd [list proc status {code} \ [concat [info body ::httpd::status] \ $code \ [list [list return [list $code $message]]] \ ] ] } % ::httpd::status 200 200 OK ====== Comments, suggestions, improvements welcome. ---- [bll] 2017-10-17 Seems complicated. Why not just: ====== namespace eval httpd { variable vars set vars(dict.code.msg) { 100 Continue } proc status { code } { variable vars if { [dict exists $vars(dict.code.msg) $code] } { return [list $code [dict get $vars(dict.code.msg) $code]] } # handle future growth return [list $code "Code $code"] } } ====== ---- [Napier] 10-17-2017 Hmm, I may be misunderstanding what you are trying to do here but I would also agree that there is more being done here than is really needed. 1. Why not simply a dict at that point? Then you can add to it extremely easily by either accepting a second value to httpd::status or by simply doing a [[dict set ::httpd::STATUS_CODES $code $status]] (identical to the suggestion above but without arrays as it adds an unnecessary layer in my opinion and would be slower) ====== namespace eval httpd { variable STATUS_CODES { 100 Continue } proc status code { variable STATUS_CODES if {[dict exists $STATUS_CODES $code]} { return [list $code [dict get $STATUS_CODES $code]] } else { return [list $code UNKNOWN] } } } ====== 2. Seems like you want something like a var switch. This is also implemented within the [https://github.com/Dash-OS/tcl-modules/blob/master/varx-1.0.1.tm#L31%|%varx%|%] package as varx::switch ====== package require varx namespace eval httpd { proc status code { ::varx::switch $code { 100 Continue } } } ====== ---- 18-Oct-2017 change [list [list return [list $code $message]]] \ to [list [list return $message]] \ to get rid of the redundant code value change and the pesky extra curly brackets. ---- [xk2600] If I remember right, my goal was to maximize the performance on future calls as these error codes and the message that is output with them is static (for the lifetime of execution within the program) but is a called with every call to the webserver. I really need to go back and run some benchmarks but the theory was that the switch within the proc would perform faster than lookups in an array or a dict... taking that in mind, the intent was to dynamically write a proc (which when ran the first time would be byte compiled) by appending onto the switch statement with the foreach loop the contents of the error code... taking the example above the proc body should end up looking like: ====== proc ::httpd::status {code} { switch -exact -- $code \ 100 {return {100 Continue}} \ 101 {return {101 {Switching Protocols}}} \ 102 {return {102 Processing}} \ 200 {return {200 OK}} \ 201 {return {201 Created}} \ 202 {return {202 Accepted}} \ 203 {return {203 {Non-Authoritative Information}}} \ 204 {return {204 {No Content}}} \ 205 {return {205 {Reset Content}}} \ 206 {return {206 {Partial Content}}} \ 207 {return {207 Multi-Status}} \ 208 {return {208 {Already Reported}}} \ 226 {return {226 {IM Used}}} \ 300 {return {300 {Multiple Choices}}} \ 301 {return {301 {Moved Permenantly}}} \ 302 {return {302 Found}} \ 303 {return {303 {See Other}}} \ 304 {return {304 {Not Modified}}} \ 305 {return {305 {Use Proxy}}} \ 306 {return {306 {Switch Proxy}}} \ 307 {return {307 {Temporary Redirect}}} \ 308 {return {308 {Permenant Redirect}}} \ 400 {return {400 {Bad Request}}} \ 401 {return {401 Unauthorized}} \ 402 {return {402 {Payment Require\d}}} \ 403 {return {403 Forbidden}} \ 404 {return {404 {Not Found}}} \ 405 {return {405 {Method Not Allowed}}} \ 406 {return {406 {Not Acceptable}}} \ 407 {return {407 {Proxy Authentication Required}}} \ 408 {return {408 {Request Timeout}}} \ 409 {return {409 Conflict}} \ 410 {return {410 Gone}} \ 411 {return {411 {Length Required}}} \ 412 {return {412 {Precondition Failed}}} \ 413 {return {413 {Payload Too Large}}} \ 414 {return {414 {URI Too Long}}} \ 415 {return {415 {Unsupported Media Type}}} \ 416 {return {416 {Range Not Satisfiable}}} \ 417 {return {417 {Expectation Failed}}} \ 421 {return {421 {Misdircted Request}}} \ 422 {return {422 {Unprocessable Entity}}} \ 423 {return {423 Locked}} \ 424 {return {424 {Failed Dependancy}}} \ 426 {return {426 {Upgrade Required}}} \ 428 {return {428 {Precondition Required}}} \ 429 {return {429 {Too Many Requests}}} \ 431 {return {431 {Request Header Fields Too Large}}} \ 451 {return {451 {Unavailable For Legal Reasons}}} \ 500 {return {500 {Internal Server Error}}} \ 501 {return {501 {Not Implemented}}} \ 502 {return {502 {Bad Gateway}}} \ 503 {return {503 {Service Unavailable}}} \ 504 {return {504 {Gateway Time-out}}} \ 505 {return {505 {HTTP Version Not Supported}}} \ 506 {return {506 {Variant Also Negotiates}}} \ 507 {return {507 {Insufficient Storage}}} \ 508 {return {508 {Loop Detected}}} \ 510 {return {510 {Not Extended}}} \ 511 {return {511 {Network Authentication Required}}} } ====== To sweeten the code a little bit and provide some sugar: ====== proc staticEnum {procName keyArg body} { set namespace [namespace qualifiers $procName] set procedure [namespace tail $procName] # create base procedure proc $procName $keyArg [format {switch -exact -- $%s} $keyArg] # append switch case/eval clauses foreach pair of entries foreach [list key val] $body { proc $procName $keyArg [concat [info body $procName] \ [format {%s {return {%s %s}}} $key $key $val]] } } ====== Now we can write: ====== % namespace eval ::httpd {} % staticEnum ::httpd::status {code} { 100 Continue 101 {Switching Protocols} 102 Processing 200 OK 201 Created 202 Accepted 203 {Non-Authoritative Information} 204 {No Content} 205 {Reset Content} 206 {Partial Content} 207 Multi-Status 208 {Already Reported} 226 {IM Used} 300 {Multiple Choices} 301 {Moved Permenantly} 302 Found 303 {See Other} 304 {Not Modified} 305 {Use Proxy} 306 {Switch Proxy} 307 {Temporary Redirect} 308 {Permenant Redirect} 400 {Bad Request} 401 Unauthorized 402 {Payment Required} 403 Forbidden 404 {Not Found} 405 {Method Not Allowed} 406 {Not Acceptable} 407 {Proxy Authentication Required} 408 {Request Timeout} 409 Conflict 410 Gone 411 {Length Required} 412 {Precondition Failed} 413 {Payload Too Large} 414 {URI Too Long} 415 {Unsupported Media Type} 416 {Range Not Satisfiable} 417 {Expectation Failed} 421 {Misdircted Request} 422 {Unprocessable Entity} 423 Locked 424 {Failed Dependancy} 426 {Upgrade Required} 428 {Precondition Required} 429 {Too Many Requests} 431 {Request Header Fields Too Large} 451 {Unavailable For Legal Reasons} 500 {Internal Server Error} 501 {Not Implemented} 502 {Bad Gateway} 503 {Service Unavailable} 504 {Gateway Time-out} 505 {HTTP Version Not Supported} 506 {Variant Also Negotiates} 507 {Insufficient Storage} 508 {Loop Detected} 510 {Not Extended} 511 {Network Authentication Required} } % ::httpd::status 200 200 OK % time {::httpd::status [expr rand()*400+100]} 10000 1.7802 microseconds per iteration ====== comparitavely the utilization of dict as noted above: ====== namespace eval httpd { variable STATUS_CODES { 100 Continue 101 {Switching Protocols} 102 Processing 200 OK 201 Created 202 Accepted 203 {Non-Authoritative Information} 204 {No Content} 205 {Reset Content} 206 {Partial Content} 207 Multi-Status 208 {Already Reported} 226 {IM Used} 300 {Multiple Choices} 301 {Moved Permenantly} 302 Found 303 {See Other} 304 {Not Modified} 305 {Use Proxy} 306 {Switch Proxy} 307 {Temporary Redirect} 308 {Permenant Redirect} 400 {Bad Request} 401 Unauthorized 402 {Payment Required} 403 Forbidden 404 {Not Found} 405 {Method Not Allowed} 406 {Not Acceptable} 407 {Proxy Authentication Required} 408 {Request Timeout} 409 Conflict 410 Gone 411 {Length Required} 412 {Precondition Failed} 413 {Payload Too Large} 414 {URI Too Long} 415 {Unsupported Media Type} 416 {Range Not Satisfiable} 417 {Expectation Failed} 421 {Misdircted Request} 422 {Unprocessable Entity} 423 Locked 424 {Failed Dependancy} 426 {Upgrade Required} 428 {Precondition Required} 429 {Too Many Requests} 431 {Request Header Fields Too Large} 451 {Unavailable For Legal Reasons} 500 {Internal Server Error} 501 {Not Implemented} 502 {Bad Gateway} 503 {Service Unavailable} 504 {Gateway Time-out} 505 {HTTP Version Not Supported} 506 {Variant Also Negotiates} 507 {Insufficient Storage} 508 {Loop Detected} 510 {Not Extended} 511 {Network Authentication Required} } proc status code { variable STATUS_CODES if {[dict exists $STATUS_CODES $code]} { return [list $code [dict get $STATUS_CODES $code]] } else { return [list $code UNKNOWN] } } } % ::httpd::status 200 200 OK % time {::httpd::status [expr rand()*400+100]} 10000 2.7135 microseconds per iteration % info patchlevel 8.6.8 ====== 1.7ms vs 2.7ms static proc created dynamically at startup vs utilizing dict for lookup, the static proc provides a 58% improvement in performance, which is far from what I would consider negligible, especially on a webserver dumping out 200k requests/min. ---- <>Concept