<p>The typical syntax for accessing an array (or list, map and similar data structures) at a specific index is <code>a[i]</code>. I believe C first introduced it as syntax sugar, though I wonder why it has stuck around when an alternative syntax could be a mere infix operator (something like <code>a @ i</code>), yielding back one precious pair of brackets for other use cases, such as generics (angle brackets knowingly being a hassle to parse).</p>
<p>This would intuitively make sense to me, as typically mixfix operators are rarely encountered otherwise in programming languages (exceptions being the function call and ternary operator). Yet I don't know a single language that would permit something along the lines of the following (Java-y):</p>
<pre class="lang-java prettyprint-override"><code>// cities: Map&lt;String, List&lt;Inhabitant&gt;&gt;
cities @ cityName @ inhabitantIdx = new Inhabitant(...);
</code></pre>
<p>The only potential problem I can see is grouping (e.g., for accessing a member: <code>(a @ i).field</code>), though languages like Java already have a similar problem with the binary AND and OR operators (i.e. <code>if ((field &amp; mask) != 0) ...</code>), and people get along with that just fine. What might then be the reason that programming languages throughout the spectrum have consequently stuck to this one single syntax for accessing arrays (AFAIK), when they're showing wild exploration in so many other areas?</p>

<syntax><operators><data-structures>
Why is array access not an infix operator?
CC BY-SA 4.0
2024-06-10T14:45:52.537Z
[Relevant.](https://tio.run/##y9bNS8/7/19DybEyVclaySkVRAanJippKjgoGP3/DwA "K (ngn/k) – Try It Online")
Adám
CC BY-SA 4.0
2024-06-10T15:06:36.843Z
[Civet](https://civet.dev/) also permits e.g. `arr.2` for accessing the third element and `arr.-1` for accessing the last element, so you only need the bracket syntax for dynamically computed indices.
Bbrk24
CC BY-SA 4.0
2024-06-10T16:07:47.550Z
Infix is always a little awkward for non-associative operations like this.  How should `x@y@z` be parsed?  Both `(x@y)@z` (two-dimensional array) and `x@(y@z)` (double indirection) are useful, and it's not intuitive to me which one should be preferred.  They might even both be semantically valid if you have weak typing and associative arrays.  On the other hand, mix-fix forces you to write either `x[y][z]` or `x[y[z]]` and there is no ambiguity.
Nate Eldredge
CC BY-SA 4.0
2024-06-10T16:11:30.547Z
There's also a strong argument for making the syntax mirror that for function calls, since mathematically an array is just a function whose domain is the set of integers `{0, ... n-1}` (assuming zero-based).  And function call syntax is ingrained from math, but I suppose it would likewise be interesting to ask what alternatives have been considered there.
Nate Eldredge
CC BY-SA 4.0
2024-06-10T16:13:58.833Z
On the other hand, the subscript notation from math might argue for `_` as a name for this infix operator.  Though in math, typography helps distinguish between `(a_i)_j` and `a_(i_j)`, as the latter would have the `j` smaller and placed vertically lower.
Nate Eldredge
<p>There are a couple of arguments in favour of the <code>x[y]</code> syntax for arrays, over an infix operator.</p>
<p>One is that we want array access to bind the left operand more tightly than the right operand. For example, in <code>x + y[z]</code> we want the access to have higher precedence than <code>+</code>, but in <code>x[y + z]</code> we want the opposite. An infix operator normally has the same precedence on both sides.</p>
<p>Another is that infix operators need to decide on associativity. Neither of <code>x[y][z]</code> or <code>x[y[z]]</code> is clearly a better choice in general for the meaning of <code>x @ y @ z</code>. Probably multidimensional array access <code>x[y][z]</code> is more commonly used, but left-associativity would mean the operator binds slightly <em>looser</em> on the left, contradicting the above. (That is, if <code>@</code> is left-associative then <code>x @ y</code> binds where <code>y</code> is the right operand, instead of <code>y @ z</code> where <code>y</code> is the left operand.)</p>
<p>Both of these reasons can be summarised by saying that we would often need to use parentheses anyway to disambiguate usages of an infix array access operator; so we might as well make the parentheses part of the syntax, and then we don't need the additional symbol for an infix operator.</p>
<hr />
<p>Another thing to consider is that in some languages, the &quot;index&quot; in an array access is not necessarily an expression. For example, many languages allow access to multidimensional arrays using commas like <code>x[y, z]</code> even when <code>y, z</code> is not a valid expression in those languages. There are also array slices like Python's <code>x[y:z]</code> or <code>x[::-1]</code>, where <code>y:z</code> and <code>::-1</code> are not expressions.</p>
<p>In such languages, array access cannot be parsed the same way as a binary infix operator which expects expressions for both operands. However, languages which want to use an infix operator could get around this by allowing tuples and slices to be expressions.</p>

CC BY-SA 4.0
2024-06-10T16:36:44.927Z
2024-06-11T14:10:06.460Z
2024-06-11T14:10:06.460Z
kaya3
CC BY-SA 4.0
2024-06-10T17:17:27.123Z
The first point I completely hadn't thought of (you'd need to have different precedences for the left and right of the operator...). Though I do personally believe multi-dimensional array access to be more common, so I'd intuitively say to interpret it as `(x @ y) @ z`. Do you believe it'd nonetheless be worth it trying this syntax in the context of a hobby language, at the risk of making everything unreadable?
linux_user36
CC BY-SA 4.0
2024-06-10T17:28:07.153Z
@linux_user36 Multidimensional array access is probably more common overall than indirection in languages which support it, but note that this is contrary to the general rule of binding the left operand more tightly - left-associativity (i.e. where `x @ y @ z` means `(x @ y) @ z`) implies a slightly lower precedence on the left than on the right, since the `y` gets bound on the right instead of on the left.
kaya3
CC BY-SA 4.0
2024-06-10T17:31:00.897Z
It's also worth considering that multidimensional array access might be written like `x[y, z]` instead, since a language might not implement multidimensional arrays as "arrays of arrays" (this is generally less performant due to more pointer indirection) the syntax `x[y][z]` might be semantically incorrect in most usages anyway. As for what you should do in a hobby language, the good thing about hobby languages is that you can try something out and if it's bad, nobody except you will be annoyed, and you can change it later without annoying anyone else too.
kaya3
CC BY-SA 4.0
2024-06-11T13:33:34.763Z
A thousand times this. I have spent the last decade of my life writing C and C++, and I still add unnecessary parentheses to logical conditions. Remembering precedence and associativity is extra mental load and unnecessary chances to make a mistake.
jaskij
CC BY-SA 4.0
2024-06-11T15:24:20.660Z
Whether array of arrays style is less performant depends on on what "array of arrays" actually means in the language.  In C, for example, array of arrays is generally *more* performant than the primary alternative of arrays of pointers (to arrays).  The former is roughly the same as a "true" multi-dimensional array would be.  Java, on the other hand, doesn't even have a standard analogue of the former.  Its arrays of arrays necessarily require traversing an extra reference for each additional dimension.
John Bollinger
CC BY-SA 4.0
2024-06-11T15:43:04.887Z
@JohnBollinger Generally, what you call "true" multidimensional arrays are more performant than "arrays of arrays". In languages where arrays are stored inline in their containing types, and do not have length prefixes, (e.g. C), they are really the same thing ─ because arrays stored consecutively in memory will have the same layout as one big array. (The individual "rows" might have padding, but the same padding would often be used for a "true" multidimensional array.)
kaya3
CC BY-SA 4.0
2024-06-11T15:59:58.633Z
The point is that your wording is ambiguous and potentially misleading.  C multidimensional arrays (e.g. `int a[3][3];`) are absolutely "arrays of arrays" with respect to the semantics and spec-defined terminology of that language, but I'm reasonably confident that that is not the kind of data structure you are calling less performant.
John Bollinger
CC BY-SA 4.0
2024-06-11T16:07:47.660Z
@JohnBollinger Yes, as I said in my previous comment, in C a multidimensional array is the same thing as an array of arrays. My comment before that could be misinterpreted because of the word "[generally](https://en.wiktionary.org/wiki/generally)", which in one sense means "without exception", but that is not the usual sense of that word and is not the sense I intended.
kaya3
CC BY-SA 4.0
2024-06-12T15:19:09.880Z
A multidimensional C-array may be a C-array of C-arrays, but a multidimensional "vector" is not a vector of vectors, tipically. The proposal [P2128R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2128r5.pdf) for adding multidimensional indexing to C++ via [i,j,k] goes into reasons (page 5) why it was considered necessary (ie useful). One example is sparse matrices, where you don't really want to implement a[i] in a[i][j], only a[i,j] directly.
Pablo H
CC BY-SA 4.0
2024-06-12T21:35:25.507Z
@JohnBollinger: Whether arrays of pointers to arrays are more or less efficient than arrays of arrays will depend upon the sizes of the arrays, the target platform, and in some cases the usage patterns.  On many older platforms, memory accesses were much cheaper than multiplies, and even on platforms where that isn't true, using an array of pointers to arrays to unchanging data may be faster than using an array of arrays if many rows of the data are identical and can share the same inner arrays.
supercat
<h1>it is, sometimes</h1>
<p>In Haskell, array access is the binary operator <a href="https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelude.html#v:-33--33-" rel="noreferrer"><code>!!</code></a>.</p>
<p>In APL, one of the ways of doing array access is the dyadic function <a href="https://aplwiki.com/wiki/Index_(function)" rel="noreferrer"><code>⌷</code></a>.</p>

CC BY-SA 4.0
2024-06-10T15:34:38.753Z
2024-06-10T15:34:38.753Z
RubenVerg
CC BY-SA 4.0
2024-06-12T13:28:37.917Z
And in C, `a[b]` is formally equivalent to `*((a) + (b))`, which is infix with respect to to the `+`.  This also means that `a[b]` has a property typical of infix operations, but very unusual for array-access expressions in general: that the operands are interchangeable.  In C, `(a)[b]` is wholly equivalent to `(b)[a]`.
John Bollinger
CC BY-SA 4.0
2024-06-12T21:31:32.577Z
Note that pointer indexing operator `+` does not convert both operands to a common type (and indeed cannot be used to add two pointers to each other), so there's no inherent reason why the operands should be interchangeable.  Further, when the minus token is used as an infix operator with a pointer type as its left operand, it may represent either of two very different operations depending upon the type of the right hand operand.
supercat
CC BY-SA 4.0
2024-06-14T00:07:13.853Z
@JohnBollinger: In turn C inherited this from BCPL, where `E1 + E2` is rvalue/integer addition, while `E1 ! E2` or `E1*[E2]` (depending on version) are lvalue/pointer addition. (NB: `E1[E2, E3, … En]` is a function call.) The manuals say “The representations of Vectors, Lvalues, and integers is such that the following relations are true: / `E1*[E2]` = `rv (E1+E2)` / `lv E1 * [ E2 ]` = `E1 + E2`” and “Vector subscription `(E1!E2` [sic] is implemented using `PLUS` and `RV`”.
Jon Purdy
<p>Another consideration not mentioned so far is that no readily available symbols had the right mnemonic value at the time these subscript syntaxes were devised.</p>
<p><code>@</code> (U+0040 <a href="https://en.wikipedia.org/wiki/At_sign" rel="nofollow noreferrer">at sign</a>) typically meant “each at” or “at a rate of”, that is, a kind of multiplication. You can still find this usage on receipts: 2 apples @ \$1.35 is 2 apples × \$1.35/apple, or \$2.70. The “at a location” sense has become more common <em>because</em> it was repurposed for email addresses, and later Twitter-style username tags.</p>
<p>Likewise, <code>#</code> (U+0023 <a href="https://en.wikipedia.org/wiki/Number_sign" rel="nofollow noreferrer">number sign</a>) was often “pound”, which is still used in contexts like “100# paper” (100 pounds per ream) or the “pound key” on a telephone. If you want “sheep number <em>n</em>”, nowadays <code>sheep # n</code> is a fine choice, but ca. 1960 you would’ve been better off with <code>№</code> (U+2116 <a href="https://en.wikipedia.org/wiki/Numero_sign" rel="nofollow noreferrer">numero sign</a>) as your glyph for a “number sign”. (In fact you still might—<code>#X</code> can be highlighted as a hashtag where <code>№X</code> gets left alone.)</p>
<p>Because of reliance on mnemonic value, it may also be unclear which operand order to pick:</p>
<ul>
<li><code>array @ index</code> — in this array, the value <strong>at</strong> this index</li>
<li><code>name @ host</code> — the user by this name, <strong>at</strong> this host</li>
</ul>
<p>Whereas an analogy with an existing notation, such as a mathematical subscript, reduces the chance for confusion.</p>

CC BY-SA 4.0
2024-06-14T00:45:51.303Z
2024-06-14T00:52:48.970Z
2024-06-14T00:52:48.970Z
Jon Purdy
<p>K has both infix functional indexing and bracket indexing:</p>
<pre><code>a: (1 2; (3 4 5; 6 7))  // nested list
a@0  // 1 2
a[0] // 1 2
a@1  // (3 4 5; 6 7)
a[1] // (3 4 5; 6 7)
</code></pre>
<p>Infix ops have equal precedence but evaluation is right-to-left, so if you're using <code>@</code> on a nested structure often requires parens:</p>
<pre><code>(a@0)@1  // 2, equivalent to a[0][1]
</code></pre>
<p>But that would be tedious, so K also has a <code>.</code> operator for &quot;deep indexing&quot; with a right array argument:</p>
<pre><code>a.1 0  // 3 4 5, equivalent to a[1][0]
</code></pre>

CC BY-SA 4.0
2024-07-27T15:15:05.343Z
2024-07-27T15:15:05.343Z
Alex Shroyer
<p>An single-dimensional array access is syntactically very similar to a single-argument function call; indeed, in some languages the syntax would be identical.  The latter doesn't use any actual operator, but merely the juxtaposition of two expressions, the latter of which must be a parenthesized primary expression, without any explicit operator whatsoever.  I suspect the use of square brackets in C was probably motivated by their use in earlier languages, but functionally a pair of square brackets behaves like a pair of parentheses preceded by an &quot;add and dereference&quot; infix operator.</p>
<p>In FORTRAN, the requirement that an array subscript appear in parentheses was likely motivated by a couple of considerations:</p>
<ol>
<li><p>There needed to be a non-alphanumeric character between the array name and the index, because <code>FOO BAR</code> would have been styntactically equivalent to <code>FOOB AR</code>, <code>FO OBAR</code>, <code>FOOBAR</code>, or any other combination of those letters (in order) and intervening spaces.</p>
</li>
<li><p>The range of available non-alphanumeric characters was extremely limited: <code>.</code>, <code>,</code>, <code>*</code>, <code>/</code>, <code>+</code>, <code>-</code>, <code>$</code>, <code>'</code>, <code>=</code>, <code>(</code>, <code>)</code>.  I'm not sure what dollar sign was used for, and it might have been possible to have rules for the use of <code>'</code> that would allow it to be used as an index in some contexts and a quoted string literal in others, but all of the other symbols were needed for other purposes.</p>
</li>
</ol>
<p>Once FORTRAN established the convention of indexing by juxtaposition of an identifier and a parentheses-enclosed primary expression without using an intervening operator other than the opening delimiter, other languages likewise dispensed with the use of an intervening operator.</p>

CC BY-SA 4.0
2024-06-12T21:27:23.870Z
2024-06-13T11:36:24.607Z
2024-06-13T11:36:24.607Z
supercat
CC BY-SA 4.0
2024-06-12T23:12:05.580Z
"The range of available alphanumeric characters" – is this missing a "non-"?
Paŭlo Ebermann
CC BY-SA 4.0
2024-06-13T00:07:53.027Z
@PaŭloEbermann: Thanks.  Corrected.  I was also just thinking that if one views the parentheses in `1/(x+y)` as indicating what needs to be written lower (below the bar), but that they would be omitted in contexts where one could actually print things lower, then `a(i)` as equivalent to putting `i` in a subscript after `a`, with no other operator, would make sense, though I have no idea if that figures into the design intention of FORTRAN.
supercat
CC BY-SA 4.0
2024-06-13T00:41:41.550Z
I agree with the reasoning behind FORTRAN's choice but there was no `'` in character sets used with the IBM 704: https://bitsavers.org/pdf/ibm/704/24-6661-2_704_Manual_1955.pdf#page=35 . It's probably why LISP 1.5 had no abbreviation for `QUOTE`.
texdr.aft
CC BY-SA 4.0
2024-06-13T03:51:34.923Z
That character set has multiple representations for zero, and a few other characters that aren't used in FORTRAN.  I don't know the history of character sets, but I'm pretty sure FORTRAN needed an apostrophe for string literals.
supercat
CC BY-SA 4.0
2024-06-13T11:35:05.040Z
I'm not convinced by this interpretation. There's no "juxtaposition of two expressions" going on in early languages, there is a specific syntax with an identifier, some brackets, and a list of expressions. The brackets aren't there to group anything, they _are_ the syntax for marking a function call or subscripted variable. Interpreting as an operator is a *post hoc* rationalisation once you start treating "array" as a first-class type, and allowing any expression to have a subscript after it.
IMSoP
CC BY-SA 4.0
2024-06-13T15:39:38.810Z
@IMSoP: The normal mathematical notation for identifying things by index involves printing the index lower than the thing being indexed or the things that follow, *without any intervening operator*.  Punched cards can't show subscripts, but because X₍₂+3) would be meaningless, and multiplication required punctuation, `x(2+3)` was a natural notation for x₍₂₊₃₎.
supercat
CC BY-SA 4.0
2024-06-13T15:59:24.560Z
I guess I don't actually understand what your answer is saying. Are you just agreeing with my existing answer, that FORTRAN didn't consider this an operator, but only a way of formatting subscripts? Or are you implying that the designers _would_ have used an operator if they had a wider choice of characters? What are you imagining that would look like?
IMSoP
<p>The answer to &quot;why&quot; questions is often partly historical - unless there is a good reason to be different, following existing conventions helps limit a new language's &quot;strangeness budget&quot;, and makes it more likely to succeed.</p>
<p>Using brackets for array dimensions goes back long past C, at least as far as the hugely influential FORTRAN and ALGOL, both designed in the late 1950s.</p>
<p>In these early languages, arrays were not considered a separate data type, and so accessing elements was not conceived as an operation with an array on one side, and a number on the other. Instead, both languages defined &quot;subscripted variables&quot;, which could have multiple dimensions; the brackets contained the comma-separated list of &quot;subscripts&quot; into this multi-dimensional structure.</p>
<p>In <a href="http://archive.computerhistory.org/resources/text/Fortran/102649787.05.01.acc.pdf" rel="noreferrer">the 1958 FORTRAN manual</a> describes it thus:</p>
<blockquote>
<p>A variable can be made to represent any member of a 1, 2, or 3-dimensional
Subscripted array of quantities by appending to it 1, 2, or 3 subscripts; the variable is then a subscripted variable. The subscripts are fixed point quantities whose values
determine which member of the array is being referred to.</p>
</blockquote>
<p>And gives examples <code>A(I)</code>, <code>K(3)</code>, and <code>BETA(5* J-2, K +2,L)</code></p>
<p>The <a href="https://dl.acm.org/doi/10.1145/377924.594925" rel="noreferrer">preliminary report of the ALGOL committee</a> from the same year, says:</p>
<blockquote>
<ol start="3">
<li>Subscripted Variables V designate quantities which are components of multidimensional arrays.<br />
Form: V ~ I [ C ]<br />
where C ~ E, E, ~. . . . , E is a list of arithmetic expressions as defined below. Each expression
E occupies one subscript position of the subscripted variable, and is called a subscript. The
complete list of subscripts is enclosed in the subscript brackets [ ].<br />
The array component referred to by a subscripted variable is specified by the actual numerical
value of its subscripts (cf. arithmetic expressions).</li>
</ol>
</blockquote>
<p>In other words, the mathematical notation <span class="math-container">$x_{a,b,c}$</span> translated to FORTRAN <code>X(A,B,C)</code> and ALGOL <code>x[a,b,c]</code></p>
<p>Note also how this fits with <a href="https://langdev.stackexchange.com/q/1372/1769">using parentheses for function application</a> - in both cases, you have an identifier offset from a <em>list</em> of <em>arguments</em> or <em>subscripts</em>.</p>
<p>It is only in later languages that multi-dimensional arrays are treated as &quot;arrays of arrays&quot; (or, in C's case, as a special case of pointer arithmetic), so that the list of subscripts is replaced by a sequence of operators, <code>x[a][b][c]</code>. By then, &quot;array subscripts appear in brackets&quot; was a well-established convention.</p>

CC BY-SA 4.0
2024-06-10T16:58:12.493Z
2024-06-10T17:09:20.307Z
2024-06-10T17:09:20.307Z
IMSoP
CC BY-SA 4.0
2024-06-10T17:04:52.700Z
COBOL also uses `()` syntax. And MacLisp used `(arrayname a b c ...)`. So using function-like syntax has a long tradition.
Barmar
CC BY-SA 4.0
2024-06-11T13:09:08.657Z
Good answer, I think it misses the simplest explanation though that arrays are matrices and [] looks like matrix notation
ScottishTapWater
CC BY-SA 4.0
2024-06-11T13:34:24.620Z
@ScottishTapWater As far as I know, $[1, 2, 3]$ defines the _content_ of a matrix, but if $x$ was a matrix, $x[1, 2, 3]$ would represent some kind of product, not picking an element from a 3-dimensional matrix, as FORTRAN and ALGOL had it. The use of the term "subscript" in those early specs makes clear that the typeset notation $x_{1,2,3}$ is what they had in mind; the parentheses or brackets appear to just be a way to group the list of subscripts (similarly, the TeX markup I've used here is `x_{1,2,3}`, because `x_1,2,3` would only subscript the 1: $x_1,2,3$).
IMSoP
CC BY-SA 4.0
2024-06-11T14:00:13.460Z
@ScottishTapWater If you're aware of any examples of the `x[i]` syntax being used as an alternative to $x_i$ for a subscript of a vector or a matrix in mathematical writing (or other contexts that aren't programming languages) prior to 1958, please let me know - like you, I suspect that this notation existed in mathematics before Algol 58 used it, but I didn't find any examples.
kaya3
CC BY-SA 4.0
2024-06-11T15:06:11.160Z
@IMSoP, you're correct there, I more just meant the square brackets look familiar so it seems a rational choice
ScottishTapWater
# Why is array access not an infix operator?
Posted by: username_0 on 2024-06-10
The typical syntax for accessing an array (or list, map and similar data structures) at a specific index is a[i]. I believe C first introduced it as syntax sugar, though I wonder why it has stuck around when an alternative syntax could be a mere infix operator (something like a @ i), yielding back one precious pair of brackets for other use cases, such as generics (angle brackets knowingly being a hassle to parse).
This would intuitively make sense to me, as typically mixfix operators are rarely encountered otherwise in programming languages (exceptions being the function call and ternary operator). Yet I don't know a single language that would permit something along the lines of the following (Java-y):
// cities: Map>
cities @ cityName @ inhabitantIdx = new Inhabitant(...);

The only potential problem I can see is grouping (e.g., for accessing a member: (a @ i).field), though languages like Java already have a similar problem with the binary AND and OR operators (i.e. if ((field & mask) != 0) ...), and people get along with that just fine. What might then be the reason that programming languages throughout the spectrum have consequently stuck to this one single syntax for accessing arrays (AFAIK), when they're showing wild exploration in so many other areas?
**Tags:** syntax operators data-structures
> **Comments:**
> **username_1**: [Relevant.](https://tio.run/##y9bNS8/7/19DybEyVclaySkVRAanJippKjgoGP3/DwA "K (ngn/k) – Try It Online")  
> **username_2**: [Civet](https://civet.dev/) also permits e.g. `arr.2` for accessing the third element and `arr.-1` for accessing the last element, so you only need the bracket syntax for dynamically computed indices.  
> **username_3**: Infix is always a little awkward for non-associative operations like this.  How should `x@y@z` be parsed?  Both `(x@y)@z` (two-dimensional array) and `x@(y@z)` (double indirection) are useful, and it's not intuitive to me which one should be preferred.  They might even both be semantically valid if you have weak typing and associative arrays.  On the other hand, mix-fix forces you to write either `x[y][z]` or `x[y[z]]` and there is no ambiguity.  
> **username_3**: There's also a strong argument for making the syntax mirror that for function calls, since mathematically an array is just a function whose domain is the set of integers `{0, ... n-1}` (assuming zero-based).  And function call syntax is ingrained from math, but I suppose it would likewise be interesting to ask what alternatives have been considered there.  
> **username_3**: On the other hand, the subscript notation from math might argue for `_` as a name for this infix operator.  Though in math, typography helps distinguish between `(a_i)_j` and `a_(i_j)`, as the latter would have the `j` smaller and placed vertically lower.  
---
## 6 answers
### Answer by username_14 on 2024-06-10. Score: 42 | Accepted answer
The answer to "why" questions is often partly historical - unless there is a good reason to be different, following existing conventions helps limit a new language's "strangeness budget", and makes it more likely to succeed.

Using brackets for array dimensions goes back long past C, at least as far as the hugely influential FORTRAN and ALGOL, both designed in the late 1950s.

In these early languages, arrays were not considered a separate data type, and so accessing elements was not conceived as an operation with an array on one side, and a number on the other. Instead, both languages defined "subscripted variables", which could have multiple dimensions; the brackets contained the comma-separated list of "subscripts" into this multi-dimensional structure.

In [the 1958 FORTRAN manual](http://archive.computerhistory.org/resources/text/Fortran/102649787.05.01.acc.pdf) describes it thus:

> A variable can be made to represent any member of a 1, 2, or 3-dimensional
> Subscripted array of quantities by appending to it 1, 2, or 3 subscripts; the variable is then a subscripted variable. The subscripts are fixed point quantities whose values
> determine which member of the array is being referred to.

And gives examples `A(I)`, `K(3)`, and `BETA(5* J-2, K +2,L)`

The [preliminary report of the ALGOL committee](https://dl.acm.org/doi/10.1145/377924.594925) from the same year, says:

> 3. Subscripted Variables V designate quantities which are components of multidimensional arrays.  
>    Form: V ~ I [ C ]  
>    where C ~ E, E, ~. . . . , E is a list of arithmetic expressions as defined below. Each expression
>    E occupies one subscript position of the subscripted variable, and is called a subscript. The
>    complete list of subscripts is enclosed in the subscript brackets [ ].  
>    The array component referred to by a subscripted variable is specified by the actual numerical
>    value of its subscripts (cf. arithmetic expressions).

In other words, the mathematical notation $x\_{a,b,c}$ translated to FORTRAN `X(A,B,C)` and ALGOL `x[a,b,c]`

Note also how this fits with [using parentheses for function application](https://langdev.stackexchange.com/q/1372/1769) - in both cases, you have an identifier offset from a *list* of *arguments* or *subscripts*.

It is only in later languages that multi-dimensional arrays are treated as "arrays of arrays" (or, in C's case, as a special case of pointer arithmetic), so that the list of subscripts is replaced by a sequence of operators, `x[a][b][c]`. By then, "array subscripts appear in brackets" was a well-established convention.
> **Comments:**
> **username_15** (2024-06-10): COBOL also uses `()` syntax. And MacLisp used `(arrayname a b c ...)`. So using function-like syntax has a long tradition.  
> **username_16** (2024-06-11): Good answer, I think it misses the simplest explanation though that arrays are matrices and [] looks like matrix notation  
> **username_14** (2024-06-11): @ScottishTapWater As far as I know, $[1, 2, 3]$ defines the _content_ of a matrix, but if $x$ was a matrix, $x[1, 2, 3]$ would represent some kind of product, not picking an element from a 3-dimensional matrix, as FORTRAN and ALGOL had it. The use of the term "subscript" in those early specs makes clear that the typeset notation $x_{1,2,3}$ is what they had in mind; the parentheses or brackets appear to just be a way to group the list of subscripts (similarly, the TeX markup I've used here is `x_{1,2,3}`, because `x_1,2,3` would only subscript the 1: $x_1,2,3$).  
> **username_4** (2024-06-11): @ScottishTapWater If you're aware of any examples of the `x[i]` syntax being used as an alternative to $x_i$ for a subscript of a vector or a matrix in mathematical writing (or other contexts that aren't programming languages) prior to 1958, please let me know - like you, I suspect that this notation existed in mathematics before Algol 58 used it, but I didn't find any examples.  
> **username_16** (2024-06-11): @IMSoP, you're correct there, I more just meant the square brackets look familiar so it seems a rational choice  
---
### Answer by username_4 on 2024-06-10. Score: 32
There are a couple of arguments in favour of the `x[y]` syntax for arrays, over an infix operator.

One is that we want array access to bind the left operand more tightly than the right operand. For example, in `x + y[z]` we want the access to have higher precedence than `+`, but in `x[y + z]` we want the opposite. An infix operator normally has the same precedence on both sides.

Another is that infix operators need to decide on associativity. Neither of `x[y][z]` or `x[y[z]]` is clearly a better choice in general for the meaning of `x @ y @ z`. Probably multidimensional array access `x[y][z]` is more commonly used, but left-associativity would mean the operator binds slightly *looser* on the left, contradicting the above. (That is, if `@` is left-associative then `x @ y` binds where `y` is the right operand, instead of `y @ z` where `y` is the left operand.)

Both of these reasons can be summarised by saying that we would often need to use parentheses anyway to disambiguate usages of an infix array access operator; so we might as well make the parentheses part of the syntax, and then we don't need the additional symbol for an infix operator.

---

Another thing to consider is that in some languages, the "index" in an array access is not necessarily an expression. For example, many languages allow access to multidimensional arrays using commas like `x[y, z]` even when `y, z` is not a valid expression in those languages. There are also array slices like Python's `x[y:z]` or `x[::-1]`, where `y:z` and `::-1` are not expressions.

In such languages, array access cannot be parsed the same way as a binary infix operator which expects expressions for both operands. However, languages which want to use an infix operator could get around this by allowing tuples and slices to be expressions.
> **Comments:**
> **username_0** (2024-06-10): The first point I completely hadn't thought of (you'd need to have different precedences for the left and right of the operator...). Though I do personally believe multi-dimensional array access to be more common, so I'd intuitively say to interpret it as `(x @ y) @ z`. Do you believe it'd nonetheless be worth it trying this syntax in the context of a hobby language, at the risk of making everything unreadable?  
> **username_4** (2024-06-10): @linux_user36 Multidimensional array access is probably more common overall than indirection in languages which support it, but note that this is contrary to the general rule of binding the left operand more tightly - left-associativity (i.e. where `x @ y @ z` means `(x @ y) @ z`) implies a slightly lower precedence on the left than on the right, since the `y` gets bound on the right instead of on the left.  
> **username_4** (2024-06-10): It's also worth considering that multidimensional array access might be written like `x[y, z]` instead, since a language might not implement multidimensional arrays as "arrays of arrays" (this is generally less performant due to more pointer indirection) the syntax `x[y][z]` might be semantically incorrect in most usages anyway. As for what you should do in a hobby language, the good thing about hobby languages is that you can try something out and if it's bad, nobody except you will be annoyed, and you can change it later without annoying anyone else too.  
> **username_5** (2024-06-11): A thousand times this. I have spent the last decade of my life writing C and C++, and I still add unnecessary parentheses to logical conditions. Remembering precedence and associativity is extra mental load and unnecessary chances to make a mistake.  
> **username_6** (2024-06-11): Whether array of arrays style is less performant depends on on what "array of arrays" actually means in the language.  In C, for example, array of arrays is generally *more* performant than the primary alternative of arrays of pointers (to arrays).  The former is roughly the same as a "true" multi-dimensional array would be.  Java, on the other hand, doesn't even have a standard analogue of the former.  Its arrays of arrays necessarily require traversing an extra reference for each additional dimension.  
> **username_4** (2024-06-11): @JohnBollinger Generally, what you call "true" multidimensional arrays are more performant than "arrays of arrays". In languages where arrays are stored inline in their containing types, and do not have length prefixes, (e.g. C), they are really the same thing ─ because arrays stored consecutively in memory will have the same layout as one big array. (The individual "rows" might have padding, but the same padding would often be used for a "true" multidimensional array.)  
> **username_6** (2024-06-11): The point is that your wording is ambiguous and potentially misleading.  C multidimensional arrays (e.g. `int a[3][3];`) are absolutely "arrays of arrays" with respect to the semantics and spec-defined terminology of that language, but I'm reasonably confident that that is not the kind of data structure you are calling less performant.  
> **username_4** (2024-06-11): @JohnBollinger Yes, as I said in my previous comment, in C a multidimensional array is the same thing as an array of arrays. My comment before that could be misinterpreted because of the word "[generally](https://en.wiktionary.org/wiki/generally)", which in one sense means "without exception", but that is not the usual sense of that word and is not the sense I intended.  
> **username_7** (2024-06-12): A multidimensional C-array may be a C-array of C-arrays, but a multidimensional "vector" is not a vector of vectors, tipically. The proposal [P2128R5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2128r5.pdf) for adding multidimensional indexing to C++ via [i,j,k] goes into reasons (page 5) why it was considered necessary (ie useful). One example is sparse matrices, where you don't really want to implement a[i] in a[i][j], only a[i,j] directly.  
> **username_8** (2024-06-12): @JohnBollinger: Whether arrays of pointers to arrays are more or less efficient than arrays of arrays will depend upon the sizes of the arrays, the target platform, and in some cases the usage patterns.  On many older platforms, memory accesses were much cheaper than multiplies, and even on platforms where that isn't true, using an array of pointers to arrays to unchanging data may be faster than using an array of arrays if many rows of the data are identical and can share the same inner arrays.  
---
### Answer by username_9 on 2024-06-10. Score: 23
# it is, sometimes

In Haskell, array access is the binary operator [`!!`](https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelude.html#v:-33--33-).

In APL, one of the ways of doing array access is the dyadic function [`⌷`](https://aplwiki.com/wiki/Index_(function)).
> **Comments:**
> **username_6** (2024-06-12): And in C, `a[b]` is formally equivalent to `*((a) + (b))`, which is infix with respect to to the `+`.  This also means that `a[b]` has a property typical of infix operations, but very unusual for array-access expressions in general: that the operands are interchangeable.  In C, `(a)[b]` is wholly equivalent to `(b)[a]`.  
> **username_8** (2024-06-12): Note that pointer indexing operator `+` does not convert both operands to a common type (and indeed cannot be used to add two pointers to each other), so there's no inherent reason why the operands should be interchangeable.  Further, when the minus token is used as an infix operator with a pointer type as its left operand, it may represent either of two very different operations depending upon the type of the right hand operand.  
> **username_10** (2024-06-14): @JohnBollinger: In turn C inherited this from BCPL, where `E1 + E2` is rvalue/integer addition, while `E1 ! E2` or `E1*[E2]` (depending on version) are lvalue/pointer addition. (NB: `E1[E2, E3, … En]` is a function call.) The manuals say “The representations of Vectors, Lvalues, and integers is such that the following relations are true: / `E1*[E2]` = `rv (E1+E2)` / `lv E1 * [ E2 ]` = `E1 + E2`” and “Vector subscription `(E1!E2` [sic] is implemented using `PLUS` and `RV`”.  
---
### Answer by username_8 on 2024-06-12. Score: 3
An single-dimensional array access is syntactically very similar to a single-argument function call; indeed, in some languages the syntax would be identical. The latter doesn't use any actual operator, but merely the juxtaposition of two expressions, the latter of which must be a parenthesized primary expression, without any explicit operator whatsoever. I suspect the use of square brackets in C was probably motivated by their use in earlier languages, but functionally a pair of square brackets behaves like a pair of parentheses preceded by an "add and dereference" infix operator.

In FORTRAN, the requirement that an array subscript appear in parentheses was likely motivated by a couple of considerations:

1. There needed to be a non-alphanumeric character between the array name and the index, because `FOO BAR` would have been styntactically equivalent to `FOOB AR`, `FO OBAR`, `FOOBAR`, or any other combination of those letters (in order) and intervening spaces.
2. The range of available non-alphanumeric characters was extremely limited: `.`, `,`, `*`, `/`, `+`, `-`, `$`, `'`, `=`, `(`, `)`. I'm not sure what dollar sign was used for, and it might have been possible to have rules for the use of `'` that would allow it to be used as an index in some contexts and a quoted string literal in others, but all of the other symbols were needed for other purposes.

Once FORTRAN established the convention of indexing by juxtaposition of an identifier and a parentheses-enclosed primary expression without using an intervening operator other than the opening delimiter, other languages likewise dispensed with the use of an intervening operator.
> **Comments:**
> **username_12** (2024-06-12): "The range of available alphanumeric characters" – is this missing a "non-"?  
> **username_8** (2024-06-13): @PaŭloEbermann: Thanks.  Corrected.  I was also just thinking that if one views the parentheses in `1/(x+y)` as indicating what needs to be written lower (below the bar), but that they would be omitted in contexts where one could actually print things lower, then `a(i)` as equivalent to putting `i` in a subscript after `a`, with no other operator, would make sense, though I have no idea if that figures into the design intention of FORTRAN.  
> **username_13** (2024-06-13): I agree with the reasoning behind FORTRAN's choice but there was no `'` in character sets used with the IBM 704: https://bitsavers.org/pdf/ibm/704/24-6661-2_704_Manual_1955.pdf#page=35 . It's probably why LISP 1.5 had no abbreviation for `QUOTE`.  
> **username_8** (2024-06-13): That character set has multiple representations for zero, and a few other characters that aren't used in FORTRAN.  I don't know the history of character sets, but I'm pretty sure FORTRAN needed an apostrophe for string literals.  
> **username_14** (2024-06-13): I'm not convinced by this interpretation. There's no "juxtaposition of two expressions" going on in early languages, there is a specific syntax with an identifier, some brackets, and a list of expressions. The brackets aren't there to group anything, they _are_ the syntax for marking a function call or subscripted variable. Interpreting as an operator is a *post hoc* rationalisation once you start treating "array" as a first-class type, and allowing any expression to have a subscript after it.  
> **username_8** (2024-06-13): @IMSoP: The normal mathematical notation for identifying things by index involves printing the index lower than the thing being indexed or the things that follow, *without any intervening operator*.  Punched cards can't show subscripts, but because X₍₂+3) would be meaningless, and multiplication required punctuation, `x(2+3)` was a natural notation for x₍₂₊₃₎.  
> **username_14** (2024-06-13): I guess I don't actually understand what your answer is saying. Are you just agreeing with my existing answer, that FORTRAN didn't consider this an operator, but only a way of formatting subscripts? Or are you implying that the designers _would_ have used an operator if they had a wider choice of characters? What are you imagining that would look like?  
---
### Answer by username_10 on 2024-06-14. Score: 1
Another consideration not mentioned so far is that no readily available symbols had the right mnemonic value at the time these subscript syntaxes were devised.

`@` (U+0040 [at sign](https://en.wikipedia.org/wiki/At_sign)) typically meant “each at” or “at a rate of”, that is, a kind of multiplication. You can still find this usage on receipts: 2 apples @ \$1.35 is 2 apples × \$1.35/apple, or \$2.70. The “at a location” sense has become more common *because* it was repurposed for email addresses, and later Twitter-style username tags.

Likewise, `#` (U+0023 [number sign](https://en.wikipedia.org/wiki/Number_sign)) was often “pound”, which is still used in contexts like “100# paper” (100 pounds per ream) or the “pound key” on a telephone. If you want “sheep number *n*”, nowadays `sheep # n` is a fine choice, but ca. 1960 you would’ve been better off with `№` (U+2116 [numero sign](https://en.wikipedia.org/wiki/Numero_sign)) as your glyph for a “number sign”. (In fact you still might—`#X` can be highlighted as a hashtag where `№X` gets left alone.)

Because of reliance on mnemonic value, it may also be unclear which operand order to pick:

* `array @ index` — in this array, the value **at** this index
* `name @ host` — the user by this name, **at** this host

Whereas an analogy with an existing notation, such as a mathematical subscript, reduces the chance for confusion.
---
### Answer by username_11 on 2024-07-27. Score: 0
K has both infix functional indexing and bracket indexing:
a: (1 2; (3 4 5; 6 7))  // nested list
a@0  // 1 2
a[0] // 1 2
a@1  // (3 4 5; 6 7)
a[1] // (3 4 5; 6 7)

Infix ops have equal precedence but evaluation is right-to-left, so if you're using @ on a nested structure often requires parens:
(a@0)@1  // 2, equivalent to a[0][1]

But that would be tedious, so K also has a . operator for "deep indexing" with a right array argument:
a.1 0  // 3 4 5, equivalent to a[1][0]
---
