Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to test for an empty list? ({})

7,825 views
Skip to first unread message

Alexander Rast

unread,
Mar 15, 2012, 9:56:41 PM3/15/12
to
Hi, new troubles, now related to using arguments in a proc.

I have:

proc setGroupParams {args} {

if {$args == <empty list>} {
set params <default-params>
} elseif {$args == <single dictionary>} {
<set required params to those specified in the dictionary>
} else {
<set required params using the first dictionary, other
params using other dictionaries>
}
}

The critical thing here is that setGroupParams may receive as args
either an empty list, a single dictionary, or a list of dictionaries.
This seems to create a problem in detecting the empty list case.
Nothing I've tried for the test seems to work. The obvious answer:

if {$args == {}}

definitely didn't work. I ran some puts's that indicated that $args
was indeed {} - at least, this is what it outputs to the screen
(stdout). Running llength $args returns 1. So it thinks it's a list -
with a single empty value. Various forms of test for an empty list all
failed, falling through to the default case of a list of dictionaries
- and given that it would be possible that args is actually a list
consisting of a single dictionary I can't use llength $args as the
test. How, then, can I test for this empty list?

(More ideally, I'd like to find some global way of handling all 3
cases without having to do a test, but there doesn't seem to be an
easy way of stepping through a dictionary that might have no entries,
which certainly the 2 cases where dictionaries are present need to
do.)

Thanks,

Alex Rast

DrS

unread,
Mar 15, 2012, 11:34:26 PM3/15/12
to
On 3/15/2012 9:56 PM, Alexander Rast wrote:
> Hi, new troubles, now related to using arguments in a proc.
>
> I have:
>
> proc setGroupParams {args} {
>
> if {$args ==<empty list>} {
> set params<default-params>
> } elseif {$args ==<single dictionary>} {
> <set required params to those specified in the dictionary>
> } else {
> <set required params using the first dictionary, other
> params using other dictionaries>
> }
> }
>
> The critical thing here is that setGroupParams may receive as args
> either an empty list, a single dictionary, or a list of dictionaries.
> This seems to create a problem in detecting the empty list case.
> Nothing I've tried for the test seems to work. The obvious answer:
>

args is always a list. If you are receiving a list of one element which
turns out to be an empty list, look to the caller to find out why and
fix it if needed.

Also, why are you using "args"? As you state, if the input is always a
single element (be it a list, a dictionary or a list of dictionaries),
just use a named argument and your troubles would go away.


If you simply want to get rid of empty elements, a quick and dirty way is:
% set new_args [eval concat $args]

However, be careful that this will also flatten lists in the arguments.


Hopefully this is helpful...

DrS



Harald Oehlmann

unread,
Mar 16, 2012, 3:39:42 AM3/16/12
to
On 16 Mrz., 02:56, Alexander Rast <alex.rast.techni...@gmail.com>
wrote:
> Hi, new troubles, now related to using arguments in a proc.
>
> I have:
>
> proc setGroupParams {args} {
>
>         if {$args == <empty list>} {
>            set params <default-params>
>         } elseif {$args == <single dictionary>} {
>            <set required params to those specified in the dictionary>
>         } else {
>             <set required params using the first dictionary, other
> params using other dictionaries>
>         }
>
> }

Dear Alex,

the answer by DrS is good.

To test for an empty list in a clean way, please use:
if { 0 == [llength $args] } {

For me, your 3rd if is not clear. On the command line, there is a list
of dicts, isn't it ?
Example implementation for that:
proc setGroupParams {args} {
switch -exact -- [llength $args] {
0 {
set params <default-params>
}
1 {
<set required params to those specified in the dictionary>
}
default {

Donal K. Fellows

unread,
Mar 16, 2012, 7:31:47 AM3/16/12
to
On 16/03/2012 07:39, Harald Oehlmann wrote:
> To test for an empty list in a clean way, please use:
> if { 0 == [llength $args] } {

Or you can look at the overall length of the list returned by [info
level 0]; that includes all the arguments, not just the ones bound to
$args. (For some ways of building an interface, this is the only sane
way to do it. Be aware that the first argument is actually the name of
the command...)

Donal.

Mark Janssen

unread,
Mar 16, 2012, 7:30:38 AM3/16/12
to
A list with a single empty element is not the empty list as you found out. It's equivalent to the string "{}" instead of "".
So either:
- Don't call the script with an empty argument, so script.tcl instead of script.tcl ""
- Or use {[lindex $args 0] eq ""}

Mark

Alexander Rast

unread,
Mar 16, 2012, 12:04:56 PM3/16/12
to
On Mar 16, 3:34 am, DrS <drscr...@gmail.com> wrote:
> On 3/15/2012 9:56 PM, Alexander Rast wrote:
>
>
>
> > Hi, new troubles, now related to using arguments in a proc.
>
> > I have:
>
> > proc setGroupParams {args} {
>
> >          if {$args ==<empty list>} {
> >             set params<default-params>
> >          } elseif {$args ==<single dictionary>} {
> >             <set required params to those specified in the dictionary>
> >          } else {
> >              <set required params using the first dictionary, other
> > params using other dictionaries>
> >          }
> > }
>
> > The critical thing here is that setGroupParams may receive as args
> > either an empty list, a single dictionary, or a list of dictionaries.
> > This seems to create a problem in detecting the empty list case.
> > Nothing I've tried for the test seems to work. The obvious answer:
>
> args is always a list.  If you are receiving a list of one element which
> turns out to be an empty list, look to the caller to find out why and
> fix it if needed.
>
> Also, why are you using "args"?  As you state, if the input is always a
> single element (be it a list, a dictionary or a list of dictionaries),
> just use a named argument and your troubles would go away.

What I was saying is, by the process whereby "args" in the proc is
turned into a list, (as you say "args is always a list") the actual
arguments passed in are made into lists. What's going on is that the
proc is being fed from the output of another (not readily changed
because it sits in a package with standard interfaces) proc whose
output may be one of 3 possible cases. It may output an empty string,
it may output a dictionary, or it may output multiple dictionaries.
Thus when input into the proc these are transformed, respectively,
into a list consisting of an empty element, a list of a single
dictionary, or a list of dictionaries. The case where the output of
the lower-level proc is an empty string is not an error or
misbehaviour on the part of the low-level proc. The lower level proc
reads in lines from an input file that specifies, in this case, a
neural network. Generally, each specification line has a list of
parameters. The difficult bit is that the line may actually have no
parameters, which indicates in fact that all parameters are to be set
to certain system default values. In that case the low-level proc
returns the empty string.

> If you simply want to get rid of empty elements, a quick and dirty way is:
> % set new_args [eval concat $args]
>
> However, be careful that this will also flatten lists in the arguments.

Which is what I need it to NOT do, because this will bung together
lists of dictionaries.

Also Harald Oehlmann said:

>To test for an empty list in a clean way, please use:
>if { 0 == [llength $args] }

That was one of the things I tried, but it didn't work because
[llength $args} reports 1 for the first case, namely args == {}

From what's been posted so far, I get the distinct impression that the
answer is "there's no easy way to do this". In fact, the problem of
"fall-through defaults" is proving overall to be an astonishingly
difficult one to solve.

Gerald W. Lester

unread,
Mar 16, 2012, 12:53:45 PM3/16/12
to
Can you give example code of how you are "feeding" the proc with args?

If you are doing: ProcWithArgs [SomeOtherProc $p1 $p2]

Then no matter what SomeOtherProc returns, the llength of args will always be 1.

--
+------------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+------------------------------------------------------------------------+

DrS

unread,
Mar 16, 2012, 2:38:45 PM3/16/12
to
On 3/16/2012 12:04 PM, Alexander Rast wrote:
>
> What I was saying is, by the process whereby "args" in the proc is
> turned into a list, (as you say "args is always a list") the actual
> arguments passed in are made into lists. What's going on is that the
> proc is being fed from the output of another (not readily changed
> because it sits in a package with standard interfaces) proc whose
> output may be one of 3 possible cases. It may output an empty string,
> it may output a dictionary, or it may output multiple dictionaries.


Please read the docs and what everyone is trying to point out. Until
then, here is a simple block of code to determine each of the three cases:

if {[llength $args] == 0} {
puts "himmm... called with no args from command line?"

} elseif {[llength $args] == 1} {
puts "OK --> single empty argument or a single dict?"
set which [lindex $args 0]
if {[string length $which] == 0} {
puts "Case 1: empty list (assuming that caller doesn't return empty dicts"
} else {
puts "Case 2: A dict"
}
} else {
puts "Case 3: a list of dicts..."
}


>
> From what's been posted so far, I get the distinct impression that the
> answer is "there's no easy way to do this". In fact, the problem of
> "fall-through defaults" is proving overall to be an astonishingly
> difficult one to solve.
>


See if the code above helps.


DrS

Alexander Rast

unread,
Mar 17, 2012, 7:50:49 PM3/17/12
to
On Mar 16, 4:53 pm, "Gerald W. Lester" <Gerald.Les...@KnG-
Consulting.net> wrote:
>
> Can you give example code of how you are "feeding" the proc with args?
>
> If you are doing:  ProcWithArgs [SomeOtherProc $p1 $p2]
>
> Then no matter what SomeOtherProc returns, the llength of args will always be 1.

The route is complex. I'd like it to be simpler but earlier questions
for the basic problem (I need to intercept a series of custom commands
for another application (Lens) that normally would be processed by
that application, and send them through another instantiation route to
implement them on hardware, suggested that this might be the most
likely way to succeed.

First, a top-level command specifies a function (in this case called
"addGroup"). addGroup has a few required arguments, and then a host of
other optional arguments: the calling syntax is addGroup Name
Num_Units <optional-args>, where optional args is possibly long list
of other args that specify group parameters.

The interception itself works through the unknown handler, which
reparses the command into a usable format:

proc Lens_Unknown {args} {
uplevel 1 LScan start \"$args\"
set command [uplevel 1 {eval LParse parse}]
uplevel 1 namespace eval ${Lens}PACMAN_CMD $command
...
}

the namespace eval then reaches the redefined addGroup command:

proc addGroup {args} {
set RequiredArgs [lindex $args 0]
set args [lreplace $args 0 0]
set PopulationType [setGroupParams $args]
...
}

where the set PopulationType... command is the one calling the
function in question.

DrS also wrote:

> Please read the docs and what everyone is trying to point out.

Which is what, exactly? Please don't interpret this as confrontational
- I'm not posing a cheeky sardonic question but rather really don't
know what is being implied. I read the docs thoroughly through before
posting and found nothing in there that gave an answer.

> Until
> then, here is a simple block of code to determine each of the three cases:

> if {[llength $args] == 0} {
> puts "himmm... called with no args from command line?"

Sorry, that didn't work; as I mentioned in the original post, for the
case when there are no optional arguments $args is {} with llength 1.

DrS

unread,
Mar 17, 2012, 9:57:26 PM3/17/12
to
On 3/17/2012 7:50 PM, Alexander Rast wrote:
> Which is what, exactly? Please don't interpret this as confrontational
> - I'm not posing a cheeky sardonic question but rather really don't
> know what is being implied. I read the docs thoroughly through before
> posting and found nothing in there that gave an answer.
>

I guess, specifically, the pages on what "args" is and does. The reason
I emphasized it is that you were using it and your questions were
stemming from that usage. It looked like you could benefit from reading
it. As an argument, it has a special meaning. It is always a list
consisting of all of the remaining arguments after the named ones are
accounted for. To get at the original arguments, you would iterate over
it in a loop or refer to individual items using lindex.

Perhaps it may help to study it in isolation:


% proc setGroupParams {args} { puts "[llength $args] items/[string
length $args] chars: ***[join $args ::]***"}

% setGroupParams
0 items/0 chars: ******

% setGroupParams what
1 items/4 chars: ***what***

% setGroupParams what is
2 items/7 chars: ***what::is***

% setGroupParams what is this
3 items/12 chars: ***what::is::this***



### the specific case you mentioned - see the difference and similarity
% setGroupParams {}
1 items/2 chars: ******

% setGroupParams [list]
1 items/2 chars: ******



>> if {[llength $args] == 0} {
>> puts "himmm... called with no args from command line?"
>
> Sorry, that didn't work; as I mentioned in the original post, for the
> case when there are no optional arguments $args is {} with llength 1.


First, that case is not when "there are no optional arguments", but when
there is a single optional argument and it is an empty list - please see
above. It may seem like a minor difference but it is important.

Also, not sure how it did not work. The number of args is either 0, 1
or more than 1. The first elseif branch accounts for your case
specifically and it even checks for a simple string vs. a dict. You can
perhaps be better off checking for the empty list by using [llength
$which] == 0" instead of using [string length] or you can use a string
equality test for better protection. It depends on your specific
requirements.


Hopefully this helps - I don't have much else to add.


DrS











0 new messages