''[Peter Lewerin] (2013-12-26): I can't believe this basic trick hasn't been described here yet, but I can't find it even after repeated searches. I'll put it up here, and if it's already on the wiki somewhere, let me know and I'll nominate this page for deletion.'' 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. [PL]: 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. ---- [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]]`. [PL]: that would indeed equivalent to using `eitherExists` above with the invocation `eitherExists var ""`. It doesn't handle any of the other cases, though. <> beginner | Category Concept | Category Example | Category Functional Programming | Quick'n'dirty