<p>Are there good reasons to attempt to keep the number of keywords/reserved tokens in a language to a minimum? Such as by repurposing existing keywords for new syntax instead of adding new ones. Related: <a href="https://langdev.stackexchange.com/q/9/38">Why do some programming languages choose to have a dedicated keyword for elseif instead of using else + if like in C?</a></p>
<p>I suspect that more keywords may make implementing a compiler more complicated, slower as there are more keywords to compare tokens against or similar. But are these concerns legitimate and are there other advantages to having/maintaining a low number of keywords?</p>

<keywords>
Are there good reasons to minimize the number of keywords in a language?
CC BY-SA 4.0
2023-07-05T04:45:26.457Z
Try to remember (or in the first place, learn) *all* the keywords in SQL!
Bergi
<blockquote>
<p>I suspect that more keywords may make implementing a compiler more complicated, slower as there are more keywords to compare tokens against or similar</p>
</blockquote>
<p>This is probably unfounded. There are two parts to it:</p>
<ul>
<li>The lexer has to tell whether a token like <code>while</code> or <code>count</code> is a keyword or an identifier. This can be done by looking up the string in a hashtable, which takes O(1) time independently of the number of keywords.</li>
<li>When the parser sees a keyword token, it has to branch on the kind of keyword; for example, on an <code>if</code> token call <code>parseIfStmt</code>, on a <code>while</code> token call <code>parseWhileStmt</code>, on a <code>throw</code> token call <code>parseThrowStmt</code> and so on. This can be done in a switch statement which can be compiled to something more efficient than just checking the keywords one-by-one. If the lexer has already reduced keywords from strings to enum values, then a dense switch can use a jump table, whereas if they are still strings then a hashtable is a good option. Either way, the time taken to choose the right branch doesn't have to scale with the number of keywords.</li>
</ul>
<p>So having more keywords probably has very little effect on the compiler's performance, in and of itself.</p>
<p>That said, having more <em>concepts</em> in the language might mean the compiler has more work to do after parsing, and if the additional concepts in the language correspond with additional keywords then these two things would be correlated.</p>

CC BY-SA 4.0
2023-07-04T13:03:42.393Z
2023-07-24T09:23:22.090Z
2023-07-24T09:23:22.090Z
kaya3
CC BY-SA 4.0
2023-07-05T12:32:44.637Z
If anything, I would argue that overloading a keyword makes the job of the subsequent passes more complicated, as the exact meaning now depends on the context which must be looked up...
Matthieu M.
CC BY-SA 4.0
2023-07-05T12:38:56.810Z
@MatthieuM. The context is generally already known by the parser, implicitly based on the control-flow. For example when `parseExpr` sees an `if` keyword it can only be an `if` expression, whereas if `parseStmt` sees the same keyword it can only be an `if` statement.
kaya3
CC BY-SA 4.0
2023-07-05T12:49:03.277Z
In this specific case, yes. Ask C++ about using `<>` to delimit template parameter lists though...
Matthieu M.
CC BY-SA 4.0
2023-07-05T12:50:39.137Z
@MatthieuM. Well, if you will choose to have an ambiguous grammar then you're going to have problems when you have to parse it. That's not surprising, but many languages overload keywords without making their grammar ambiguous.
kaya3
CC BY-SA 4.0
2023-07-11T15:18:08.233Z
Even if you do a linear search to lookup keywords, it won't really matter for performance. Most languages have dozens (or a few hundred in large cases) of keywords...
CoffeeTableEspresso
CC BY-SA 4.0
2023-07-11T15:19:09.990Z
Having to figure out what a keyword means by context alone (i.e. when the keyword is overloaded for multiple things) probably complicates the compiler much more than just having an extra keyword.
CoffeeTableEspresso
<h1>Simplicity and Learning Curve</h1>
<p>The less keywords and the more intuitive and related they are, the more simple and, as a such, easy to learn the language is. This is very useful especially in beginner languages.</p>

CC BY-SA 4.0
2023-07-04T09:52:31.543Z
2023-07-04T09:52:31.543Z
Starship
CC BY-SA 4.0
2023-07-04T09:59:51.953Z
Languages with few keywords typically compensate by just giving each keyword many meanings. This just makes the language more complex, not simpler
mousetail 'he-him'
CC BY-SA 4.0
2023-07-04T11:11:21.397Z
True enough I was thinking more about having more complex things be just a few simple keywords. For example, in real languages, in spanish sheets are basically called "bed clothes". Thats more what I mean @mousetail
Starship
CC BY-SA 4.0
2023-07-04T18:12:00.417Z
Actually I agree on simplicity.  Not necessarily for beginners.  FP languages have significantly less keywords.   FP experts can write very concise code with less keywords and can move between FP languages very quickly where as the same does not happen for experts in other languages.
Koenig Lear
CC BY-SA 4.0
2023-07-05T14:29:32.733Z
Also, replacing keywords with symbols reduces keyword count but not complexity: `or` vs `|` vs `||`, `begin` vs `{`, and so on.
Pablo H
<p>You can have Zero reserved keywords if you want, and this can be useful if you want users to define their own language extensions in yours.</p>
<p>Take a simple reserved keyword like the predefined type <code>int</code>: while it is a predefined type, it could belong in a specific package/module, the standard library. You could name it <code>std.int</code> and free the name <code>int</code> for other usages.  User-defined modules could have their own <code>int</code> types.</p>
<p>And this can apply to keywords that are used to structure your source code, for example:</p>
<pre><code>class MyClass {
};

fn f() {
};
</code></pre>
<p>The <code>class</code> or <code>fn</code> keywords are necessary here to know how to parse the following text. They are present at the syntactic level of a parser, but maybe you can avoid that and have a more regular parser and a single keyword <code>declare</code>:</p>
<pre><code>declare(std.class)(MyClass){
}

declare(std.fn)(f, ()) {
}
</code></pre>
<p>Here, <code>std.class</code> and <code>std.fn</code> are identifiers that the compiler knows how to handle under the <code>declare</code> expression. They are not special anymore on a syntactic level, they are identifiers in a namespace for which the language specifies a behavior.</p>
<p>Each declaration has the same syntax, and it can be extended to include things like <code>final</code>, <code>static</code>, <code>mutable</code>, etc.</p>
<p>In the case of iterators like <code>for</code>, <code>while</code> etc. you can also imagine that they are standard <code>std.for</code> etc. identifers that the compiler knows how to interpret, all under the <code>iterate</code> keyword.</p>
<p>So now, we introduced both a <code>declare</code> keyword and an <code>iterate</code> generic keywords, but they are similar and could be merged as a single <code>magic</code> keyword:</p>
<pre><code>magic(std.class)(MyClass) {
}

magic(std.for)(i, 0, 100) {
}
</code></pre>
<p>Your compiler can detect if the argument list of the <code>std.for</code> is malformed, the error detection is moved from the lexer/parser to one step further in the compiler where you check if syntactically well-formed expressions are meaningful.</p>
<p>And if you make all your syntax even more regular, you can avoid completely the <code>magic</code> keyword, which is how you end up with Lisp:</p>
<pre><code>(cl:defclass my-class () ())

(cl:defun foo (a b c) ...)

(cl:loop ...)
</code></pre>
<p>All the predefined symbols that name types, functions, macros, special operators, etc. belong to the &quot;COMMON-LISP&quot;  package (nicknamed <code>cl</code>), you can have your own <code>loop</code>, <code>defun</code> or <code>defclass</code> functions, macros or compiler-macros in your own package.</p>

CC BY-SA 4.0
2023-07-10T08:44:27.280Z
2023-07-11T02:38:31.303Z
2023-07-11T02:38:31.303Z
coredump
<h2>Conciseness</h2>
<p>Keeping the number of keywords to a minimum reduces the chances that the developer will need to pick longer, more descriptive names. This means that the language will also be more concise and readable, in most cases.</p>
<p>As well as making the language more concise, reducing the number of keywords prompts the designer to pick more descriptive words, as keywords must be used sparingly.</p>

CC BY-SA 4.0
2023-07-05T09:47:39.890Z
2023-07-05T09:47:39.890Z
Redz
<h2>If you had many you can add more</h2>
<p>If your language already had many keywords, you can add more.</p>
<p>For example you can define + operator in class:</p>
<pre><code>def __add__(...):
    ...
</code></pre>
<p>This code is clear, but if your language had many keywords, you can add more:</p>
<pre><code>public static int operator +(..., ...) {
    ...
}
</code></pre>

CC BY-SA 4.0
2023-07-04T08:03:09.790Z
2023-07-04T08:03:09.790Z
чистов_n
<h1>Historical Baggage</h1>
<p>If you've got a language that's already been released, then adding a new keyword is almost always a breaking change, since anyone who happened to use that name as a variable or function is now going to get a parse error.</p>
<p>Bjarne Stroustrup has <a href="https://stackoverflow.com/a/2156670/2288659">stated</a> that the bizarre pure virtual function syntax in C++ was designed in that way to avoid having to convince the committee to add a new keyword &quot;<code>pure</code>&quot; to the language. Instead, we got</p>
<pre><code>virtual void example() = 0;
</code></pre>
<p>Some languages get around this by defining &quot;soft keywords&quot;. For instance, the new <a href="https://peps.python.org/pep-0622/" rel="noreferrer"><code>match</code> / <code>case</code></a> statement in Python only treats the keyword specially when appearing as part of the statement, so <code>match = 1</code> is still valid and creates a variable called <code>match</code>. But this massively complicates parsing.</p>

CC BY-SA 4.0
2023-07-04T05:32:01.610Z
2023-07-04T05:32:01.610Z
Silvio Mayolo
CC BY-SA 4.0
2023-07-04T06:25:49.460Z
I would guess that almost all of the reason for aversion to adding new keywords comes down to this. In a **new** language with no backwards compatibility concerns, nobody really cares that much about minimising the number of keywords. Any feature that *might* require a keyword is no easier to memorise by reusing a keyword from another feature (if anything, probably the opposite). Ditto performance/complexity of the language implementation; if you're going to recognise *something* for a new feature, making existing keywords do dual duty is **at least** as much work as recognising a new keyword.
Ben
CC BY-SA 4.0
2023-07-05T12:29:20.650Z
Never heard "soft keyword" before, I usually see "contextual keyword" instead... I can't guarantee it's more official, but at least it's more self-describing.
Matthieu M.
CC BY-SA 4.0
2023-07-05T17:41:23.933Z
PHP mostly gets around this by forcing variables to use the $ symbol, but there can still be conflicts for other things, such as in-built classes conflicting with user-defined classes. (I had to rename a `String` class we had in some of our older PHP websites.)
TRiG
CC BY-SA 4.0
2023-07-06T07:05:22.323Z
@MatthieuM. for Python, "soft keyword" is definitely [the official term](https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords)
muru
CC BY-SA 4.0
2023-07-07T00:40:36.393Z
The pure virtual function syntax isn't *entirely* bizarre.  It can also be viewed as an abstraction leakage, as virtual functions are almost always implemented as pointers.
Mark
CC BY-SA 4.0
2023-07-11T15:12:16.997Z
@TRiG PHP had "bare strings" at one point I believe, which still conflicted with adding new keywords.
CoffeeTableEspresso
CC BY-SA 4.0
2023-07-25T06:59:38.230Z
There are also languages which reserved entire classes of words as keywords, so that new keywords could be allocated from the same class: https://en.wikipedia.org/wiki/Stropping_(syntax)
Criticize SE actions means ban
<p>You can simply use one of the lexerless parsing approaches (e.g., PEG), and then you would not need to worry about keywords. Your special meaning keywords will only be recognised as such when they make sense in a context, and you can still use the same words anywhere else (e.g., <code>if</code> or <code>for</code> as variable names, etc.).</p>

CC BY-SA 4.0
2023-07-04T08:29:55.007Z
2023-07-04T08:29:55.007Z
SK-logic
CC BY-SA 4.0
2023-07-04T14:20:04.607Z
The Fortran approach that allows such clear code as `if if == then then then = else else else = if` (and don't forget that the whitespace isn't required).
Barmar
CC BY-SA 4.0
2023-07-06T15:09:41.357Z
@Barmar haha! Though to be fair, if you really want to write code as crazy as that you can do it in any language. `Main::main main() {Main::main main = main;}` is legal C++, if you first declare `namespace Main {typedef int main;}`
leftaroundabout
<h2>Reducing the number of reserved words</h2>
<p>You normally can't name identifiers the same as keywords. That might be inconvenient. You may want a variable named <code>class</code> representing the HTML class attribute, or a function named <code>catch</code>.</p>
<p>Keywords are typically short verbs which are likely to conflict with functions or short variables.</p>
<p>You can have keywords that are not reserved by allowing them only in some situations. For example in Javascript in <code>for (x of y)</code> of is a keyword yet you can name your identifier <code>of</code> in other contexts.</p>
<p>More keywords should not make the compiler slower, in fact it is probably very slightly faster than aliasing keywords to multiple meanings that most languages use.</p>

CC BY-SA 4.0
2023-07-04T05:23:01.110Z
2023-07-04T05:23:01.110Z
mousetail 'he-him'
CC BY-SA 4.0
2023-07-05T08:34:12.920Z
C++ is another language that has some context-dependent "keywords" - `final`, `override` and more only have their reserved meanings in particular places.
Toby Speight
CC BY-SA 4.0
2023-07-05T12:31:31.203Z
@TobySpeight: Note that all of those were "added" to C++ after the first version, where any new keyword risked breaking backwards compatibility.
Matthieu M.
CC BY-SA 4.0
2023-07-05T13:40:27.570Z
Indeed, that was the mechanism to extend the language without adding new reserved words.
Toby Speight
<p><strong>TL;DR: No.</strong></p>
<p>You raise a number of points, and a number of answers were given. I'll play Devil's Advocate and refute most/all of them.</p>
<h4>Compiler Complexity and Performance</h4>
<blockquote>
<p>I suspect that more keywords may make implementing a compiler more complicated, slower as there are more keywords to compare tokens against or similar</p>
</blockquote>
<p>On the contrary.</p>
<p>Compiler complexity is typically proportional to the number of <em>concepts</em> that the compiler has to deal with, and how much <em>context</em> the compiler needs to reconstruct (type inference, for example).</p>
<p>Using concepts with no keywords, or overloading keywords to mean multiple concepts in different contexts increases the amount of information the compiler must re-calculate (that the developer knew about) and therefore slows down compilation.</p>
<p>From a compiler perspective, one concept = one unique keyword is actually best.</p>
<h4>Backward Compatibility</h4>
<p>Or the inability to introduce a new keyword because it would prevent compiling older programs.</p>
<p>This is certainly an issue in many languages. Work-arounds include:</p>
<ul>
<li>Using non-keywords: C++ uses <code>= 0</code> for pure virtual functions, for example.</li>
<li>Using contextual keywords: C++ uses <code>final</code> and <code>override</code> as keywords <em>only</em> in function declarations.</li>
<li>Overloading existing keywords: C++ uses <code>static</code> in 4 different ways, with drastically different meanings.</li>
</ul>
<p>And demonstrates an embarrassing lack of foresight.</p>
<p>A modern<sup>1</sup> language should plan for <em>evolution</em>, and thereby figure out a solution to be able to introduce keywords without breaking backwards compatibility.</p>
<p>Examples:</p>
<ul>
<li>Prefixing: if keywords start with <code>:</code>, and identifiers cannot, then there's no clash possible.</li>
<li>Versioning: in Rust, each edition introduces new keywords, and users opt-in to the new editions, fixing their code as they do<sup>2</sup>.</li>
</ul>
<p>Thus, in a properly crafted language -- easier in hindsight -- there is no backward compatibility issue in adding keywords.</p>
<p><sup>1</sup>: <em>By which I mean a language created nowadays, with over 50 years of hindsight.</em></p>
<p><sup>2</sup>: <em>This is supported by another feature, which allow importing identifiers from previous versions, called <a href="https://doc.rust-lang.org/rust-by-example/compatibility/raw_identifiers.html" rel="nofollow noreferrer">Raw Identifiers</a>. In essence, it applies the sigil strategy to identifiers (exceptionally), rather than keywords.</em></p>
<h4>Reducing Reserved Words</h4>
<p>There are many kinds of keywords.</p>
<p>The &quot;traditional&quot; keyword is reserved at all scopes, and there may be indeed a desire to keep that number low. There are, however, also <em>contextual</em> keywords, which are only keywords in certain contexts.</p>
<p>As an example, consider the (dubious) <a href="https://github.com/rust-lang/rust/pull/43752/files" rel="nofollow noreferrer">Rust test case</a>:</p>
<blockquote>
<pre><code>fn union() {
    union union&lt;'union&gt; { union: &amp;'union union&lt;'union&gt;, }
}
</code></pre>
</blockquote>
<p><code>union</code> is a keyword, when introducing an item, but otherwise can be used as function name, type name, lifetime name, and field name.</p>
<p>Other approaches to avoid &quot;encroaching&quot; on user variables exist, such as the unpopular option of prefix every keyword with a specific sigil<sup>3</sup>.</p>
<p><sup>3</sup> <em>In this Rust example, single-quote is used as a sigil for lifetimes.</em></p>
<h4>Simplicity and Learning Curve</h4>
<p>The difficulty in learning a programming language is generally about semantics -- concepts -- and libraries -- standard or 3rd-party.</p>
<p>Having a single unique keyword for every concept is actually <em>helpful</em> for learners, as they make it easy to:</p>
<ol>
<li>Recognize concepts they have not learned yet.</li>
<li>Search for them -- by keyword! -- on the web.</li>
</ol>
<p>Keyword-less approaches, or keywords overloading, make a programming language less discoverable as it makes formulating web search queries more difficult, and reduces the pertinence of the search results.</p>
<h4>Conclusion</h4>
<p>One may want to reduce the number of <em>concepts</em> to keep a language simpler, both for users and compiler-writers.</p>
<p>Reducing the number of <em>keywords</em> without reducing the number of <em>concepts</em>, however, is foolish. If anything, it makes the language harder to learn.</p>
<p>On the other hand, one may want to use mostly <em>contextual</em> keywords, to avoid reserving too many desirable user-defined names.</p>
<p>And of course, one should plan for <em>evolution</em> and have a plan to introduce <em>new</em> keywords in the future. External versioning is a potential solution.</p>

CC BY-SA 4.0
2023-07-05T13:08:30.607Z
2023-08-17T13:29:39.123Z
2023-08-17T13:29:39.123Z
Matthieu M.
CC BY-SA 4.0
2023-07-06T19:15:05.840Z
re: "plan for evolution" - I would love for js to have had this from the beginning instead of the mantra "one js".  I understand there are very practical benefits to backward compatibility - and they potentially outweigh a versioned language.  But darn it, removing baggage via convention and tooling (e.g. eslint) makes the language much more difficult to learn than if the baggage was removed from the language via a version update, making it eventually non-existent for newcomers.
aaaaaa
CC BY-SA 4.0
2023-07-07T05:38:50.027Z
@aaaaaa - what would you call javascript's strict mode? It removes several features from the original language that are frequently the cause of mistakes and it's not merely a convention.
Damien_The_Unbeliever
CC BY-SA 4.0
2023-07-07T12:16:58.593Z
you're right damien - they were wrong from the beginning.  It's always been "two js".
aaaaaa
CC BY-SA 4.0
2023-07-11T15:16:27.200Z
I would say contextual keywords are much harder for users of the language. It's _very_ unclear to me what is going on in the `union` example, because I can't tell at a glance what is a keyword and what is not. The big advantage of contextual keywords in my mind is backwards compatibility.
CoffeeTableEspresso
CC BY-SA 4.0
2023-07-11T16:09:26.337Z
@CoffeeTableEspresso: The `union` example is taken to the extreme, and made worse by the fact that Rust has separate types and function namespaces: there is a single appearance of `union` as a keyword, in fact, so most of the confusion is fairly independent from it.
Matthieu M.
# Are there good reasons to minimize the number of keywords in a language?
Posted by: username_0 on 2023-07-04
Are there good reasons to attempt to keep the number of keywords/reserved tokens in a language to a minimum? Such as by repurposing existing keywords for new syntax instead of adding new ones. Related: [Why do some programming languages choose to have a dedicated keyword for elseif instead of using else + if like in C?](https://langdev.stackexchange.com/q/9/38)

I suspect that more keywords may make implementing a compiler more complicated, slower as there are more keywords to compare tokens against or similar. But are these concerns legitimate and are there other advantages to having/maintaining a low number of keywords?
**Tags:** keywords
> **Comments:**
> **username_1**: Try to remember (or in the first place, learn) *all* the keywords in SQL!  
---
## 9 answers
### Answer by username_12 on 2023-07-04. Score: 32 | Accepted answer
Historical Baggage
If you've got a language that's already been released, then adding a new keyword is almost always a breaking change, since anyone who happened to use that name as a variable or function is now going to get a parse error.
Bjarne Stroustrup has stated that the bizarre pure virtual function syntax in C++ was designed in that way to avoid having to convince the committee to add a new keyword "pure" to the language. Instead, we got
virtual void example() = 0;

Some languages get around this by defining "soft keywords". For instance, the new match / case statement in Python only treats the keyword specially when appearing as part of the statement, so match = 1 is still valid and creates a variable called match. But this massively complicates parsing.
> **Comments:**
> **username_13** (2023-07-04): I would guess that almost all of the reason for aversion to adding new keywords comes down to this. In a **new** language with no backwards compatibility concerns, nobody really cares that much about minimising the number of keywords. Any feature that *might* require a keyword is no easier to memorise by reusing a keyword from another feature (if anything, probably the opposite). Ditto performance/complexity of the language implementation; if you're going to recognise *something* for a new feature, making existing keywords do dual duty is **at least** as much work as recognising a new keyword.  
> **username_3** (2023-07-05): Never heard "soft keyword" before, I usually see "contextual keyword" instead... I can't guarantee it's more official, but at least it's more self-describing.  
> **username_14** (2023-07-05): PHP mostly gets around this by forcing variables to use the $ symbol, but there can still be conflicts for other things, such as in-built classes conflicting with user-defined classes. (I had to rename a `String` class we had in some of our older PHP websites.)  
> **username_15** (2023-07-06): @MatthieuM. for Python, "soft keyword" is definitely [the official term](https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords)  
> **username_16** (2023-07-07): The pure virtual function syntax isn't *entirely* bizarre.  It can also be viewed as an abstraction leakage, as virtual functions are almost always implemented as pointers.  
> **username_4** (2023-07-11): @TRiG PHP had "bare strings" at one point I believe, which still conflicted with adding new keywords.  
> **username_17** (2023-07-25): There are also languages which reserved entire classes of words as keywords, so that new keywords could be allocated from the same class: https://en.wikipedia.org/wiki/Stropping_(syntax)  
---
### Answer by username_6 on 2023-07-04. Score: 20
## Reducing the number of reserved words

You normally can't name identifiers the same as keywords. That might be inconvenient. You may want a variable named `class` representing the HTML class attribute, or a function named `catch`.

Keywords are typically short verbs which are likely to conflict with functions or short variables.

You can have keywords that are not reserved by allowing them only in some situations. For example in Javascript in `for (x of y)` of is a keyword yet you can name your identifier `of` in other contexts.

More keywords should not make the compiler slower, in fact it is probably very slightly faster than aliasing keywords to multiple meanings that most languages use.
> **Comments:**
> **username_21** (2023-07-05): C++ is another language that has some context-dependent "keywords" - `final`, `override` and more only have their reserved meanings in particular places.  
> **username_3** (2023-07-05): @TobySpeight: Note that all of those were "added" to C++ after the first version, where any new keyword risked breaking backwards compatibility.  
> **username_21** (2023-07-05): Indeed, that was the mechanism to extend the language without adding new reserved words.  
---
### Answer by username_3 on 2023-07-05. Score: 16
TL;DR: No.
You raise a number of points, and a number of answers were given. I'll play Devil's Advocate and refute most/all of them.
Compiler Complexity and Performance

I suspect that more keywords may make implementing a compiler more complicated, slower as there are more keywords to compare tokens against or similar

On the contrary.
Compiler complexity is typically proportional to the number of concepts that the compiler has to deal with, and how much context the compiler needs to reconstruct (type inference, for example).
Using concepts with no keywords, or overloading keywords to mean multiple concepts in different contexts increases the amount of information the compiler must re-calculate (that the developer knew about) and therefore slows down compilation.
From a compiler perspective, one concept = one unique keyword is actually best.
Backward Compatibility
Or the inability to introduce a new keyword because it would prevent compiling older programs.
This is certainly an issue in many languages. Work-arounds include:

Using non-keywords: C++ uses = 0 for pure virtual functions, for example.
Using contextual keywords: C++ uses final and override as keywords only in function declarations.
Overloading existing keywords: C++ uses static in 4 different ways, with drastically different meanings.

And demonstrates an embarrassing lack of foresight.
A modern1 language should plan for evolution, and thereby figure out a solution to be able to introduce keywords without breaking backwards compatibility.
Examples:

Prefixing: if keywords start with :, and identifiers cannot, then there's no clash possible.
Versioning: in Rust, each edition introduces new keywords, and users opt-in to the new editions, fixing their code as they do2.

Thus, in a properly crafted language -- easier in hindsight -- there is no backward compatibility issue in adding keywords.
1: By which I mean a language created nowadays, with over 50 years of hindsight.
2: This is supported by another feature, which allow importing identifiers from previous versions, called Raw Identifiers. In essence, it applies the sigil strategy to identifiers (exceptionally), rather than keywords.
Reducing Reserved Words
There are many kinds of keywords.
The "traditional" keyword is reserved at all scopes, and there may be indeed a desire to keep that number low. There are, however, also contextual keywords, which are only keywords in certain contexts.
As an example, consider the (dubious) Rust test case:

fn union() {
    union union<'union> { union: &'union union<'union>, }
}


union is a keyword, when introducing an item, but otherwise can be used as function name, type name, lifetime name, and field name.
Other approaches to avoid "encroaching" on user variables exist, such as the unpopular option of prefix every keyword with a specific sigil3.
3 In this Rust example, single-quote is used as a sigil for lifetimes.
Simplicity and Learning Curve
The difficulty in learning a programming language is generally about semantics -- concepts -- and libraries -- standard or 3rd-party.
Having a single unique keyword for every concept is actually helpful for learners, as they make it easy to:

Recognize concepts they have not learned yet.
Search for them -- by keyword! -- on the web.

Keyword-less approaches, or keywords overloading, make a programming language less discoverable as it makes formulating web search queries more difficult, and reduces the pertinence of the search results.
Conclusion
One may want to reduce the number of concepts to keep a language simpler, both for users and compiler-writers.
Reducing the number of keywords without reducing the number of concepts, however, is foolish. If anything, it makes the language harder to learn.
On the other hand, one may want to use mostly contextual keywords, to avoid reserving too many desirable user-defined names.
And of course, one should plan for evolution and have a plan to introduce new keywords in the future. External versioning is a potential solution.
> **Comments:**
> **username_22** (2023-07-06): re: "plan for evolution" - I would love for js to have had this from the beginning instead of the mantra "one js".  I understand there are very practical benefits to backward compatibility - and they potentially outweigh a versioned language.  But darn it, removing baggage via convention and tooling (e.g. eslint) makes the language much more difficult to learn than if the baggage was removed from the language via a version update, making it eventually non-existent for newcomers.  
> **username_23** (2023-07-07): @aaaaaa - what would you call javascript's strict mode? It removes several features from the original language that are frequently the cause of mistakes and it's not merely a convention.  
> **username_22** (2023-07-07): you're right damien - they were wrong from the beginning.  It's always been "two js".  
> **username_4** (2023-07-11): I would say contextual keywords are much harder for users of the language. It's _very_ unclear to me what is going on in the `union` example, because I can't tell at a glance what is a keyword and what is not. The big advantage of contextual keywords in my mind is backwards compatibility.  
> **username_3** (2023-07-11): @CoffeeTableEspresso: The `union` example is taken to the extreme, and made worse by the fact that Rust has separate types and function namespaces: there is a single appearance of `union` as a keyword, in fact, so most of the confusion is fairly independent from it.  
---
### Answer by username_18 on 2023-07-04. Score: 11
You can simply use one of the lexerless parsing approaches (e.g., PEG), and then you would not need to worry about keywords. Your special meaning keywords will only be recognised as such when they make sense in a context, and you can still use the same words anywhere else (e.g., `if` or `for` as variable names, etc.).
> **Comments:**
> **username_19** (2023-07-04): The Fortran approach that allows such clear code as `if if == then then then = else else else = if` (and don't forget that the whitespace isn't required).  
> **username_20** (2023-07-06): @Barmar haha! Though to be fair, if you really want to write code as crazy as that you can do it in any language. `Main::main main() {Main::main main = main;}` is legal C++, if you first declare `namespace Main {typedef int main;}`  
---
### Answer by username_2 on 2023-07-04. Score: 6
> I suspect that more keywords may make implementing a compiler more complicated, slower as there are more keywords to compare tokens against or similar

This is probably unfounded. There are two parts to it:

* The lexer has to tell whether a token like `while` or `count` is a keyword or an identifier. This can be done by looking up the string in a hashtable, which takes O(1) time independently of the number of keywords.
* When the parser sees a keyword token, it has to branch on the kind of keyword; for example, on an `if` token call `parseIfStmt`, on a `while` token call `parseWhileStmt`, on a `throw` token call `parseThrowStmt` and so on. This can be done in a switch statement which can be compiled to something more efficient than just checking the keywords one-by-one. If the lexer has already reduced keywords from strings to enum values, then a dense switch can use a jump table, whereas if they are still strings then a hashtable is a good option. Either way, the time taken to choose the right branch doesn't have to scale with the number of keywords.

So having more keywords probably has very little effect on the compiler's performance, in and of itself.

That said, having more *concepts* in the language might mean the compiler has more work to do after parsing, and if the additional concepts in the language correspond with additional keywords then these two things would be correlated.
> **Comments:**
> **username_3** (2023-07-05): If anything, I would argue that overloading a keyword makes the job of the subsequent passes more complicated, as the exact meaning now depends on the context which must be looked up...  
> **username_2** (2023-07-05): @MatthieuM. The context is generally already known by the parser, implicitly based on the control-flow. For example when `parseExpr` sees an `if` keyword it can only be an `if` expression, whereas if `parseStmt` sees the same keyword it can only be an `if` statement.  
> **username_3** (2023-07-05): In this specific case, yes. Ask C++ about using `<>` to delimit template parameter lists though...  
> **username_2** (2023-07-05): @MatthieuM. Well, if you will choose to have an ambiguous grammar then you're going to have problems when you have to parse it. That's not surprising, but many languages overload keywords without making their grammar ambiguous.  
> **username_4** (2023-07-11): Even if you do a linear search to lookup keywords, it won't really matter for performance. Most languages have dozens (or a few hundred in large cases) of keywords...  
> **username_4** (2023-07-11): Having to figure out what a keyword means by context alone (i.e. when the keyword is overloaded for multiple things) probably complicates the compiler much more than just having an extra keyword.  
---
### Answer by username_5 on 2023-07-04. Score: 6
# Simplicity and Learning Curve

The less keywords and the more intuitive and related they are, the more simple and, as a such, easy to learn the language is. This is very useful especially in beginner languages.
> **Comments:**
> **username_6** (2023-07-04): Languages with few keywords typically compensate by just giving each keyword many meanings. This just makes the language more complex, not simpler  
> **username_5** (2023-07-04): True enough I was thinking more about having more complex things be just a few simple keywords. For example, in real languages, in spanish sheets are basically called "bed clothes". Thats more what I mean @mousetail  
> **username_7** (2023-07-04): Actually I agree on simplicity.  Not necessarily for beginners.  FP languages have significantly less keywords.   FP experts can write very concise code with less keywords and can move between FP languages very quickly where as the same does not happen for experts in other languages.  
> **username_8** (2023-07-05): Also, replacing keywords with symbols reduces keyword count but not complexity: `or` vs `|` vs `||`, `begin` vs `{`, and so on.  
---
### Answer by username_9 on 2023-07-10. Score: 4
You can have Zero reserved keywords if you want, and this can be useful if you want users to define their own language extensions in yours.
Take a simple reserved keyword like the predefined type int: while it is a predefined type, it could belong in a specific package/module, the standard library. You could name it std.int and free the name int for other usages.  User-defined modules could have their own int types.
And this can apply to keywords that are used to structure your source code, for example:
class MyClass {
};

fn f() {
};

The class or fn keywords are necessary here to know how to parse the following text. They are present at the syntactic level of a parser, but maybe you can avoid that and have a more regular parser and a single keyword declare:
declare(std.class)(MyClass){
}

declare(std.fn)(f, ()) {
}

Here, std.class and std.fn are identifiers that the compiler knows how to handle under the declare expression. They are not special anymore on a syntactic level, they are identifiers in a namespace for which the language specifies a behavior.
Each declaration has the same syntax, and it can be extended to include things like final, static, mutable, etc.
In the case of iterators like for, while etc. you can also imagine that they are standard std.for etc. identifers that the compiler knows how to interpret, all under the iterate keyword.
So now, we introduced both a declare keyword and an iterate generic keywords, but they are similar and could be merged as a single magic keyword:
magic(std.class)(MyClass) {
}

magic(std.for)(i, 0, 100) {
}

Your compiler can detect if the argument list of the std.for is malformed, the error detection is moved from the lexer/parser to one step further in the compiler where you check if syntactically well-formed expressions are meaningful.
And if you make all your syntax even more regular, you can avoid completely the magic keyword, which is how you end up with Lisp:
(cl:defclass my-class () ())

(cl:defun foo (a b c) ...)

(cl:loop ...)

All the predefined symbols that name types, functions, macros, special operators, etc. belong to the "COMMON-LISP"  package (nicknamed cl), you can have your own loop, defun or defclass functions, macros or compiler-macros in your own package.
---
### Answer by username_10 on 2023-07-05. Score: 2
## Conciseness

Keeping the number of keywords to a minimum reduces the chances that the developer will need to pick longer, more descriptive names. This means that the language will also be more concise and readable, in most cases.

As well as making the language more concise, reducing the number of keywords prompts the designer to pick more descriptive words, as keywords must be used sparingly.
---
### Answer by username_11 on 2023-07-04. Score: 2
If you had many you can add more
If your language already had many keywords, you can add more.
For example you can define + operator in class:
def __add__(...):
    ...

This code is clear, but if your language had many keywords, you can add more:
public static int operator +(..., ...) {
    ...
}
---
