A common idiom in programming is "use this value unless it isn't what I want to have; in that case use this default value". For instance, when assigning a value to a variable, it can be useful to make sure that the variable gets some safe value instead if the intended value isn't up to snuff. For me, it's often "I'd like to use `$a` unless it's an empty string, in which case I'll use `$b`". So I have this little `[proc]` which I tend to copy into my projects (as you can see, it's possible to have some value other than an empty string as the undesired value; actually I have never used that option except when testing the command): ====== proc either {value default {nullval {}}} { expr {$value ne $nullval ? $value : $default} } # use like this: set foo {} either $foo Tcl # -> Tcl set foo xxx either $foo yyy # -> xxx either $foo yyy xxx # -> yyy ====== A variant of this is to define the unwanted value as any logically false value (`0`, `false`, or `no` in Tcl): this works like the ''or'' operator (however it is written) in some languages (like Scheme's `or` or Perl's `||`) but ''not'' as in other languages which either 1) don't accept non-boolean values as operands to ''or'' (Tcl doesn't), or 2) always has the ''or'' operator return a boolean value, or both. ====== proc eitherOr {value default} { expr {$value ni {0 "false" "no"} ? $value : $default} } set foo xxx eitherOr $foo yyy # -> xxx set foo no eitherOr $foo yyy # -> yyy ====== Another variant is to instead of an unwanted value use however the language defines the undefined state. Some languages have operators (known as ''null coalescing operators'') for this, such as C#'s `??` or Perl's `//`; Scheme's `or` works here too. Tcl doesn't have a value for ''undefined'' / ''[null]'', but at least we can test a variable for existence: ====== proc eitherExists {varname default} { upvar $varname _varname expr {[info exists _varname] ? $_varname : $default} } set foo xxx eitherExists foo yyy # -> xxx unset foo eitherExists foo yyy # -> yyy ====== Finally (?) we can use a provided predicate function to tell us whether to use the value or the default value. Note that the function must be an actual ''predicate'', i.e. return a legal boolean value (`1`, `true`, `yes`, `0`, `false`, or `no`). ====== proc eitherApply {value default func} { expr {[apply $func $value] ? $value : $default} } set foo xxx eitherApply $foo yyy {{val} {string match x* $val}} # -> xxx set foo aaa eitherApply $foo yyy {{val} {string match x* $val}} # -> yyy ====== This is of course the most generic variant. Actually it can be used to redefine the original command: ====== proc either {value default {func {{val} {expr {$val ne {}}}}}} { expr {[apply $func $value] ? $value : $default} } set foo {} either $foo Tcl # -> Tcl set foo xxx either $foo yyy # -> xxx either $foo yyy {{val} {expr {$val ne "xxx"}}} # -> yyy ====== [aspect]: thanks for refreshing this - I love the name [[either]] and I'm definitely stealing that! Not so sure about the subcommands .. they might be a good case for sprucing up with [options and arguments]. A similar pattern I've been using a lot lately but irritatingly can't find a good name for is: ====== proc ifnotempty {_var args} { upvar 1 $_var var if {[info exists var] && $var ne ""} { uplevel 1 {*}$args } } ====== I've considered [[maybe]], [[iff]] (which might be more like an error-suppressing [if]) .. but nothing quite fits. [[name redacted]]: the term ''iff'' is usually understood as meaning "if and only if", so I wouldn't use that. Maybe `ifhas`? [aspect]: Oops - I mis-copied the code. With the `{*}` hopefully it makes more sense, and makes the comment I deleted redundant. ([[name redacted]]: I'm putting it back inside a discussion tag for the time being, we'll delete it later when the discussion is over.) No, the `{*}` doesn't necessarily make very much more sense. The `[uplevel]` in effect already applies an implied `{*}` to `$args` (just like `[eval]` does), so what you get is a double expansion of the argument list. This means that the user can now either provide a script as a sequence of arguments: === ifnotempty foo puts Foo ; puts Bar === or as a script body: === ifnotempty foo { puts Foo ; puts Bar } ;# could've been on separate lines === or both (the semicolon seems out of place, but is necessary here): === ifnotempty foo { puts Foo ; } puts Bar === While this kind of freedom might seem like a nice thing (I suspect the [Perl] crowd would be all over it `;)`), ultimately it will, I think, be confusing to the user. My personal preference is to make the code unambiguous in what it accepts. The `uplevel 1 $args` form accepts a sequence of arguments but not a script body, the `uplevel 1 $body` form accepts the latter but not the former (well, it ''does'' accept single-word command invocations with or without braces, such as `[pwd]`), the `uplevel 1 {*}$args` form accepts both and a mixture of both. I would go with the second or first form, but not with the third. [aspect] - well said. I will point out that the behaviour with {*}$args more closely mimics Tcl core commands, including [uplevel]. I've always found this "implicit concat" behaviour a bit unnerving (see also: [after], [eval], ...). I can see how it served to make command/script composition less ugly in the absence of {*}, but I always find myself second-guessing where to wrap arguments with [list] -- and sometimes I get it horribly wrong, as in this example :-). Hm, I just searched for [implicit concat] and found no obvious hits. This discussion almost warrants a page of its own .. [[name redacted]]: actually, I think `after`, `eval`, and `uplevel` are the only ones that do concat-and-evaluate. `[catch]` doesn't, for instance (the command syntax would need a major rewrite to make that possible). There are lots and lots of control commands that take singular script arguments, however. I also thought of another point earlier but forgot to mention it. If we rename the different versions `ine1` (your original version, with `uplevel 1 $args`), `ine2` (my version, with `uplevel 1 $script`), and `ine3` (your later version, with `uplevel 1 {*}$args`), and set the command to print a) the value of `foo`, and b) the value of `msg` (which is the text "foo bar"): ====== % set foo bar # -> bar % set msg "foo bar" # -> foo bar % ine1 foo puts $foo # => foo % ine1 foo puts $msg # => foo bar % ine2 foo puts $foo # =2> wrong # args: should be "ine2 _var body" % ine2 foo { puts $foo } # => foo % ine2 foo { puts $msg } # => foo bar % ine3 foo puts $foo # => foo % ine3 foo puts $msg # =2> can not find channel named "foo" ====== I'd say that it's not quite obvious what's wrong with the last invocation (and why the next-to-last invocation is ok) unless you are familiar with the implementation of the command (the problem with the first invocation of `ine2`, in contrast, is fairly obvious even from the automatically generated error message). Again, the `ine1` and `ine2` commands are internally consistent, while the `ine3` command seems inconsistent (of course, it isn't really, but seeming inconsistency is almost as bad as real inconsistency). <> ---- [AMG]: As I wrote on the [[[append]]] page, [[append]] can be used to set a variable to empty string if it doesn't already exist, leaving its value alone otherwise. This is often all that's needed. Just do: ====== append var "" ====== As a bonus, this returns the variable's value (or empty string if it didn't exist), so just write `[[append var ""]]` instead of `$var` or `[[set var]]`. [[name redacted]]: that would indeed equivalent to using `eitherExists` above with the invocation `eitherExists var ""`. It doesn't handle any of the other cases, though. <> Category Concept | Category Example | Category Functional Programming | Quick'n'dirty