Tcl Source Code

View Ticket
Login
Ticket UUID: f4a4bd7f107031f273642cbaefc3cbed72315b1
Title: lseq "count" argument also dictates output formatting
Type: Bug Version:
Submitter: pooryorick Created on: 2024-08-29 15:06:16
Subsystem: - New Builtin Commands Assigned To: griffin
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2024-09-10 12:16:07
Resolution: Fixed Closed By: oehhar
    Closed on: 2024-09-10 12:16:07
Description:

The following interactive session illustrates that two logically equivalent sequences do not have the same string representation:

% lseq 3
0 1 2
% lseq 3.0
0.0 1.0 2.0
% string compare [lseq 3] [lseq 3.0]
-1

Overloading the count argument in this way is probably opening a can of worms.

User Comments: oehhar added on 2024-09-10 12:16:07:

Brian said that lseq arguments are expressions on its own. This makes the difference, as it is fed to expr.

Thanks, Harald


oehhar added on 2024-09-09 09:02:27:
I would be in favor to make this compatible.
Entier (bignum) and float is really different internally and "entier float" is hard to fullfill in many cases.

Harald

apnadkarni added on 2024-09-08 16:55:51:

I'll point out this is (I think) the only place in Tcl where floating point representations of whole numbers are accepted as counts (or indices for that matter). Consider

% string repeat x 2.0
expected integer but got "2.0"
% lrepeat 2.0 x
expected integer but got "2.0"
% # BUT
% lseq 2.0
0.0 1.0

So I'm not sure about the basis for Nathan's comment "prohibiting 3.0 as the value of the count argument would be less intuitive and more awkward. Artificial constraints like that have generally been avoided for Tcl.". As seen above, Tcl does in fact have this constraint (artificial or not is a matter of opinion).

As a further aside, also with regards to Nathan's comment, and the expr 3==3.0 example, compare expr 1/3 with expr 1/3.0. So not sure about the basis for the statement "3.0 and 3 have the same meaning" either. At least not in Tcl.

I'd prefer consistency between arguments that are treated as counts (accept floats everywhere or nowhere) but shrug...


griffin added on 2024-09-01 22:54:57:
The numeric type (Integer vs Real) of the Count parameter should not be used to determine the formatting of the results. A Real value can be given as the Count value, but only if the value is a whole number.
These changes have been implemented in [93057ed877].

As for the other suggestions and critiques, I am very reluctant to change the command argument syntax since this command is already in active use. If the above change impacts any existing applications, it's probably for the better.

pooryorick added on 2024-08-31 06:25:45:

Following sebres' line of thinking, an alternative would be to eliminate "count" as an argument entirely. "from", "to", and "by" are probably sufficient.


pooryorick added on 2024-08-31 06:09:16:

When behaviour follows meaning, it is intuitive. 3.0 and 3 have the same meaning:

% expr {3.0 == 3}
1

Therefore, prohibiting 3.0 as the value of the count argument would be less intuitive and more awkward. Artificial constraints like that have generally been avoided for Tcl.


apnadkarni added on 2024-08-31 05:25:49:

My two cents -

I think the phrase "string representation" in the initial report confused the real issue which is about how a single argument is interpreted.

I tend to agree with Nathan and Harald with the interpretation of a single argument as a count, both because it feels more natural to me and matches current behavior. Sergey's interpretation of a single argument as the "end" (if I read his suggested document change right) subjectively feels less natural and more important would be a change in behavior as Harald points out (lseq 3 would return 4 elements instead of current 3).

If interpreted as a count then, the question remains whether floating values should be accepted if they are whole integers. While it might be mildly convenient for lseq 100.0 to generate a floating point sequence, for a graph axis e.g., I agree that implicitly basing the type of the sequence values on the count argument is not desirable or should at least be documented.

All in all, TL;DR my preference is the single argument to be stay interpreted as a count but only accept integers (not 3.0).

/Ashok


pooryorick added on 2024-08-30 19:43:18:

This particular report is only about the "count" argument. At least for that option 3 and 3.0 both mean the same thing. Having "count" always be interpreted as a whole number still leaves plenty of room to influence the behaviour of [lseq] using the other arguments that it accepts.


oehhar added on 2024-08-30 16:52:40:

Dear Sergey,

thank you for your insights.

The explanation, that:

lseq 3.0
is a shortcut for
lseq 0 to 3.0
explains the behaviour. If one of the arguments is a float, the mathematics are float and the result is a float.

So, I tried the equivalence:

% lseq 0 to 3.0
0.0 1.0 2.0 3.0
% lseq 3.0
0.0 1.0 2.0
% lseq 0 to 3.5
0.0 1.0 2.0 3.0

For me, the item "3.0" is missing in the "lseq 3.0" case.

Thank you all for all, Harald


sebres added on 2024-08-30 15:31:54:

It looks completely fine and desirable to me... Also code says it (I know that exactly, because I touched it as I fixed lseq in [f05f5ef759] and it was pretty obvious intentional).

I see it simply as an equivalent of lseq ?0 to? 3.0 (further below).

>two logically equivalent sequences do not have the same string representation

Nothing is here equivalent. Why don't you not wonder that following are different?

% string compare [expr 3] [expr 3.0]
-1
% string compare [expr int(3)] [expr double(3)]
-1
I know in your world EIAS, but... the matter of string representation has nothing to do with lseq and completely to neglect here.

Most interesting is the question what would happen if the object gets shimmer internally to double. And this can be answered as it'd behave correct. Just because an entier would never shimmer to floating type (because its string representation wouldn't concur for both type). With other words because Tcl_GetDoubleFromObj and co would obtain double from integer without to shimmer:

% list [set i [expr 3]] [tcl::unsupported::representation $i]
3 {value is a int ...}
% lseq $i
0 1 2
% list [expr {double($i)}] [tcl::unsupported::representation $i]
3.0 {value is a int ...}
% lseq $i
0 1 2

So shimmering issue is excluded. Nothing else matters.

Moreover lseq natively supports expressions, so lseq 3.0 is quasi equivalent to lseq [expr {3.0}] and this is also possible (and deliberate):

% lseq double(3)
0.0 1.0 2.0

> Specially here is clear that the count is an entier:
> % lseq 3.5
> expected integer but got "3.5"

It is not clear to me. IMHO, it is simply undefined currently, but easy too fix: To be consistent, I'd rather prefer to change the command so this:

% lseq 3.0
0.0 1.0 2.0
% lseq 3.5
0.0 1.0 2.0 3.0
# with other words it'd become short equivalent to:
% lseq 0 to 3.5
0.0 1.0 2.0 3.0
And documentation can be changed from:
- lseq start ?(..|to)? end ??by? step?
+ lseq ?start ?(..|to)?? end ??by? step?
  lseq start count count ??by? step?
- lseq count ?by step?
where start is by default 0 (or 0.0 in case of double end)

It'd be much simpler and more consistent. But it'd be just nice to have.


griffin added on 2024-08-30 12:26:08:

I agree, this is not the intended behavior. I think I see where the hole is in the logic.


oehhar added on 2024-08-30 07:37:59:

Dear Nathan, Jan,

please allow me to give my limitted view:

In the form "lseq 3.0" the argument "3.0" is a count for a sequence.

That a coung beeing a float or an entier gives the final format is IMHO "interesting functionality" hard to explain to an end user.

For me, this feels quite critical, as float and entier work quite differently internally. float have roughly 15 significant digits while entier is unlimited.

Specially here is clear that the count is an entier:

% lseq 3.5
expected integer but got "3.5"

Controlling the type of the return value is possible by the "by" clause. This is logical and ok for me:

% lseq 3 by 1
0 1 2
% lseq 3 by 1.0
0.0 1.0 2.0

So, I would say, that "lseq 3.0" returning floats is a bug, or at least, a feature hard to explain to the end user. Or do I miss the big picture?

Thank you and take care, Harald


pooryorick added on 2024-08-29 18:44:07:

But overloading parameters like that almost always leads to trouble.


pooryorick added on 2024-08-29 18:41:59:

Then it should at least be documented.


jan.nijtmans added on 2024-08-29 15:58:21:

This looks like a feature to me, not a bug.