`Box` should probably be called `Kite`

I don't think it helps to try and come up with alternative views on what those values represent, depending on whether you need them to be inclusive or not.

The values coming from that range will normally be used as indices or even values (numerical or not), so trying to interpret them as left and right length markers may lead to other confusions when you're using them—it's where off-by-one errors come from.

Anyway, the symmetry was opposing the real symmetry given by the inclusive range, a..=b, where the imaginary length stops making sense. There, if you need to deal with both types, it would be even more confusing not to think of the values as indices.

If the range represents characters to match, like 'a'..'z', it's not even applicable.

In an editor, they're line/column character coordinates, starting at line 1, column 1. They're not distances, nor any representation of fenceposts. If my error is the word at line 1, columns 7:11 ("world" in your example), I'm not going to report "line 1, columns [7, 12)"; it would only confuse the user.

These are quirky error-prone human traditions, doesn't mean they should be incorporated in a programming language. It's a conversion you want to do for UI purposes when interacting with humans, not something to be used in internal data structures and APIs. It's similar to how humans prefer HH:MM:SS am/pm for timestamps, but that doesn't mean it's how one should store timestamps in data structures or APIs.

Personally I am so used to fencepost substrings and 0-based indexing that I would find "error at world, line 0, columns 6..11" notation more pleasant to work with than "line 1, columns 7:11", but I agree the traditional reporting is different so you may want to convert.

Given that my cursor is generally between glyphs, I actually think it'd be much better to think of (and ideally show) those positions as fenceposts.

In a line with only one character, my cursor might be at column 0 (before the letter) or at column 1 (after the letter).


Yes, there's a bunch of historical silliness that places still use despite knowing better. But I still don't want the first line in my file to be line 12, then line 1, then line 2, etc, even if hours in a day are typically listed that way in this country.

Everyone knows that's silly (even if only unconsciously) and it's why even minutes and seconds don't work like that. We could have had a clock count 10:59 -> 10:60 -> 11:01 (or 10:59 -> 11:60 -> 11:01 to be more like hours in a day?), but we don't.

Sometimes the unfamiliar thing really is just better, even if it takes some getting used to.

Except in vi where the cursor is a rectangle covering a whole character. Which leads to confusing things, such as two separate "paste" commands: p is "paste after the current character" and P is "paste before the current character".

Is it even an "alternative" view, at least once you've learned enough that you know there's more than one?

While I have some sympathy for the "friendly" / "human" indexing of the n elements from 1..n, a big part of the reason we largely moved away from that in programming languages is that they're not actually representing an abstracted name of an element (like in math), but an offset to the start of an allocation of contiguous elements. If you're thinking about an allocation as the traditional sequence of boxes for elements, the first box still has to be the same size as all the others, so the "start" of the allocation naturally has to be "before" the first box.

Further, it's quite conventional and natural to refer to slice represented with either a pointer or index pair as being a "start" and "end" pair, in contrast using the "index is pointing at the element" interpretation you would be using "first" and "last" (or the terrible "one past the last" for half open).


The example of text editing is pretty interesting, actually: it turns out nearly all basic edits are actually the same actual operation: replace the selection with some other text, then set the selection to an empty range immediately after the inserted text. That covers typing individual characters inside or at the end, pasting text, and deleting the selection (by inserting empty text). The other basic operation of backspacing with an empty selection (and some similar ones like deleting the following character, and type-over) simply extend the selection by a character first.

This is extremely simple and obvious logic if selection is "between" characters, like it is visually represented. It's far more if you insist on closed ranges, since you're most often dealing with empty selections (an insert cursor is just an empty selection) and at the end of the range, so to append to n characters, you need a range [n..n-1], and replacing a selection from [s..e] with n chars puts the new selection at [s+n..s+n-1], and the length has changed by e-s+n+1. With half-open, all those ±1s disappear.


For completeness, since it seems nobody's mentioned it so far? Closed ranges with a 0 base have the extra technical wrinkle of requiring a single negative index for only the empty range at the start. That's half the range thrown away for a single case.

Only some of them strictly prefer the 24-hour alternative over the am/pm syntax, mind you.

The problem with intuition of this sort - as much as with any lack of it - is just how subjective it is.

Anyone who ever had the pain/pleasure to code their own stack, will have one sort of an intuition in between bits and bytes being placed here or somewhere there on the mystical heap, far away.

Someone who chose to dig deeper and/or implement their own custom heap allocator will have a much better idea, and a completely different intuition regarding, what's going on behind the hood: pages, arenas, mapping, physical/virtual, buddy/slub, Linux's mman.h vs Win32's memoryapi.h; anyone who doesn't get a headache, a panic attack, or a fit of despair at the above will have a drastically different intuition compared to someone who's only ever read the Rust book, once.

If you're coming at it from a background C++, creating a few new neural pathways in your gray matter linking Rust's Box to C++'s std::unique_ptr will be all too easy. Perhaps the fact that the "unique" part has a lot more to do with the uniqueness of the heap allocated object, than with any prospective singularity of the pointer itself, might escape you; yet the intuition part will be all too loud and clear.

Neither of the above would likely care about the name all that much, regardless. Once you know what you're looking at, changing the label doesn't have any effect on you, in the slightest.


More importantly yet, however, is the matter of abstraction. Calling it an HeapAddrUsize<T> might describe (perfectly well) what it is, but not its purpose. You don't move data onto the heap for the sake of the heap pointer alone. You do it because you're going to be referencing that chunk of data over and over and over again; and pushing/popping it from the stack on every single function call would add way too big of an overhead. You just want to "wrap" or "set aside" or "box" the thing, and know that it won't be moving around as much: copying 10's of 100's of 1000's of bytes on every a = b.

Naming it "kite", on the other hand, would inevitably (and rather unnecessarily, strictly IMO in both cases) break down into additional needless cognitive load. Instead of a quite neutral "box", as in "container", as in "place you put something in and forget about it", your mind would now be drawn towards some piece of "strand" flapping in the wind, loosely hanging unto some papier-mâché at the mercy of the wind currents high and above. Not the sort of thing you want to think about. Not while trying to argue with the borrow checker, out of all people compiler mechanics, for sure.


As a strictly educational exercise, though: it could be quite an interesting idea. Replacing the names of the most common built-ins with their ExcessivelyTechnicalYetPerfectlyCorrect<T>'s could certainly teach quite a lot of newcomers what it is that they're actually doing. Some overly verbose types in "extreme" Hungarian notation: all the data types, none of the underlying logic. Alternative spelling for the biggest community pet peeves (do we have a ranking yet?) Array<T> instead of Vec; NoMove<T> for Pin; StateMachine<T> in place of Future. Could be a fun little thing.

The seal has been broken, the curse arises, and the brave warrior Joel Spolskey must be summoned once again to the defense of (a small part of) Microsoft:

Extremely verbose article summarized: original flavor Apps Hungarian was actually a pretty neat hack if you don't have a good way to do newtypes. But nobody actually got the original flavor they got the stupid Systems Hungarian.

Despite the seeming side-track, that article does actually largely address the topic pretty well in general: that what "good" and "bad" code is depends very heavily on your familiarity with it. There's an unstated assumption that the more familiar perspective is correct, but I don't think that's necessarily true: very often it's quite easy to become blind to real flaws just due to getting used to them, or even to complain when they get fixed only because it's now less familiar - exactly the same mistake the bigger had!

I think you missed the point: I said, very clearly, in the context of minimal-interval semantics (Charlie Clarke wrote a recent paper about that). Miminal-interval semantics gives meaning to a text query using an antichain of intervals. There are no antichains containing the empty interval except for the antichain containing the empty interval, which you always represent separately. On the other hand, when you debug, or think, and locate intervals, geometrically it makes much more sense to have extremes included.

BTW, I'm in favor of semi-open everywhere (else). Dijkstra's memo has been on my programming course page for a decade. You're preaching to the choir. :man_shrugging:t2:

Well, MG4J (our research search engine) was written at the end of the '90s, so it's definitely a bit late for suggestions :joy:. Apache Lucene integrated intervals later, and, as you can see by yourself, they use a closed-interval representation, exactly as we did. I don't think that's gonna change after almost 30 years of collective experience in that domain.

sighs I report an error about a group of symbols, not about the visual representation of a cursor... Besides, your cursor is pretty much at the position of a character; it's only shown as a vertical bar to avoid any confusion as to where the typed characters will be inserted. If you have used computers in the past, you'll know that it hasn't always been like that: they used to be block blinking on top of the current character.

Alright. I'm starting to suspect people are really making fun out of me, so I'll stop replying here. I understand that many people are unconditional fans of the language and can't take an objective remark for just what it is. :roll_eyes:

Can you give a short summary of what differentiates this context from other scenarios where you deal with text substrings? What exactly is it that makes you prefer using first and last character indices in this context as opposed to prefering fencepost ranges in all other contexts?

Quite a lovely article, that one was. I'm no longer as much as of a hater of the SH as I once was (writing enough Win32 API calls will do that to you), yet AH is infinitely more telling. Semantic vs type-based distinction is definitely something they've messed up, and in a major way at that.

I'd not thought about that before, but it's a great example that thinking in fenceposts really can make things easier :+1:

While I at least agree there are absolutely some cases where closed ranges make sense (there's a syntax for them, after all) I'm quite confused as to why for text editing specifically you think the cursor points at a character, and not between them?

After all, you can type into an empty text field, or insert a character both at the beginning or end of the text. The implementation is quite natural and identical regardless, but if we're taking conceptually it seems far more natural to me to consider a cursor as positions between characters, but needs a "ghost" one-after-the-last character to work if you're considering it to be pointing at characters.

Further, in practice an insert cursor is just an empty selection (I go into this in an earlier reply here) - if you consider an index to point at the character itself then using closed ranges means that conceptually an insert cursor is a selection from one character to the character behind it, which implies when inserting at the start of the text you also have a conceptual -1 character.

To be clear, this does all work fine in the implementation, at worst you just end up with some extra ±1s with closed ranges (a separate choice to what you think a cursor position is) that aren't great but are hardly the biggest deal. I'm just not sure if you're actually thinking of these "ghost" characters before and after the text when you think of a cursor being on them.

Well, that's how typewriters work. And text-mode screen of many computers. Also my xterm shows a rectangular block covering whole character (and I guess plenty of other terminal emulators do the same). In all these devices the cursor/print head points to a place (area) where character can be. I think this way is more natural way whenever your default editing operation is to overwrite a character.

Sure, nowadays text editing is based mostly on insertions and range replacements, but there is a long history of the other way.

Better to think of those as places where character can be. E.g. if you are editing a [char; 80], there are 80 such places and one-past-text-typed-so-far is nothing special. (Again, not what we are doing now, but it was common in the past.)

Yeah, in those contexts it absolutely makes sense, I agree - though how much that was driven due to the conceptual model of indexes pointing at characters vs terminals simply not being able to show anything between characters vs inserts being somewhat expensive and therefore not the default is probably lost to time? Probably some mix of all of those.

Now you've described it that way I now suspect that's also where the "virtual cursor" thing that always confused me comes from in some weirder editors where you place the cursor anywhere past the end of the line, too (I think Eclipse used to do that by default?)