QB64-Phoenix-Edition / QB64pe

The QB64 Phoenix Edition Repository
https://qb64phoenix.com
Other
119 stars 26 forks source link

Variable-Length Strings #402

Open lavender-programming opened 11 months ago

lavender-programming commented 11 months ago

A String have a fixed length when adding a * suffix to the declaration, but it has to be a number following the *: Dim Text as String * 10 This code isn't valid: A = 10 Dim Text as String * A It would be nice to have the ability to change the length of a string that way. This is similar to issue #359

SteveMcNeill commented 10 months ago

I imagine the reason this isn't allowed is to prevent runtime errors.

A = -3 DIM foo AS STRING * A

In the above, if A was a CONST, the IDE could catch the error and stop it before you compile. As a variable, it wouldn't be able to, which would result in serious runtime glitching, I'd imagine. (Probably a seg fault and program crash, I'd think.)

Personally, I'd also like to see this adopted, but I honestly imagine it'd end up leading to lots of user errors in various situations.

INPUT "How big a string do you need?"; A

User enters "256", but A was defined as a _BYTE and overflows to "0"... What happens on the next line with:

DIM userString AS STRING * A

mkilgore commented 10 months ago

Unlike most languages the Dim statement in QB64 ignores scope (except for SUB/FUNCTION scope) so this isn't quite as simple as it seems. You can see this behavior in code when you do loops, Ex:

For i = 1 To 20
    Dim foo As String
    If i = 1 Then foo = "bar"

    Print foo
Next i

Print foo

You might expect this only prints bar once, but it actually prints it 20 times. The code is equivalent to moving the Dim foo As String outside the loop and that is effective what happens when the code is compiled. We're even allowed to do a Print foo from after the loop and it still refers to the foo declared inside the loop.

So with that being the case, allowing Dim foo As String * i gets weird because:

  1. Does it still only get declared once, or does it get reinitialized every time?
  2. What does it mean to use foo outside of where it is declared (imagine if it's in an If that never gets taken, so the Dim line is never reached)?

That said these thing's aren't impossible to resolve, but they'd be differences in how Dim normally works. Perhaps we should require ReDim to be used for String * i, that's more or less how arrays solve this problem. You can ReDim foo As String * i as much as you want and the size is simply the size of the last ReDim that has happened.