<p>In languages like C++ and Rust, generics use angle brackets. For example, <code>Vec&lt;f64&gt;</code> for a vec of floats, <code>HashMap&lt;String, i64&gt;</code> for a map from strings to ints, or <code>Option&lt;Box&lt;char&gt;&gt;</code> for a boxed <code>char</code> that can be <code>None</code>. This isn't universal, however. For example, Haskell uses spaces.</p>
<p>What are some different syntaxes for generics? What are their pros and cons?</p>

<syntax><design-choice-comparison><generics>
What are some syntax options for describing generic ("templated") types?
<h1>Square Brackets</h1>
<p>Python's optional typing module uses square brackets for this, such as <code>list[int]</code>. The <a href="https://peps.python.org/pep-0484/#which-brackets-for-generic-type-parameters" rel="noreferrer">PEP that added this syntax</a> has a lengthy analysis of why they chose that syntax, primarily that it didn't clash with any other syntax whereas angle brackets could be confused with less than and greater than signs.</p>

CC BY-SA 4.0
2023-05-16T21:43:22.353Z
2023-05-16T21:43:22.353Z
pppery
CC BY-SA 4.0
2023-06-28T16:43:25.337Z
Go uses square brackets as well, such as in `type Node[T] = struct[T]{...}`. The reasoning for square brackets can be seen in the [proposal paper here](https://go.googlesource.com/proposal/+/HEAD/design/43651-type-parameters.md#why-not-use-the-syntax-like-c_and-java).
bigyihsuan
CC BY-SA 4.0
2023-07-19T07:33:36.707Z
Also used in Nim (which has a Python-inspired syntax, but had generics long before Python).
xigoi
CC BY-SA 4.0
2023-10-14T23:08:38.790Z
"primarily that it didn't clash with any other syntax whereas angle brackets could be confused with less than and greater than signs." more precisely, I would say: square brackets correspond to an already existing operator that could be overloaded - `list[int]` could be parsed with existing rules and transform to `list.__getitem__(int)`, whereas `list<int>` would seem to be missing a right-hand side for the `>`. Of course, `()` would also work with existing syntax, but `list(int)` *already has* meaning (and is a type error, as the `int` type isn't a sequence).
Karl Knechtel
CC BY-SA 4.0
2023-10-15T02:46:56.233Z
Yeah, that's a better way of phrasing my point.
pppery
<h1>First-class types</h1>
<p>In this case, we introduce a type for types: <code>U</code>, then we have <code>List : U -&gt; U</code>, so naturally we would use the function call syntax for generics: <code>List(Int)</code> or like in Haskell/ML: <code>List Int</code>.</p>
<p>In case of the <code>Map&lt;Thing&lt;String, int&gt;, Option&lt;Box&lt;char&gt;&gt;&gt;</code> example in the other answer, we would have</p>
<ul>
<li><code>Map : (U, U) -&gt; U</code></li>
<li><code>Thing : (U, U) -&gt; U</code></li>
<li><code>Option : U -&gt; U</code></li>
<li><code>Box : U -&gt; U</code></li>
<li><code>char : U</code></li>
</ul>
<p>So it would be <code>Map(Thing(String, int), Option(Box(char)))</code>.</p>
<p>Note that it's not necessarily the case that <code>U : U</code>, we can assign no type to <code>U</code> while allowing it to be a type.</p>

CC BY-SA 4.0
2023-05-16T20:25:38.640Z
2024-07-13T20:56:28.213Z
2024-07-13T20:56:28.213Z
ice1000
CC BY-SA 4.0
2023-07-19T07:37:35.610Z
Note that by itself, this approach will force you to explicitly pass types to all functions, for example `map Int [1,2,3] (n -> n+1)`. Some languages (Coq, Lean) solve this by allowing functions to have inferred arguments (not just types).
xigoi
CC BY-SA 4.0
2023-07-24T21:01:57.193Z
@SilvioMayolo Haskell has kinds which are used to express the "types" of types. The basic kind is called `*`, so `Map :: * -> * -> *`, `Thing :: * -> * -> *`, `Option :: * -> *`, `Box :: * -> *`, and `Char :: *`. But `* :: *`, so it's not fatal.
OpenAI was the last straw
CC BY-SA 4.0
2023-05-16T21:49:10.387Z
This is my favourite _syntax_, but doesn't type-in-type cause issues?
wizzwizz4
CC BY-SA 4.0
2023-05-16T22:03:55.513Z
@wizzwizz4 Not immediately. If `U : U` then yes, you're up a creek. But if you just stop and say "`U` is a special snowflake that's not an instance of `U` or anything else" then you're fine. Alternatively, if you want to go all the way, you can have cumulative universes and say `U : U1 : U2 : U3 : U4 : ...` ad infinitum. This is how Agda does it.
Silvio Mayolo
CC BY-SA 4.0
2023-05-16T22:17:11.320Z
@wizzwizz4 what kind of issue are you thinking of? Regarding logical consistency, please see my other post: https://languagedesign.stackexchange.com/a/149/40. If it's other issues, ask me!
ice1000
<h1>Spaces</h1>
<p>This would look like <code>List float</code>, <code>Map String int</code>, or <code>Option Box char</code>.</p>
<p><strong>Pros:</strong></p>
<ul>
<li>Looks nicer (in my opinion), reduces clutter</li>
<li>Faster to type</li>
<li>Angle brackets can be inconvenient due to ambiguity or text editors failing to highlight matched pairs</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Prefix notation can be difficult to read with nested multiple-argument generics (for example, <code>Map&lt;Thing&lt;String, int&gt;, Option&lt;Box&lt;char&gt;&gt;&gt;</code> would be <code>Map Thing String int Option Box char</code>, which takes some work to mentally parse)</li>
<li>Incompatible with variadic generics</li>
</ul>

CC BY-SA 4.0
2023-05-16T19:57:08.913Z
2023-05-16T20:01:56.987Z
2023-05-16T20:01:56.987Z
rydwolf
CC BY-SA 4.0
2023-07-19T07:38:56.367Z
You can allow/require parentheses when nesting: `Map (Thing String Int) (Option (Box Char))`
xigoi
CC BY-SA 4.0
2023-07-19T14:15:34.163Z
@xigoi That's an [answer already](https://langdev.stackexchange.com/a/175/5) (and my personal favorite :p)
rydwolf
CC BY-SA 4.0
2023-07-21T23:29:55.297Z
@Bbrk24 It's not incompatible with variadic generics. For `T Xs...` some variadic type, then `T X Y Z` is of type or kind `Type & (Type... -> Type)`, where you need to ascribe the desired kind to observe the desired behaviour (eg. `type W = T X Y Z` is a type). See [Haskell's polyvariadic functions](https://wiki.haskell.org/Varargs) for a concrete case.
Longinus
CC BY-SA 4.0
2023-07-21T23:33:45.377Z
@Longinus Given variadic W and X, how do you differentiate `W<X<Y>, Z>` from `W<X<Y, Z>>`? You still need a delimiter in those cases, even if it isn’t otherwise required.
Bbrk24
CC BY-SA 4.0
2023-07-21T23:35:39.373Z
@Bbrk24 The same way you differentiate `Map List String` from `Map (List String)`: with parentheses (or some other tokens).
Longinus
CC BY-SA 4.0
2023-07-23T21:16:39.487Z
In ML, that’s `float list`, `char Box Option`, etc.
D. Ben Knoble
CC BY-SA 4.0
2023-05-16T20:01:23.147Z
Another con: incompatible with variadic generics.
Bbrk24
CC BY-SA 4.0
2023-05-16T20:01:42.477Z
@Bbrk24 Oh true, will add
rydwolf
CC BY-SA 4.0
2023-05-16T20:25:39.520Z
RPN is also an option, e.g. `int list` in OCaml.
kaya3
<h1>A pairing that you're willing to give up on using for <em>any</em> other purpose</h1>
<p>Angle brackets have a strong history in this role, but <code>&lt;</code> and <code>&gt;</code> are also common comparison operators. Square brackets are used in a number of languages, but often overlap with an indexing operator. So are parentheses, which often have overlapping uses for function application or precedence. Braces don't come up a lot for this use, but are heavily used elsewhere for scoping and collection literals.</p>
<p>These overlapping uses create parsing difficulties, particularly for partially-complete code that needs syntax highlighting. At what point do you know whether <code>x &lt; y * z</code> is a type expression or not? Is <code>list[string] *z</code> declaring a pointer to a list of strings or multiplying a value? The language implementation itself probably knows, or knows what error to throw, but <strong>other systems need to parse the code as well</strong>, as do people.</p>
<p>Not every language has all of those complications - perhaps all comparisons are done with methods, indexing uses parentheses, application uses juxtaposition, etc. <strong>If there's a &quot;keyboard pair&quot; that isn't in use elsewhere, use that one</strong>, and if there's more than one, pick your favourite.</p>
<h2>What if they're all gone?</h2>
<p>If you do need to use angle brackets, parentheses, square brackets, and braces all for other purposes, doubling up is a good option. <code>list[[string]]</code> is a little more typing, but if <code>[[</code> never appears anywhere else in code then you've immediately got a clearer understanding of what's going on with only a local view. Find a pair that can't ever show up in normal code and use that.</p>
<p>Alternatively, shift one of the <em>other</em> uses to a double if that is less common. If indexing is expected to be rare but types are ubiquitous, maybe it doesn't need to squat on prime real estate.</p>

CC BY-SA 4.0
2023-05-16T22:06:55.637Z
2023-05-16T22:06:55.637Z
Michael Homer
CC BY-SA 4.0
2023-06-26T22:47:33.363Z
Coming back to this way late, but the first prototype of Objective-C used `{| ... |}` for method calls (where modern Objective-C uses `[ ... ]`) because that was illegal in C.
Bbrk24
CC BY-SA 4.0
2023-05-16T22:10:22.020Z
It's usually clear from context what's a type and what's a value, depending on the language's syntax, so I don't think this is a _huge_ concern. Worth considering as a factor tho yeah (I don't think `[[`/`]]` would fix anything tho, still ambiguous with a multidimensional array or array in an index)
rydwolf
CC BY-SA 4.0
2023-05-16T22:12:25.537Z
Depends on the language. C and many of its relatives use braces for arrays, not square brackets, so `[[` was illegal. Modern C uses it for some attributes though, like `[[noreturn]]`, precisely because it was impossible before.
Bbrk24
CC BY-SA 4.0
2023-05-16T22:16:35.427Z
@RadvylfPrograms That is language-dependent, of course, but for partially-complete code & to a machine rather than a person I don't think that's generally true.  For example, `x < y` could be a side-effecting call to a user-defined operator `<` or the start of a variable declaration, and the parsing & highlighting you want on `y`  is likely very different.
Michael Homer
CC BY-SA 4.0
2023-05-16T22:18:39.007Z
If you have multidimensional/nested array literals where `[[` can appear then of course you'd choose a different pairing - the point is that there's bound to be *something* unambiguous available.
Michael Homer
<h1>Specialised syntax</h1>
<p>Like Haskell, you could use specialised syntax for specific kinds of types. For example: <code>(A -&gt; B)</code> for a function that receives an argument of type <code>A</code> and returns a value of type <code>B</code>, <code>[A]</code> for a list of type <code>A</code>, <code>(A, B)</code> for a tuple of an <code>A</code> and a <code>B</code>. And there are other possibilities, like <code>{A}</code> for sets of <code>A</code> and <code>{A: B}</code> for dictionaries with <code>A</code> keys and <code>B</code> values.</p>
<p>Pro:</p>
<ul>
<li><p>These tend to make commonly used types less verbose. Instead of something like <code>Func&lt;List&lt;A&gt;, Func&lt;List&lt;B&gt;, List&lt;Tuple&lt;A, B&gt;&gt;&gt;&gt;</code> you would write <code>[A] -&gt; [B] -&gt; [(A, B)]</code>.</p>
</li>
<li><p>It can visually couple expressions and their types. For example, say <code>[42]</code> has type <code>[Int]</code>, and <code>(True, False)</code> has type <code>(Bool, Bool)</code></p>
</li>
</ul>
<p>Con:</p>
<ul>
<li><p>This requires a more complex grammar for every kind that has a special syntax.</p>
</li>
<li><p>User-defined types need to still have their own syntax, so you will still need one of the other answers here.</p>
</li>
</ul>

CC BY-SA 4.0
2023-05-16T23:02:00.927Z
2023-05-16T23:02:00.927Z
Jasmijn
CC BY-SA 4.0
2023-07-22T04:55:45.983Z
You do need to be careful how you “visually couple expressions and their types” though, since it’s misleading if things look the same but have slightly different meanings. It often confuses beginners to Haskell that the type `[Int]` means a list of any number of integers (meaning `[] Int`) while the pattern `[xs]` matches a list of only one element, confusingly named `xs` (meaning `(:) xs []`).
Jon Purdy
<h1>Lisp-style</h1>
<p>Another option which would work with any choice of brackets is a more lisp-style syntax: <code>(Map String Int)</code>, <code>(Option (Box char))</code>, etc. One advantage of this would be that it's more visually distinct from function application.</p>
<p>Omitting the outermost parens feels like the most optimal mix of systems to me. Here are some examples:</p>
<ul>
<li><code>String</code></li>
<li><code>Option String</code></li>
<li><code>Option (Box String)</code></li>
<li><code>Map String int</code></li>
<li><code>Map String (Option int)</code></li>
<li><code>Rc (Map String int)</code></li>
</ul>
<p>One disadvantage would be that if your language has tuple types, this would be ambiguous without extra clutter.</p>
<hr />
<p>Bonus wackiness: You could apply some sort of macro to a generic type using this syntax. E.g., if <code>DBL</code> were a macro that used a generic param twice, <code>((DBL Map) (Box (Option (Rc (Option char)))))</code> would be a shorthand for <code>(Map (Box (Option (Rc (Option char)))) (Box (Option (Rc (Option char)))))</code></p>

CC BY-SA 4.0
2023-05-16T22:22:12.893Z
2023-05-16T22:22:12.893Z
rydwolf
CC BY-SA 4.0
2023-06-23T08:39:35.563Z
The Lisp-style with outside parenthises omitted is, I believe, the same as what you get if you remove the specialized forms from Haskell's type syntax
Potato44
<h1>Just, parentheses</h1>
<p>This is what D does. For example, the following class in C#:</p>
<pre><code>public class Bar&lt;T&gt;
{
    public T member;
}
</code></pre>
<p>looks like this in D:</p>
<pre><code>class Bar(T)
{
    T member;
}
</code></pre>
<p><a href="https://dlang.org/spec/template.html#aggregate_templates" rel="noreferrer">Source</a></p>
<p>Templates are instantiated with an exclamation point, to avoid confusion with regular function calls:</p>
<pre><code>T square(T)(T t)
{
    return t * t;
}
writefln(&quot;The square of %s is %s&quot;, 3, square!(int)(3));
</code></pre>
<p>This has the obvious con of still being confused with a function call, and it also precludes postfix <code>!</code> from having another meaning (e.g. non-null assertion, as in Swift, C#, and TypeScript).</p>
<p>One thing it has going for it is that it's impossible to confuse with comparisons (see also Rust's turbofish).</p>

CC BY-SA 4.0
2023-05-16T22:00:37.887Z
2023-05-16T22:00:37.887Z
Bbrk24
CC BY-SA 4.0
2024-07-15T04:05:46.700Z
D also allows instantiating templates without parentheses in case where there's only one simple argument used: e.g. `square!int(3)` would work in the above example. source: https://dlang.org/spec/template.html#explicit_tmp_instantiation
CoffeeTableEspresso
<h1>For classes, just parentheses</h1>
<p>D language does this, as already <a href="https://langdev.stackexchange.com/a/169/954">mentioned</a>. Direct example from your question:</p>
<pre class="lang-cs prettyprint-override"><code>// Declaration

class String      // Non-generic
{ }

class Box(T)      // Generic
{ }

enum Option(T)
{
    None,
    Some T,
}

class Vec(T)
{
    public pust(value T) void {}
    public pop() T {}
}

class HashMap(K, V)
{
    public insert( key K , value V ) void {}
}

// Use

var vec = new Vec(f64);
var map = new HashMap(String, i64);
var opt = new Option(Box(char));
</code></pre>
<h1>For methods, keyword and parentheses</h1>
<p>To be possible to generalize methods directly, without annotating a class with types:</p>
<pre class="lang-cs prettyprint-override"><code>static class RangeFactory               // Non-generic, cannot new
{
    // Keyword `type` require a type be passed as first argument,
    // and in this scope, `T` can be used anywhere a type
    // restriction can appear.

    public static ClosedRange( T type , start T , end T ) Range(T)
    {
        // Logic to calculate a positive or negative step, and
        // swap start and end appropriately.

        // Logic to choose different implementation for exact and
        // innexact (floating point) numbers.

        // Logic to choose between RangeStopEquals vs RangeStopExceed.
        // RangeStopEquals is somewhat slower, but wont run forever on unsigned.
        // RangeStopExceed uses the usual .gt. / .lt. tests.
    }
}

use Range.*;

var r1 = ClosedRange(u8, 0, 254); // Faster
var r2 = ClosedRange(u8, 0, 255); // Does not run forever
var r3 = ClosedRange(u8, 0, 256); // Compiler error
</code></pre>

CC BY-SA 4.0
2023-07-22T19:19:00.410Z
2024-07-14T20:07:28.583Z
2024-07-14T20:07:28.583Z
André L F S Bacci
<p>Ada's approach to generic programming consists in having a <code>generic</code> block before the procedure being declared:</p>
<pre><code>generic
  type Element_T is private;  -- Generic formal type parameter
procedure Swap (X, Y : in out Element_T);
</code></pre>
<p>It binds <code>Element_T</code> to a type name locally, making the whole syntax quite uniform.</p>
<p>See <a href="https://en.wikibooks.org/wiki/Ada_Programming/Generics" rel="nofollow noreferrer">Generics</a>.</p>

CC BY-SA 4.0
2023-07-21T18:51:55.820Z
2023-07-21T18:51:55.820Z
coredump
# What are some syntax options for describing generic ("templated") types?
Posted by: username_0 on 2023-05-16
In languages like C++ and Rust, generics use angle brackets. For example, `Vec` for a vec of floats, `HashMap` for a map from strings to ints, or `Option>` for a boxed `char` that can be `None`. This isn't universal, however. For example, Haskell uses spaces.

What are some different syntaxes for generics? What are their pros and cons?
**Tags:** syntax design-choice-comparison generics
---
## 9 answers
### Answer by username_1 on 2023-05-16. Score: 13
# Square Brackets

Python's optional typing module uses square brackets for this, such as `list[int]`. The [PEP that added this syntax](https://peps.python.org/pep-0484/#which-brackets-for-generic-type-parameters) has a lengthy analysis of why they chose that syntax, primarily that it didn't clash with any other syntax whereas angle brackets could be confused with less than and greater than signs.
> **Comments:**
> **username_2** (2023-06-28): Go uses square brackets as well, such as in `type Node[T] = struct[T]{...}`. The reasoning for square brackets can be seen in the [proposal paper here](https://go.googlesource.com/proposal/+/HEAD/design/43651-type-parameters.md#why-not-use-the-syntax-like-c_and-java).  
> **username_3** (2023-07-19): Also used in Nim (which has a Python-inspired syntax, but had generics long before Python).  
> **username_4** (2023-10-14): "primarily that it didn't clash with any other syntax whereas angle brackets could be confused with less than and greater than signs." more precisely, I would say: square brackets correspond to an already existing operator that could be overloaded - `list[int]` could be parsed with existing rules and transform to `list.__getitem__(int)`, whereas `list<int>` would seem to be missing a right-hand side for the `>`. Of course, `()` would also work with existing syntax, but `list(int)` *already has* meaning (and is a type error, as the `int` type isn't a sequence).  
> **username_1** (2023-10-15): Yeah, that's a better way of phrasing my point.  
---
### Answer by username_5 on 2023-05-16. Score: 13
# First-class types

In this case, we introduce a type for types: `U`, then we have `List : U -> U`, so naturally we would use the function call syntax for generics: `List(Int)` or like in Haskell/ML: `List Int`.

In case of the `Map, Option>>` example in the other answer, we would have

* `Map : (U, U) -> U`
* `Thing : (U, U) -> U`
* `Option : U -> U`
* `Box : U -> U`
* `char : U`

So it would be `Map(Thing(String, int), Option(Box(char)))`.

Note that it's not necessarily the case that `U : U`, we can assign no type to `U` while allowing it to be a type.
> **Comments:**
> **username_7** (2023-05-16): This is my favourite _syntax_, but doesn't type-in-type cause issues?  
> **username_8** (2023-05-16): @wizzwizz4 Not immediately. If `U : U` then yes, you're up a creek. But if you just stop and say "`U` is a special snowflake that's not an instance of `U` or anything else" then you're fine. Alternatively, if you want to go all the way, you can have cumulative universes and say `U : U1 : U2 : U3 : U4 : ...` ad infinitum. This is how Agda does it.  
> **username_5** (2023-05-16): @wizzwizz4 what kind of issue are you thinking of? Regarding logical consistency, please see my other post: https://languagedesign.stackexchange.com/a/149/40. If it's other issues, ask me!  
> **username_3** (2023-07-19): Note that by itself, this approach will force you to explicitly pass types to all functions, for example `map Int [1,2,3] (n -> n+1)`. Some languages (Coq, Lean) solve this by allowing functions to have inferred arguments (not just types).  
> **username_6** (2023-07-24): @SilvioMayolo Haskell has kinds which are used to express the "types" of types. The basic kind is called `*`, so `Map :: * -> * -> *`, `Thing :: * -> * -> *`, `Option :: * -> *`, `Box :: * -> *`, and `Char :: *`. But `* :: *`, so it's not fatal.  
---
### Answer by username_10 on 2023-05-16. Score: 8
Just, parentheses
This is what D does. For example, the following class in C#:
public class Bar
{
    public T member;
}

looks like this in D:
class Bar(T)
{
    T member;
}

Source
Templates are instantiated with an exclamation point, to avoid confusion with regular function calls:
T square(T)(T t)
{
    return t * t;
}
writefln("The square of %s is %s", 3, square!(int)(3));

This has the obvious con of still being confused with a function call, and it also precludes postfix ! from having another meaning (e.g. non-null assertion, as in Swift, C#, and TypeScript).
One thing it has going for it is that it's impossible to confuse with comparisons (see also Rust's turbofish).
> **Comments:**
> **username_17** (2024-07-15): D also allows instantiating templates without parentheses in case where there's only one simple argument used: e.g. `square!int(3)` would work in the above example. source: https://dlang.org/spec/template.html#explicit_tmp_instantiation  
---
### Answer by username_0 on 2023-05-16. Score: 7
# Spaces

This would look like `List float`, `Map String int`, or `Option Box char`.

**Pros:**

* Looks nicer (in my opinion), reduces clutter
* Faster to type
* Angle brackets can be inconvenient due to ambiguity or text editors failing to highlight matched pairs

**Cons:**

* Prefix notation can be difficult to read with nested multiple-argument generics (for example, `Map, Option>>` would be `Map Thing String int Option Box char`, which takes some work to mentally parse)
* Incompatible with variadic generics
> **Comments:**
> **username_10** (2023-05-16): Another con: incompatible with variadic generics.  
> **username_0** (2023-05-16): @Bbrk24 Oh true, will add  
> **username_12** (2023-05-16): RPN is also an option, e.g. `int list` in OCaml.  
> **username_3** (2023-07-19): You can allow/require parentheses when nesting: `Map (Thing String Int) (Option (Box Char))`  
> **username_0** (2023-07-19): @xigoi That's an [answer already](https://langdev.stackexchange.com/a/175/5) (and my personal favorite :p)  
> **username_9** (2023-07-21): @Bbrk24 It's not incompatible with variadic generics. For `T Xs...` some variadic type, then `T X Y Z` is of type or kind `Type & (Type... -> Type)`, where you need to ascribe the desired kind to observe the desired behaviour (eg. `type W = T X Y Z` is a type). See [Haskell's polyvariadic functions](https://wiki.haskell.org/Varargs) for a concrete case.  
> **username_10** (2023-07-21): @Longinus Given variadic W and X, how do you differentiate `W<X<Y>, Z>` from `W<X<Y, Z>>`? You still need a delimiter in those cases, even if it isn’t otherwise required.  
> **username_9** (2023-07-21): @Bbrk24 The same way you differentiate `Map List String` from `Map (List String)`: with parentheses (or some other tokens).  
> **username_11** (2023-07-23): In ML, that’s `float list`, `char Box Option`, etc.  
---
### Answer by username_13 on 2023-05-16. Score: 7
# A pairing that you're willing to give up on using for *any* other purpose

Angle brackets have a strong history in this role, but `<` and `>` are also common comparison operators. Square brackets are used in a number of languages, but often overlap with an indexing operator. So are parentheses, which often have overlapping uses for function application or precedence. Braces don't come up a lot for this use, but are heavily used elsewhere for scoping and collection literals.

These overlapping uses create parsing difficulties, particularly for partially-complete code that needs syntax highlighting. At what point do you know whether `x < y * z` is a type expression or not? Is `list[string] *z` declaring a pointer to a list of strings or multiplying a value? The language implementation itself probably knows, or knows what error to throw, but **other systems need to parse the code as well**, as do people.

Not every language has all of those complications - perhaps all comparisons are done with methods, indexing uses parentheses, application uses juxtaposition, etc. **If there's a "keyboard pair" that isn't in use elsewhere, use that one**, and if there's more than one, pick your favourite.

## What if they're all gone?

If you do need to use angle brackets, parentheses, square brackets, and braces all for other purposes, doubling up is a good option. `list[[string]]` is a little more typing, but if `[[` never appears anywhere else in code then you've immediately got a clearer understanding of what's going on with only a local view. Find a pair that can't ever show up in normal code and use that.

Alternatively, shift one of the *other* uses to a double if that is less common. If indexing is expected to be rare but types are ubiquitous, maybe it doesn't need to squat on prime real estate.
> **Comments:**
> **username_0** (2023-05-16): It's usually clear from context what's a type and what's a value, depending on the language's syntax, so I don't think this is a _huge_ concern. Worth considering as a factor tho yeah (I don't think `[[`/`]]` would fix anything tho, still ambiguous with a multidimensional array or array in an index)  
> **username_10** (2023-05-16): Depends on the language. C and many of its relatives use braces for arrays, not square brackets, so `[[` was illegal. Modern C uses it for some attributes though, like `[[noreturn]]`, precisely because it was impossible before.  
> **username_13** (2023-05-16): @RadvylfPrograms That is language-dependent, of course, but for partially-complete code & to a machine rather than a person I don't think that's generally true.  For example, `x < y` could be a side-effecting call to a user-defined operator `<` or the start of a variable declaration, and the parsing & highlighting you want on `y`  is likely very different.  
> **username_13** (2023-05-16): If you have multidimensional/nested array literals where `[[` can appear then of course you'd choose a different pairing - the point is that there's bound to be *something* unambiguous available.  
> **username_10** (2023-06-26): Coming back to this way late, but the first prototype of Objective-C used `{| ... |}` for method calls (where modern Objective-C uses `[ ... ]`) because that was illegal in C.  
---
### Answer by username_14 on 2023-05-16. Score: 7
# Specialised syntax

Like Haskell, you could use specialised syntax for specific kinds of types. For example: `(A -> B)` for a function that receives an argument of type `A` and returns a value of type `B`, `[A]` for a list of type `A`, `(A, B)` for a tuple of an `A` and a `B`. And there are other possibilities, like `{A}` for sets of `A` and `{A: B}` for dictionaries with `A` keys and `B` values.

Pro:

* These tend to make commonly used types less verbose. Instead of something like `Func, Func, List>>>` you would write `[A] -> [B] -> [(A, B)]`.
* It can visually couple expressions and their types. For example, say `[42]` has type `[Int]`, and `(True, False)` has type `(Bool, Bool)`

Con:

* This requires a more complex grammar for every kind that has a special syntax.
* User-defined types need to still have their own syntax, so you will still need one of the other answers here.
> **Comments:**
> **username_15** (2023-07-22): You do need to be careful how you “visually couple expressions and their types” though, since it’s misleading if things look the same but have slightly different meanings. It often confuses beginners to Haskell that the type `[Int]` means a list of any number of integers (meaning `[] Int`) while the pattern `[xs]` matches a list of only one element, confusingly named `xs` (meaning `(:) xs []`).  
---
### Answer by username_0 on 2023-05-16. Score: 4
# Lisp-style

Another option which would work with any choice of brackets is a more lisp-style syntax: `(Map String Int)`, `(Option (Box char))`, etc. One advantage of this would be that it's more visually distinct from function application.

Omitting the outermost parens feels like the most optimal mix of systems to me. Here are some examples:

* `String`
* `Option String`
* `Option (Box String)`
* `Map String int`
* `Map String (Option int)`
* `Rc (Map String int)`

One disadvantage would be that if your language has tuple types, this would be ambiguous without extra clutter.

---

Bonus wackiness: You could apply some sort of macro to a generic type using this syntax. E.g., if `DBL` were a macro that used a generic param twice, `((DBL Map) (Box (Option (Rc (Option char)))))` would be a shorthand for `(Map (Box (Option (Rc (Option char)))) (Box (Option (Rc (Option char)))))`
> **Comments:**
> **username_16** (2023-06-23): The Lisp-style with outside parenthises omitted is, I believe, the same as what you get if you remove the specialized forms from Haskell's type syntax  
---
### Answer by username_18 on 2023-07-22. Score: 3
For classes, just parentheses
D language does this, as already mentioned. Direct example from your question:
// Declaration

class String      // Non-generic
{ }

class Box(T)      // Generic
{ }

enum Option(T)
{
    None,
    Some T,
}

class Vec(T)
{
    public pust(value T) void {}
    public pop() T {}
}

class HashMap(K, V)
{
    public insert( key K , value V ) void {}
}

// Use

var vec = new Vec(f64);
var map = new HashMap(String, i64);
var opt = new Option(Box(char));

For methods, keyword and parentheses
To be possible to generalize methods directly, without annotating a class with types:
static class RangeFactory               // Non-generic, cannot new
{
    // Keyword `type` require a type be passed as first argument,
    // and in this scope, `T` can be used anywhere a type
    // restriction can appear.

    public static ClosedRange( T type , start T , end T ) Range(T)
    {
        // Logic to calculate a positive or negative step, and
        // swap start and end appropriately.

        // Logic to choose different implementation for exact and
        // innexact (floating point) numbers.

        // Logic to choose between RangeStopEquals vs RangeStopExceed.
        // RangeStopEquals is somewhat slower, but wont run forever on unsigned.
        // RangeStopExceed uses the usual .gt. / .lt. tests.
    }
}

use Range.*;

var r1 = ClosedRange(u8, 0, 254); // Faster
var r2 = ClosedRange(u8, 0, 255); // Does not run forever
var r3 = ClosedRange(u8, 0, 256); // Compiler error
---
### Answer by username_19 on 2023-07-21. Score: 3
Ada's approach to generic programming consists in having a generic block before the procedure being declared:
generic
  type Element_T is private;  -- Generic formal type parameter
procedure Swap (X, Y : in out Element_T);

It binds Element_T to a type name locally, making the whole syntax quite uniform.
See Generics.
---
