I am looking for an "expandable" switch statement or something similar. I
have a given switch statement in my code as e.g.:
switch -glob aaab {
a*b -
b {expr {1}}
a* {expr {2}}
default {expr {3}}
}
Now later in the code I want to "add" another alternative to the switch
statement like:
c {expr {4}}
Is there a procedure I can call like add_to_switch? It seems I am looking
for something like a decision table. The end result should then be:
switch -glob aaab {
a*b -
b {expr {1}}
a* {expr {2}}
c {expr {4}}
default {expr {3}}
}
This is a basic idea, because I have not yet a definitive idea how to
spacify and handle the order of alternatives.
thanks,
s
The switch command (at least in the format you used) takes a list as
its last argument. So you can simply put that into a variable and
use the normal list operations to manipulate it:
set switch {
a*b -
b {expr {1}}
a* {expr {2}}
default {expr {3}}
}
switch -glob aaab $switch
set switch [linsert $switch end-2 c {expr {4}}]
switch -glob c $switch
Schelte.
If I understand your need correctly, you might well be better served
by an appropriate loop on a (modifiable) list rather than self-
modifying code (though Tcl can do it as well):
set ll { a*b -
b {...}
a* {...}
c {...}
}
set def {...}
proc mainswitch x {
foreach {pat action} $::ll {
if {[string match $pat $x]} {return [uplevel 1 $action]}
}
return [uplevel 1 $::def]
}
proc addcase {pat action} {lappend ::ll $pat $action}
Now if you really want to use [switch], this works as well:
proc mainswitch2 x {
switch -glob -- $x [concat $::ll [list default $::def]]
}
problem being the fact that the [switch] body won't benefit from
compilation speedup.
You can get the best of both worlds by calling [proc] dynamically, but
that may be beyond what you need. Please tell me.
-Alex
> If I understand your need correctly, you might well be better served
> by an appropriate loop on a (modifiable) list rather than self-
> modifying code (though Tcl can do it as well):
>
> set ll { a*b -
> b {...}
> a* {...}
> c {...}
> }
> set def {...}
>
> proc mainswitch x {
> foreach {pat action} $::ll {
> if {[string match $pat $x]} {return [uplevel 1 $action]}
> }
> return [uplevel 1 $::def]
> }
>
> proc addcase {pat action} {lappend ::ll $pat $action}
>
> Now if you really want to use [switch], this works as well:
>
> proc mainswitch2 x {
> switch -glob -- $x [concat $::ll [list default $::def]]
> }
>
> problem being the fact that the [switch] body won't benefit from
> compilation speedup.
> You can get the best of both worlds by calling [proc] dynamically, but
> that may be beyond what you need. Please tell me.
>
> -Alex
Thanks both Schelte and Alex!
Probably I start with Scheltes idea, because it is simplest. I am not
concerned about speed at the moment, because I use the switch just once
during a program run (it is a url router for a cgi application). But I am
still open to suggestions. Basically my application is a cgi, which
dispatches on different urls mentioned in the switch statement. I want to
modify the switch statement before invocation sometimes because I have some
session or authentication information, and then the routes have different
properties.
thanks,
s
I'd do it like this, using the alternate form of [switch]:
set defs {
a*b -
b {expr {1}}
a* {expr {2}}
}
switch -glob -- $value {*}$defs default {
expr {3}
}
Like that, adding another clause is just this:
lappend defs c {expr {4}}
Yet you won't disrupt the special handling of 'default', which has to
be the last clause. (You could also put the default handling script in
its own variable, or other arbitrarily complex solution. Your call.)
Donal.
> I'd do it like this, using the alternate form of [switch]:
>
> set defs {
> a*b -
> b {expr {1}}
> a* {expr {2}}
> }
>
> switch -glob -- $value {*}$defs default {
> expr {3}
> }
>
> Like that, adding another clause is just this:
>
> lappend defs c {expr {4}}
>
> Yet you won't disrupt the special handling of 'default', which has to
> be the last clause. (You could also put the default handling script in
> its own variable, or other arbitrarily complex solution. Your call.)
>
> Donal.
Thanks Donal, this is a great solution using {*}.
Maybe a related question, but how do you search for {*} on the wiki? (I
already know about wiki.tcl.tk/17158, but I don't know how to search for it).
thanks,
s.
It seems to not work for that. So I ask Jos Decoster if that can be
made to work, at least for the exact page name part of the search. :-)
Donal.