The concept of Named Arguments as Dictionaries is to provide an extensible means to extend argument definitions to include rules and allow them to be given in any order, without introducing a major syntax change to proc. The Tcl implementation is reasonably trivial: ====== package provide nproc 0.1 proc ::@args {argdef} { if {[catch {dict keys $argdef} argnames]} { puts $argnames error "Argument definition is not a well formed dict" } set result {} append result {if {[llength ${args}]==1} {set @args [lindex $args 0]} else {set @args $args}} \n foreach {field info} $argdef { set variable $field set aliases {} set mandatory 1 if {[dict exists $info aliases]} { set aliases [dict get $info aliases] } if {[dict exists $info variable]} { set variable [dict get $info variable] } if {[dict exists $info mandatory]} { set mandatory [dict get $info mandatory] } foreach {name} $aliases { if {$name eq $field} continue set map [list @field@ $field @name@ $name @variable@ $variable] set argbody [list if {[dict exists ${@args} {@name@}] && ![dict exists ${@args} {@field@}]}] if {[dict exists $info upvar]} { lappend argbody {upvar @level@ [dict get ${@args} {@name@}] {@variable@}} } else { lappend argbody {set {@variable@} [dict get ${@args} {@name@}] ; dict set @args {@field@} [dict get ${@args} {@name@}]} } append result [string map $map $argbody] \n } set map [list @field@ $field @name@ $field @variable@ $variable] set argbody [list if {[dict exists ${@args} {@name@}]}] if {[dict exists $info upvar]} { set level 1 if {[dict exist $info level]} { set level [dict get $info level] } lappend map @level@ $level @upvar@ [dict get $info upvar] lappend argbody {upvar @level@ [dict get ${@args} {@name@}] {@variable@}} lappend argbody else {upvar @level@ {@upvar@} {@variable@}} } else { lappend argbody {set {@variable@} [dict get ${@args} {@name@}]} dict with info {} if {[dict exists $info default]} { lappend map @dvalue@ [dict get $info default] lappend argbody else {set {@variable@} {@dvalue@}} } elseif {$mandatory} { lappend argbody else {error "@field@ is required"} } } append result [string map $map $argbody] \n } return $result } # Optional, replace the behavior of proc if {[info command ::_proc] eq {}} { rename ::proc ::_proc _proc ::proc {name arglist body} { set result {} if {[lindex [lindex $arglist end] 0] eq "@args"} { append result [::@args [lindex [lindex $arglist end] 1]] set arglist [lrange $arglist 0 end-1] lappend arglist args } append result $body ::_proc $name $arglist $result } } ### # Named Procedures as new command ### proc ::@proc {name argdef body} { set result {} append result [::@args $argdef] \n append result $body ::proc $name args $result } proc ::oo::define::@method {name argdef body} { set class [lindex [::info level -1] 1] set result {} append result [::@args $argdef] \n append result $body oo::define $class method $name args $result } ====== And here are some examples of play testing the new rules: ====== ### # Examples ### proc standard {subject sender {@args { mtime {mandatory 0} body {} }}} { set auto_reply [subst {To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply } puts "STANDARD" puts [info args standard] puts [info body standard] puts -- standard {Hi there} {yoda@etoyoc.com} body {Extra garbage} ===== Output: ===== STANDARD subject sender args if {[llength ${args}]==1} {set @args [lindex $args 0]} else {set @args $args} if {[dict exists ${@args} {mtime}]} {set {mtime} [dict get ${@args} {mtime}]} if {[dict exists ${@args} {body}]} {set {body} [dict get ${@args} {body}]} else {error "body is required"} set auto_reply [subst {To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply -- To: yoda@etoyoc.com Subject: Re: Hi there Dear yoda@etoyoc.com, Thank you for writing us about Hi there ===== New proc style ===== @proc newstyle { subject {mandatory 1} sender {mandatory 1} mtime {mandatory 0} body {} } { set auto_reply [subst {To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply } puts "NEW" puts [info args newstyle] puts [info body newstyle] puts -- newstyle subject {Hi there} sender {yoda@etoyoc.com} body {Extra garbage} mtime [clock format [clock seconds]] @proc withupvar { subject {mandatory 1} sender {mandatory 1 aliases from} mtime {} body {} uuid {upvar nextmsgid} } { set auto_reply [subst {Msgid: [incr uuid] To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply } puts "WITHUPVAR" puts [info args withupvar] puts [info body withupvar] puts -- withupvar subject {Hi there} sender {yoda@etoyoc.com} body {Extra garbage} mtime [clock format [clock seconds]] withupvar subject {Hi there} from {yoda@etoyoc.com} body {Extra garbage} mtime [clock format [clock seconds]] ===== Output: ===== NEW args if {[llength ${args}]==1} {set @args [lindex $args 0]} else {set @args $args} if {[dict exists ${@args} {subject}]} {set {subject} [dict get ${@args} {subject}]} else {error "subject is required"} if {[dict exists ${@args} {sender}]} {set {sender} [dict get ${@args} {sender}]} else {error "sender is required"} if {[dict exists ${@args} {mtime}]} {set {mtime} [dict get ${@args} {mtime}]} if {[dict exists ${@args} {body}]} {set {body} [dict get ${@args} {body}]} else {error "body is required"} set auto_reply [subst {To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply -- To: yoda@etoyoc.com Subject: Re: Hi there Dear yoda@etoyoc.com, Thank you for writing us about Hi there WITHUPVAR args if {[llength ${args}]==1} {set @args [lindex $args 0]} else {set @args $args} if {[dict exists ${@args} {subject}]} {set {subject} [dict get ${@args} {subject}]} else {error "subject is required"} if {[dict exists ${@args} {from}] && ![dict exists ${@args} {sender}]} {set {sender} [dict get ${@args} {from}] ; dict set @args {sender} [dict get ${@args} {from}]} if {[dict exists ${@args} {sender}]} {set {sender} [dict get ${@args} {sender}]} else {error "sender is required"} if {[dict exists ${@args} {mtime}]} {set {mtime} [dict get ${@args} {mtime}]} else {error "mtime is required"} if {[dict exists ${@args} {body}]} {set {body} [dict get ${@args} {body}]} else {error "body is required"} if {[dict exists ${@args} {uuid}]} {upvar 1 [dict get ${@args} {uuid}] {uuid}} else {upvar 1 {nextmsgid} {uuid}} set auto_reply [subst {Msgid: [incr uuid] To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply -- Msgid: 1 To: yoda@etoyoc.com Subject: Re: Hi there Dear yoda@etoyoc.com, Thank you for writing us about Hi there Msgid: 2 To: yoda@etoyoc.com Subject: Re: Hi there Dear yoda@etoyoc.com, Thank you for writing us about Hi there ===== As an OO method ===== oo::class create nclass { @method message { subject {mandatory 1} sender {mandatory 1 aliases from} mtime {} body {} uuid {upvar nextmsgid} } { set auto_reply [subst {Msgid: [incr uuid] To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists ${@args} mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply } } puts "OO METHOD" puts [info class definition ::nclass message] puts -- nclass create N N message subject {Hi there} from {yoda@etoyoc.com} body {Extra garbage} mtime [clock format [clock seconds]] ====== And the output: ====== OO METHOD args {if {[llength ${args}]==1} {set @args [lindex $args 0]} else {set @args $args} if {[dict exists ${@args} {subject}]} {set {subject} [dict get ${@args} {subject}]} else {error "subject is required"} if {[dict exists ${@args} {from}] && ![dict exists ${@args} {sender}]} {set {sender} [dict get ${@args} {from}] ; dict set @args {sender} [dict get ${@args} {from}]} if {[dict exists ${@args} {sender}]} {set {sender} [dict get ${@args} {sender}]} else {error "sender is required"} if {[dict exists ${@args} {mtime}]} {set {mtime} [dict get ${@args} {mtime}]} else {error "mtime is required"} if {[dict exists ${@args} {body}]} {set {body} [dict get ${@args} {body}]} else {error "body is required"} if {[dict exists ${@args} {uuid}]} {upvar 1 [dict get ${@args} {uuid}] {uuid}} else {upvar 1 {nextmsgid} {uuid}} set auto_reply [subst {Msgid: [incr uuid] To: $sender Subject: Re: $subject Dear $sender, Thank you for writing us about $subject}] if {[dict exists $@args mtime]} { append auto_reply " on [clock format [clock scan $mtime]]" } puts $auto_reply } -- Msgid: 3 To: yoda@etoyoc.com Subject: Re: Hi there Dear yoda@etoyoc.com, Thank you for writing us about Hi there on Mon Oct 23 20:03:06 EDT 2017 ====== <>Enter Category Here