3
votes

Problem Statement

I'm importing a set of coordinate from an unknown source, which I don't have privilege to look into.

set yMin [lindex [lindex $bbox 0] 1]
puts "yMin: <$yMin>"

It works normally.

yMin: <-6.149999999999999e-02>

The brackets are used to check if there are any spaces or even hidden tabs. However, if yMin is multiplied by any number such as 0.5, it goes wrong.

set Y2 [expr {0.5 * $yMin}]

can't use empty string as operand of "*"
while executing "expr {0.5 * $yMin}"
invoked from within "set Y2 [expr {0.5 * $yMin}]"

Even if only yMin is printed, it still has the empty-operand error.

set Y1 [expr $yMin]
puts "Y1: <$Y1>"

empty expression in expression "" (parsing expression "")
invoked from within "expr $yMin"
invoked from within "set Y1 [expr $yMin]"

But there's an interesting test. It works if curly braces are added!

set Y1 [expr {$yMin}]
puts "Y1: <$Y1>"

Y1: <-0.06149999999999999>


How to reproduce the problem

Thanks to Glenn Jackman (see replies below),

% set bbox {{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}}
{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}
% set yMin [lindex [lindex $bbox 0] 1]
-6.149999999999999e-02
% expr {1 + $yMin}
0.9385

Actually, this seems to be not able to reproduce the problem (this is why I have this post). But it could be a template at least.


Trial and Error

The following code is used to check if it's really empty. It turns out not to be empty.

if {$yMin eq {}} {
    puts "Empty records"
    exit 1 
} else {
    puts "yMin is not empty: <$yMin>
}

yMin is not empty: <-6.149999999999999e-02>

Finally, I tried trim, map and regsub to remove any spaces and tabs but none of them works.

set trim_yMin [string trim $yMin]
puts "trim_yMin: <$trim_yMin>"

set map_yMin [string map {" " ""} $yMin]
puts "map_yMin: <$map_yMin>"

regsub -all {\s} $yMin {} reg_yMin
puts "reg_yMin: <$reg_yMin>"

if {$trim_yMin eq {} || $map_yMin eq {} || $reg_yMin eq {}} {
    puts "Empty records"
    exit 1
} else {
    puts "trim_yMin is not empty: <$reg_yMin>"
    puts "map_yMin is not empty: <$reg_yMin>"
    puts "reg_yMin is not empty: <$reg_yMin>"
}

trim_yMin: <-6.149999999999999e-02>
map_yMin: <-6.149999999999999e-02>
reg_yMin: <-6.149999999999999e-02>
trim_yMin is not empty: <-6.149999999999999e-02>
map_yMin is not empty: <-6.149999999999999e-02>
reg_yMin is not empty: <-6.149999999999999e-02>

Here I only shows the result of regsub. Others' results are the same.

set reg_Y2 [expr {0.5 * $reg_yMin}]
puts "0.5 * reg_yMin: $reg_Y2"

can't use empty string as operand of "*"
while executing "expr {0.5 * $reg_yMin}"
invoked from within "set reg_Y2 [expr {0.5 * $reg_yMin}]"

Could you please help me? I really have no idea about what else I can try. Thanks in advance.


Updates and Replies

To Ergwun:

puts $bbox;
set yMin [lindex [lindex $bbox 0] 1]
puts "yMin: <$yMin>"

{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}
yMin: <-6.149999999999999e-02>

set Y2 [expr {0.5 * $yMin}]
puts $Y2

can't use empty string as operand of "*"
while executing "expr {0.5 * $yMin}"
invoked from within "set Y2 [expr {0.5 * $yMin}]"

To benaja:

puts [tcl::unsupported::representation $yMin]

value is a string with a refcount of 4, object pointer at 0x44ed0910, internal representation 0x450d6120:(nil), string representation "-6.14999999999...."

To Shawn,

puts [binary encode hex $yMin]

2d362e313439393939393939393939393939652d3032


Relevant Posts

  1. Why do Tcler suggest to brace your expressions?
  2. What does it mean -can't use empty string as operand of "*" on tcl-? how to resolve
  3. How to strip whitespace in string in TCL?
  4. Removing space from string after reading it from file using TCL
  5. missing operand at @ in tcl script
  6. Determine type of a variable in Tcl
2
I can't reproduce your error. It's hard to tell what's wrong without knowing what bbox is. Can you show the output you get when you run this: puts $bbox;set yMin [lindex [lindex $bbox 0] 1];puts "yMin: <$yMin>";set Y2 [expr {0.5 * $yMin}];puts $Y2Ergwun
Thank you @Ergwun ! BBox contains two sets of (x,y) coordinates. It stands for coordinates of some bounding box. I've updated and shown the results in the post. Please take a look, thank you!Kao Ethan
Sorry, I can't work out what might cause the [expr] to complain that $yMin is empty when it prints successfully on the previous line. Weird whitespace in bbox can break the extraction of the coordinates and cause other errors (like non-numeric value), but not empty string: replit.com/@ergwun/EntireThinDrawing#main.tclErgwun
::tcl::unsupported::representation can be also useful: stackoverflow.com/questions/62449211/…benaja
Can you include the output of binary encode hex $yMin?Shawn

2 Answers

3
votes

Without having the exact starting point in that bbox variable, we can only really speculate. That value should work:

% set yMin -6.149999999999999e-02
-6.149999999999999e-02
% expr {0.5 * $yMin}
-0.030749999999999996

All the looking at ways that expr may fail won't help if the input data is plain old bogus, and empty strings are never numeric enough to support multiplication. (This isn't Python!) We've got to back up a few steps.

I suspect that the problem is that the bbox variable is sometimes not the shape that you expect, sometimes having a value like this: 1.0 -6.149999999999999e-02 3.0 4.0. In that case, the [lindex [lindex $bbox 0] 1] will produce an empty string (because indexing off the end of a list does that because of the history of the language):

% set bbox {1.0 -6.149999999999999e-02 3.0 4.0}
1.0 -6.149999999999999e-02 3.0 4.0
% puts >[lindex [lindex $bbox 0] 1]<
><

Just using lindex $bbox 1 would work better in this case.

% puts >[lindex $bbox 1]<
>-6.149999999999999e-02<

There's a shorthand for nested lindex:

lindex $boox 0 1

but bounding boxes (at least when they come from Tk) are usually just simple lists of four numeric values, X1 Y1 X2 Y2 so using the nested form on them would be very likely to be both wrong and inefficient.

1
votes

This is not an answer, it's a comment with formatting

% set bbox {{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}}
{-4.599999999999999e-02 -6.149999999999999e-02} {8.000000000000002e-02 6.149999999999999e-02}
% set yMin [lindex [lindex $bbox 0] 1]
-6.149999999999999e-02
% expr {1 + $yMin}
0.9385

Something else is going on in your code that is altering the value of the variable. Have a look at How to create a Minimal, Reproducible Example