-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Revert "Raise IndexDefect when deleting element at out of bounds index (#17821)" #18461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
nim-lang#17821)" This reverts commit 92cb765.
It seems to me that the previous behaviour was an undocumented bug, I don't see how this is a "big breaking change". |
Yes, |
Code might rely on this behavior and we have to be more careful with breaking changes. The worst changes are the changes that secretly change behavior. What should have been done here: "Deprecated system.delete, use sequtils.delete instead", for example. (Would also fight system.nim's bloat.) |
Please do not revert this bugfix, it's an undocumented bug with no justification and I haven't heard any complaints about it. The behavior before the bugfix made no sense:
And led to aribtrary inconsistencies, eg: this printed @[1] in VM or C backend, but @[1, 2] in js backend proc main =
var a: seq[int] = @[1, 2]
a.delete(3)
echo a
static: main()
main() (whereas it now raises on all backends after the bugfix)
the worst bugs are silently accepting invalid inputs, which affects the rest of the program, and generating arbitrarily different results according the the backend Every bugfix or feature addition is a potential breaking change for some use case; that's not a valid reason to not fix bugs (or single this one out vs all the other bugfixes that went in 1.5.1), the damage for keep the bug in is much larger. what would be acceptable instead
|
It made a whole lot of sense as it was the natural outcome of the used algorithm, whereas the "fixed" version has more special casing for unknown benefits. Yes, "it's inconsistent with
That doesn't change anything, it changes the behavior for everybody who happens to not to use the JS backend. (Most of our users?)
And how many of these flags do you have to use from transitioning from 1.4 to 1.6? It's quickly becoming impractical for bigger projects. |
since when is bounds checking un-natural? It's inconsistent not just with del or the rest of nim but also with itself, in so many ways: it raised a defect if container len was 0 but not if container len > 0 (and unless index was < 0). And worse than that, attempting to delete index 6 ended up not just failing to raise, but also deleting a different index than the one requested: when true:
var a = @[10,11,12]
a.delete 6
echo a # @[10, 11] # i asked to delete index 6 and it deleted index 2 instead I don't know any language other than nim that does that. This is pure nonesense and that was indeed the consensus in #16544, no-one was arguing in favor of keeping that behavior:
including you: #16544 (comment)
it's not impractical, it's a small finite set that's now following a convention ( |
I don't like the special casing at all, it indicates an "inconsistency" ;-) But let's assume I'm the only fool around that thinks this way, my outlined solution (deprecate system.delete) is the better one: Code can be updated easily and nothing breaks. |
Indicates a possible inconsistency. Unfortunately, indications don't always equal concrete evidence, especially in a programming context (if they did, life would be much more predictable). And at least in this case, the inconsistency is implementation-dependent: proc remove*[T](sequence: var seq[T]; index: int) =
# An alternate `delete` implementation, without a special-case "if" statement.
var currentIndex = index
while true:
let newIndex = currentIndex + 1
shallowCopy(sequence[currentIndex], sequence[newIndex])
currentIndex = newIndex
if currentIndex == len(sequence):
break
setLen(sequence, len(sequence) - 1)
var s = @[1,2,3,4,5]
remove(s, 30) Anyway, as @timotheecour points out, the real inconsistency is conceptual: the old implementation of
Requiring a module to be imported in order to perform a basic operation on a core datatype when all other basic operations are automatically available is also inconsistent, not to mention surprising and inconvenient. |
|
And how much of that history is composed of new users stumbling on behaviors like this and tossing the language aside (either out of frustration or judgment of Nim's quality)? It's implementation behavior like this, along with the jumbled organization and design of the standard library, that hinders adoption. Honestly, Nim should have done (and should still do) what Python 3 did: find all the big mistakes, fix them properly, and break everything, all at one time. The only reason it backfired for Python was because Python was actually used in a large number of large codebases. Nim, alas, doesn't have that problem. |
We seek to release 1.6, not 2.0. And 2.0 would have a trimed down system.nim lacking |
Ok, how about a solution that hopefully everyone is happy with: We revert the fix and deprecate func delete[T](s: var seq[T]; i: Natural) = delete(s, i, i) The deprecation message (or the doc comments) could also mention the old (unexpected) behaviour. Maybe we could also add an overload that has a slice argument, while we're at it (but that's completely optional)... |
That is exactly what I proposed too. I'm sorry for being terrible at communicating. |
Ok, I implemented
So for the user, it is not just |
Well but that is the point. You cannot do this mechanically! You need to review every callsite, consciously! |
Couldn't the user just add |
Which is what would need to be done anyway, without the revert. I'd also like to add that, in keeping the "fixed" behavior, the following apply:
If this still isn't convincing, what about raising/printing a deprecation warning when Alternately, what about deprecating both |
See #18487 which adds an overload with saner semantics for For |
But why not deprecate system.delete, the new better sequtils.delete can be used instead of it too. |
because the single index form is both more common and more intuitive than Again, sequtils.delete was just a bug, not some documented quirk, and its behavior surprised everyone (see #16544); I cannot find a single programming language that had its behavior); fixing it catches bugs (loudly, with an exception), and we should keep the bugfix for the benefit of everyone; no important_pacakges was affected, which is the best proxy we have today.
Another fallacy that's anti-pragmatism; this would block any bug fix if someone creates a package that relies on all the documented bugs, undocumented behaviors, bad design decisions, and calls it a "mission critical release blocker" because it "impacts security". Their use case should not be at the detriment of making the language better for everybody else. Otherwise let's revert dragonbox (silent behavior change! my mission critical app relied on old behavior!) and most PRs since last release.
This makes me cringe every single time I encounter a behavior only found in nim that goes against both common sense and what every other language does. Like the old |
Dunno why you bring this up, I don't remember anybody arguing for quirks just because of this slogan.
Actually, for 1.6 I do intend to make Dragonbox opt-in... It's not anti-pragmatism to spread out changes more evenly across releases to improve the ease of compiler updates. |
As I mentioned, the ambiguity errors can be avoided with |
that's a kludge that we shouldn't impose on new code. This also doesn't work inside include files (which, sadly, abound in compiler code), nor does it work for eg in when (NimMajor, NimMinor, NimPatch) >= (1, 5, 1):
import system except delete
import std/sequtils
var a = @[0,1,2]
a.delete(1)
I don't think making Dragonbox/schubfach opt-in in 1.6 is a good idea but it should be discussed in a dedicated PR/RFC/issue. At the very least it should definitely not be opt-in in devel. |
Has been handled differently. |
This is a too big breaking change to be part of Nim 1.x