1

When I was a beginner it took a while to learn the language syntax and the idea that languages couldn't improve after they were invented.

But now we're seeing new language features added every year with ES5, ES6 the so on.

If I don't write software for a few weeks or months when I come back to it I have often found for the first few days found myself writing if statements with the literal words and and or.

if (isSinglePost and isLoggedIn) {
   // do something
}

AND I've seen other languages use literal and and literal or in their language syntax.

I'd like to have the option to use and and or or || and &&. I'm not saying it's the best practice but it would be nice to have that option for readability and writability.

So now I'm wondering is there any reason languages didn't use and and or in their language syntax in the first place when they were invented? And would there be any negatives to adding it now?

ES2019candidate

  • 5
    But some languages do. VisualBasic, several flavors of SQL, IBM's EGL, etc. all use "if condition and condition" Also, some languages support both,and mixing them will cause issues with operator precedence and such. – ivanivan Mar 4 at 19:38
  • Larry Wall was once asked about his use of punctuation as names for Perl's built-in variables (e.g., $_ as the topic variable) and replied that "Perl provides word-oriented aliases to all of these variables, if you choose to write COBOL in Perl. Oddly, most folks don't." – Blrfl Mar 4 at 19:58
  • 5
    Because the operations aren't called "and" and "or". The boolean operators are conjunction and disjunction, and only colloquially called "and" and "or". In math ∧ and ∨ are used as symbols to denote those mathematical operations. – Polygnome Mar 4 at 20:17
  • @Polygnome the reality is that && and || are usually more like control flow operators like ? : than they are like logical operators. There's nothing special about the way this operator is written in the field of logic. – amon Mar 4 at 20:50
  • Personally, I think this would make it harder to quickly parse longer boolean statements. I mean, we could condense anything to plain English. Quick, what's "(five plus six minus one) times ten plus twenty times two"? Or, as you probably can read more quickly "(5+6-1)*10+20*2". – Clay07g Mar 4 at 20:52
12

In short

It's historical reasons.

The long history

Many older languages created between the 50's and the end of the 60's, as well as used the logical operators that you like such as not or and and:

  • Fortran II, 1961, introduced logical operators between dots with .NOT. .AND. .OR.
  • BASIC, 1964, (although I'm not sure that it had these operators in the very first version)
  • Simula 67, used them as keywords for the more concise and mathematically inspired ¬ for not, (and=intersection) and (or=union).
  • Algol68,1968, used them as a portable alternative to ¬, and
  • Pascal, 1970,

Their modern descendants (e.g. ADA) have kept this keyword style.

You can however see that already in this first list, there was a quest for concise expressions in many languages. But the character sets in those years were not portable and the later work on the ASCII character set didn't let many of the special characters survive.

Other languages used also the concise approach but chose characters that were more lucky in the standardisation process (for example see here the rationale that lead to the inclusion of | in the ASCII character set):

  • PL/I, 1964, used & for and, | for or and ¬ for not
  • BCPL, 1967 used & for and, | for or and ~ for not. It also offered keyword alternatives. But those were not so appealing: LOGOR, LOGAND and LOGNOT
  • Finally came C, 1972, that had the incredible growth that we know. C was inspired (indirectly via B) from BCPL. It is not surpriseing that its authors, Kernighan & Ritchie, took over the & and |. But as C is system oriented these were taken as bitwise operators. K&R identified also the need to have short circuit operators for conditional expressions to know that they can skip the rest of the expression if it's already known that it's true or false (the purpose was to write concise error checking conditions). And for these logical operators, they just doubled the symbol, so && and ||

Then came C++ inspired by C, then Java inspired by C++ then JavaScript inspired from Java... and this is why nowadays so many languages have opted for the well known || and &&

P.S.: Note, that if JavaScript would have adopted and or rather than && || , it would probably have adopted begin .. end rather than { .. } , making it overall a lot more verbose than we are used to ;-)

8

C picked some operators, and most C-like languages stuck with it. Most, but not all. A few also mixed in some Basic-ish and Pascal-ish traditions.

  • C++ has equivalent tokens for these operators. The token and is parsed as &&, and or is parsed as ||. However, the use of these is highly frowned upon.

  • Perl has both an and and && operator. These behave the same but have different precedence level in the grammar, which often makes the low-precedence versions easier to use. For example, the following two statements are equivalent:

    open(my $file, '<', $filename) || die "Could not open $filename: $!";
    open my $file, '<', $filename or die "Could not open $filename: $!";
    
  • Python prefers alphabetical operator like and, and does not have a symbol version. Syntactically, the language does not belong to the C family, though.

While new languages can introduce new operators, it is not generally possible to retrofit them into an existing language. While a language evolves it must ensure that it stays backwards compatible. This is especially important for a client-side scripting language like JavaScript that cannot mandate by which engines it will be executed. Some changes are safe when they do not clash with existing syntax, but introducing new keywords is extremely tricky: you cannot retroactively outlaw code like function and() {}. This gives rise to concepts like contextual keyword, but they complicate parsers and therefore also downstream tooling.

However, JavaScript has a good story for development-time syntax extensions through build-time transpilers with things like Babel. If you want your pretty keywords you can write your code with these keywords, but let a transpiler replace them with standard JavaScript before deploying.

  • "However, the use of these is highly frowned upon." - Citation required. While it's true that hardly anyone ever uses the alternative operators in C++, I've never seen anyone who thought that they are really a bad thing. – Christian Hackl Mar 5 at 10:36
  • @ChristianHackl searching for opinions on the C iso646.h header or C++ alternative tokens usually brings up strong opinions in either direction. While I would actually prefer that syntax, I'm strongly in the “no one should ever use this” camp simply because it is an arcane, little-known feature that would bring more confusion than clarity. Mentioning such a feature without discouraging its use would have been irresponsible. If you want a citation, then the Google Styleguide says no, but that's hardly authoritative. – amon Mar 5 at 11:53
  • 2
    Yeah, the Google Styleguide is only meant for Google's own (legacy?) code and should not be taken as an appropriate styleguide for C++ in general. That misunderstanding used to pop up all the time in Stack Overflow questions. I sort of agree with your opinion on the operators, I just believe that "highly frowned upon" is speculative. I believe it's more like a total lack of interest by the community than active discouragement (compared to things like, say, goto or C-style casts). – Christian Hackl Mar 5 at 12:10
  • 2
    @ChristianHackl: The same issue comes up all the time with regard to the AP Style Guide and English language usage. Part of the intention of the AP Style Guide is to remove any element of individual style from a person's writing, so that stories by different reporters can be used interchangeably. In most contexts, however, writers should want to have a style which doesn't perfectly match everyone else. – supercat Mar 5 at 16:48
4

The biggest problem would be the backwards compatibility issues that would arise if you took a previously unreserved keyword and made it reserved. For example, in any language that does not have a symbol prefix for variables (like the "$" in PHP), you cannot easily just go add a new reserved word because older programs might have used that phrase as a variable name. In some languages, the compiler might be smart enough to infer if you are meaning a variable name versus a reserved keyword name, but that adds a lot of effort to the compiler itself.

  • Are there any existing contexts in which one could have two valid expressions separated by an alphanumeric identifier? In C that would be possible if e.g. one were to say #define foo *; one could then have two valid expressions separated by the identifier foo. I don't think that would be possible in Javascript, however, unless the identifier was preceded and followed by line breaks, in which case the keyword wouldn't be usable as an operator anyhow. – supercat Mar 5 at 16:52
  • I think JavaScript could easily be the most dangerous language to make such a change in, given its dynamic nature and no real compiler to target, just a slew of browser makers to convince of the new features. – Graham Mar 5 at 19:52
  • Fair point, but I think the issue isn't with reserved words, but rather the fact that in dynamically-programmed contexts, the fact that a piece of text isn't syntactically valid code may in and of itself be semantically significant. – supercat Mar 5 at 20:10
2

Even if the language definition specified your and and or keywords rather than the more mathy |, ||, &, and && keywords introduced by the C language folks at Bell Labs (Brian Kernighan and Dennis Ritchie of blessed memory), we'd still need more detail than and and or can give us.

 if ( expensive_function (a) && another_expensive_function (b) ) {}

skips evaluating the second expensive function if the first one comes back false. That's also important because it lets us write safe code.

 if ( a != 0 && 1.0 / a > 0.3) {} 

would sometimes throw div-by-zero if a is zero if we used & in place of &&.

But

 if ( expensive_function (a) & another_expensive_function (b) ) {}

always evaluates both functions. The distinction is important if the second function has any side-effects (like printf() for example).

Other languages have different ways of spelling && and &. But the distinction between the two still exists. E.g. in VB.net, AndAlso functions as && does in c-like languages.

SQL gets away with using AND and OR because it's a declarative language, not procedural. It's almost, but not quite, a side-effect-free language. So SQL query planners can decide which parts of anded / ored queries must be evaluated, without we programmers telling them.

  • VB handles this with its "And" and "AndAlso" operators. – Graham Mar 4 at 20:42
  • In C++ and, bitand, or, bitor are legal and working alternatives to &&,&, || and |. C has a standard header defining them as macros. So giving it as an example of how it is a problem is a bit weird. – Frax Mar 4 at 20:50
  • 1
    +1 for this Interesting contribution that highlights very well the increase precision of & and && compared to and, and the principle of the short circuit operators. One remark however: while K&R are behind the notion of short circuit, the use of the mathy symbols precedes C by 10 to 15 years, since | was already used in PL/1 begin of the 60’s and that was one of the reason that helped this rather spartiate character to end up in the ASCII character set that was made available to K&R. – Christophe Mar 5 at 8:55
  • DELETE FROM x or DROP TABLE foo is declarative and almost side-free? I don't think so. – Christian Hackl Mar 5 at 10:42
  • 1
    @ChristianHackl: The component expressions are side-effect free. The query is not. – Ben Voigt Mar 6 at 2:02
0

In general, people maintaining language standards are loath to add features that would encourage programmers to write programs that are incompatible with existing implementations except in cases where code that uses the new features could be in some meaningful way superior to anything that could perform the same task on the older implementations (or could accomplish some task that simply couldn't be done before). I don't see the addition of text-based operators like and and or as offering enough value to overcome that, as much as I like text-based operators (using text-based operators for things like integer division, modulus, and remainder operators would allow programmers to select the exact operation they need without having to kludge it).

0

There are problems with natural languages.

Just take your question as an example. If we read it carefully, as a compiler would do, the correct answer is: “But most languages do. The only exception that I remember is Pascal”.

0

It all goes back to primarily C. C was launched as a thin layer over assembly language, maintaining unsafe coding.

As you know in assembly language bit masks, bit ANDs and ORs, are important. Hence the need for the bit operators & and |. Typically:

#define A_BEZ (A_LEFT | A_CENTER | A_APPROX)

Then there were the short-cut operators and-then and or-else: && and ||, for such things like:

if (i < n && a[i] < k)

A more or less predictable choice doubling & and | seeing ++ and --.

Both schools run partly side-by-side:

  • symbolic expression operator: &&, ||, %, ~?~:~

    Advantage: mathematical (∧, ∨)

  • named expression operator: and, or, mod, if(~)~else~

    Advantage: not cryptic (and, or)

Named operators are nicer looking especially for boolean expressions, hence and and or reentered C. It is worth comparing them with Algol68 styles. An outstanding language wherein everything is a (typed) expression.

INT a := ...;                          # REF INT variable a becomes ... #
INT b := ...;
IF a < b THEN a ELSE b FI := ...;      # Assigment to a condition LHS #
(a < b | a | b ) := ...;
(node = nil | list.head | node.next ) := ...;
BOOL c = a = b OR IF i < n AND IF v[i] < a THEN b > a ELSE  a < v[i] FI;
BOOL c = a = b ∨ ( i < n ∧ v[i] < a | b > a | a < v[i]);

Above | is a separator for then/else (else-if, ELIF, had |:), FI the end-if.

One sees that Algol68 was not afraid to use mathematical symbols not apertaining to ASCII, and even a bold font for keywords and types/operators: and. In reality AND or .or. was used as even then special keyboards were rare (simple terminals rather).

In short:

&& and || were the short-cut versions of the bitwise/both-sides-logical & and |.

Some future language may well reconsider this, as also and an or appear.

  • 1
    "C was launched as a thin layer over assembly language, maintaining unsafe coding." - Isn't it rather true that C was launched as a high-level, machine-independent language to improve coding safety? – Christian Hackl Mar 5 at 10:44
  • @ChristianHackl yes "as close to the machine" though. No index checks, "everything" a pointer, a char* (even a char[80]), cross-type casts, zero terminated strings. Not as high as even a simple Pascal. But you could program everything, on really many platforms, and port the code to other platforms. Much better than assembler, though neither suited imho as teaching sample language & its constructs, nor for robust productive code. (And I do love Unix.) C led to / was the excuse for Ada for instance. Do not get me wrong, I love C. – Joop Eggen Mar 5 at 11:14
  • @ChristianHackl: Properly written programs would be safe, but any safety was the responsibility of the programmer, not the language. – supercat Mar 5 at 16:43
  • @JoopEggen: In the late 1980s, C wasn't so much a "language" as a recipe for producing a family of dialects for different platforms that used a common syntax, but with semantics adapted for each target. It's too bad that the authors of the Standard tried to treat it as a language which didn't define anything could vary between platforms, rather than recognizing that the platform-dependent behaviors were a fundamental part of the C "recipe". – supercat Mar 5 at 16:45
  • @supercat a time of very different mainframes, elite firms, very heterogeneous hardware. That an int somewhere was an 22 bits ones-complement was to be taken into account. The POSIX standard also slowly grew. What a time. – Joop Eggen Mar 6 at 7:23

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.