# Why don't more languages have the ability to compare a value to more than one other value? [closed]

Consider the following:

if(a == b or c)


In most languages, this would need to be written as:

if(a == b or a == c)


which is slightly cumbersome and repeats information.

I know my above sample syntax is slightly clunky, but I am sure there are better ways to convey the idea.

Why don't more languages offer it? Is there performance or syntax issues?

• SQL offers that: where A IN (B, C) – thursdaysgeek May 1 '14 at 18:22
• I wasn't asking for languages that offer it, or can have it, but why don't more languages offer it? Is there performance or syntax issues? – Zeroth May 1 '14 at 18:32
• to generalize @thursdaysgeek's answer, in most languages, usually you do that with set containment. (Or a list or tuple if that's easier.) It works out the same and avoids some potentially tricky syntax issues. From your example, does "b or c" mean the set "{b, c}" or is or an operator like || ? In python "b or c" means "the value of b if true, or else the value of c" – sea-rob May 1 '14 at 18:32
• Essentially this is a syntax issue. The problem at hand is having an intuitive way to disambiguate the difference between "b or c" and "b or'd with c". – YoungJohn May 1 '14 at 18:41
• It's quite hacky to special case a == b or c, and it doesn't even ŕead well IMHO. – user7043 May 1 '14 at 18:43

The syntax issue is – that it requires syntax.

Whatever syntax your language has, people using the language have to learn it. Otherwise they run the risk of seeing code and not knowing what it does. Thus it's generally considered a good thing if a language has a simple syntax that cleanly handles a lot of cases.

In your specific example, you are trying to take an infix operator (a function that takes two arguments but is written Argument1 Operator Argument2) and trying to extend it to multiple arguments. That doesn't work very cleanly because the whole point of infix operators, to the extent that there is one, is to put the operator right in between the 2 arguments. Extending to (Argument1 Operator Argument2 MagicallyClearSymbol Argument3...) doesn't seem to add a lot of clarity over Equals(Arg1,Arg2,...). Infix is also typically used to emulate mathematical conventions that people are familiar with, which wouldn't be true of an alternate syntax.

There would not be any particular performance issues associated with your idea, other than that the parser would have to deal with a grammar with another production rule or two, which might have a slight effect on the speed of parsing. This might make some difference for an interpreted or JIT compiled language, but probably not a big difference.

The bigger problem with the idea is just that making lots of special cases in a language tends to be a bad idea.

• Aside: Scala has infix operators with an arbitrary number of arguments, as infix operators are just method calls without a .. So they'd be written as arg1 op (arg2, arg3). Not exactly beautiful, but needed in some places in the context of that language. – amon May 1 '14 at 20:01
• what about if my_var in (a, b) then? isn't this more a question of using the right tool for the job? – user112358 May 1 '14 at 22:39
• Great points. The language syntax should be essentials of the language, and then you build up libraries on top of it. If the language is too cluttered up with "helpful" syntactical sugar, it becomes harder to use. Not everyone needs a == b or c while others want a == b or c but not d. IMO that's where utility functions/libraries come to the rescue. – Allan May 2 '14 at 3:34
• Perhaps what's needed is a means via which a method could specify that a call with an arbitrary number of arguments should be handled as multiple calls, with the results combined in some way. If f().Equals(a,b,c); could be evaluated as (var temp=f(); temp.Equals(a)||temp.Equals(b)||temp.Equals(c)) that syntax would be perfect, but if it's evaluated as int[] arr = {a,b,c}; f().Equals(arr); that would not be so good, especially if a new array had to be created for each call. – supercat Jun 12 '14 at 16:04

Because it's a non-problem, and solving it brings basically zero benefit, but implementing it brings non-zero cost.

Existing range-based functions and such that practically every language does offer can work perfectly well in this situation if it scales to a size where a == b || a == c won't cut it.

• +1, but I think the answer would be improved by showing one or two of those "existing range-based functions that practically every language [offers]", just so this alternative would be clearer. – Avner Shahar-Kashtan May 1 '14 at 18:57
• Can you prove that it "brings basically zero benefit, but implementing it brings non-zero cost"? – Darek Nędza May 1 '14 at 19:04
• @DarekNędza The second half should not be contentious: Every feature must be thought through, implemented, tested, documented, and supported. None of those steps are free under any reasonable metric (peoples' time, opportunity cost, complexity, monetary cost if anyone's paid to work on it, and so on). – user7043 May 1 '14 at 19:32
• @AvnerShahar-Kashtan Agreed - to me, it's not obvious how it would look in, say, java, or sh, or zsh? Ok, he may have implied 'modern' language. Groovy? – Volker Siegel May 1 '14 at 21:36
• In PHP, it'd look like in_array($a, [$b, $c,$d, $e,$f]). :P – cHao May 2 '14 at 4:58

Some languages do have such features. E.g. in Perl6 we can use Junctions, which are “superpositions” of two values:

if $a == any($b, $c) { say "yes"; } # syntactic sugar for the above if$a == $b |$c {
say "yes";
}


Junctions allow us to express operations on a set of data quite succinctly, similar to the way scalar operations distribute over collections in some languages. E.g. using Python with numpy, the comparison can be distribute over all values:

import numpy as np
2 == np.array([1, 2, 3])
#=> np.array([False, True, False], dtype=np.bool)
(2 == np.array([1, 2, 3])).any()
#=> True


However, this only works for selected primitive types.

Why are junctions problematic? Because operations on a junction distribute over the contained values, the junction object itself behaves like a proxy for method calls – something few type systems aside from duck typing can handle.

Type system problems can be avoided if such junctions are only allowed as special syntax around comparison operators. But in this case, they are limited so much that they don't add sufficient value to be added to any sane language. The same behavior could be expressed using set operations or spelling out all comparisons manually, and most languages do not believe in adding redundant syntax if there is already a perfectly fine solution.

• That particular numpy example could be rewritten clearer as 2 in [1, 2, 3]. On the other hand, if numpy has a .all() or something, the equivalent plain python is not nearly as concise. – Izkata May 2 '14 at 13:50
• @Izkata I specifically did not use set operations. While my example did use the == operator, we can also use < instead – where is your in now? Junctions are more general than set membership tests, because operations on the junction distribute over all members – (x|y).foo is x.foo|y.foo, until the junction is finally collapsed to a single value. The provided NumPy code shows an exactly equivalent but more verbose translation of the Perl6 junctions, assuming primitive types. – amon May 2 '14 at 14:01

In languages with macros, it's easy to add something like that if it's not already there. Consider Racket

(define-syntax-rule (equal-any? a b ...)
(or (equal? a b) ...))
(equal-any? "a" "b" "a")
> #t


In other languages without metaprogramming, maybe you can reformulate that as set/list membership checking perhaps:

if a ∈ {b, c}

• The first two check whether all arguments are equal; OP wants to check whether the first argument equals any of the following. Curiously, the third snippet you show does respect that. – user7043 May 1 '14 at 18:44
• @delnan Sorry I misunderstood stuff. I've edited it. – Phil May 1 '14 at 19:23

In some (popular) languages == operator is not transitive. For instance in JavaScript 0 is equal to both '' and '0', but then '' and '0' are not equal to eachother. More of such quirks in PHP.

It means that a == b == c would add another ambiguity, because it could yield a different result depending on whether it's interpreted as (a == b) & (a == c) or (a == b) & (a == c) & (b == c).

In most languages, this should be trivially achievable by writing an In function, so why make it a part of the actual language?

Linq, for example, has Contains().

Alright, for all you pedants, here's my implementation in C#:

public static bool In<T>(this T obj, params T[] values)
{
for(int i=0; i < values.Length; i++)
{
if (object.Equals(obj, values[i]))
return true;
}
return false;
}

• That operates on a run-time range of values, not a tuple as the OP's code could be expressed as. – DeadMG May 1 '14 at 18:48
• It seems like, just because its easy, doesn't mean it shouldn't be done. Its... consider construction. Why are we always having to manually write all of these basic pieces of functionality and algorithms, over and over and over and over again? – Zeroth May 1 '14 at 18:54
• @Zeroth maybe you are writing the same thing over and over again, but others tend to use the abstraction mechanisms offered by their language instead. If you see yourself writing a == b || a == c multiple times, maybe it's time for equals_any(a, {b, c}) – amon May 1 '14 at 18:56
• A "contains" implementation doesn't easily extend to cover things like if (a > (b or c)) and if (a mod (b or c) == 2). – tobyink May 1 '14 at 22:55
• Did somebody say pedants? :) It's a foreach loops, so there's no i variable. And overall it seems to be written after you've had a long day :) Because putting both return true and return false inside the loop here means there's no way it will ever make it beyond the first iteration. You're only comparing against the first value. By the way, why not use Any as @Bob suggested and simplify it into return values.Any(value => Object.Equals(obj, value)); – Konrad Morawski May 2 '14 at 8:53

"if(a == b or c)" works in most languages: if a == b or if c is not negative, null, or zero.

Complaining that it's verbose misses the point: you shouldn't be piling a dozen things into a conditional. If you need to compare one value to an arbitrary number of other values, then build a subroutine.

• Which languages make up "most"? – FrustratedWithFormsDesigner May 1 '14 at 19:46
• @FrustratedWithFormsDesigner, well, if c evaluates to a boolean, then pretty much any language can handle a == b || c :) – Brian S May 1 '14 at 20:47
• @BrianS: I assumed the OP meant the literal syntax if(a == b or c). I need to take a break, I think... :P – FrustratedWithFormsDesigner May 1 '14 at 21:15
• @FrustratedWithFormsDesigner Lisp! ...huh?... :) – Volker Siegel May 1 '14 at 21:38
• This really misses the point of the question. if (a == b or c) is pseudo-code to check if a is equal to b, or a is equal to c. It's not meant to check that c is non-zero. – hvd May 2 '14 at 9:09

Usually, you want to keep your syntax at a minimum and instead allow such constructs to be defined in the language itself.

For example, in Haskell you can convert any function with two or more arguments into an infix operator using backticks. This allows you to write:

if a elem [b, c] then ... else ...


where elem is just a normal function taking two arguments - a value and a list of values - and checks whether the first is an element of the second.

What if you want to use and instead of or? In Haskell, you can just use the following instead of waiting for the compiler vendor to implement a new feature:

 if all (== a) [b, c] then ... else ...

• Why would one want to keep the syntax to a minimum? What exactly is the trade-off going on there? Don't make proclamations like that without backing arguments. ;) – Zeroth May 1 '14 at 22:40

Some languages do offer this -- to an extent.

Maybe not as your specific example, but take for example a Python line:

def minmax(min, max):
return max > value > min

inbounds = minmax(5, 15)
inbounds(7) ##returns True
inbounds(3) ##returns False
inbounds(18) ##returns False


So, some languages are fine with multiple comparisons, as long as you're expressing it correctly.

Unfortunately, it doesn't work quite like you'd expect it to for comparisons.

>>> def foo(a, b):
...         return value == a or b
...
>>> tester = foo(2, 4)
>>> tester(3)
4
>>> tester(2)
True
>>> tester(4)
4
>>>


"What do you mean it returns either True or 4?" -- the hire after you

One solution in this case, at least with Python, is to use it slightly differently:

>>> def bar(a, b):
...     def ans(val):
...             return val == a or val == b
...     return ans
...
>>> this = bar(4, 10)
>>> this(5)
False
>>> this(4)
True
>>> this(10)
True
>>> this(9)
False
>>>


EDIT: The following would also do something similar, again in Python...

>>> def bar(a, b):
...             return val in (a, b)
...
>>> this = bar(3, 5)
>>> this(3)
True
>>> this(4)
False
>>> this(5)
True
>>>


So, whichever language you're using, it may not be that you cannot do it, just that you must first take a closer look at how the logic actually works. Typically it's just a matter of knowing what you're 'actually asking' the language to tell you.

The indexOf method, used on an Array, that quite all languages have, allows to compare a value to several others, so i guess a special operator doesn't make much sense.

In javascript that would write :

if ( [b, c].indexOf(a) != -1 ) { ....  }


You ask why can't we do this: if(a == b or c)

Python does this very efficiently, in fact, most efficiently with set:

if a in set([b, c]):
then_do_this()


For membership testing, 'set' checks that the element's hashes are the same and only then compares for equality, so the elements, b and c, must be hashable, otherwise a list directly compares for equality:

if a in [b, c]:
then_do_this()


APL-style languages allow you to compare a scalar with each element in a vector in a single operation. This produces a Boolean vector. For an example, I'd like to shamelessly promote my minimally-featured apl calculator, inca (online interpreter).

   a<5
5
b<4
4
c<5
5
a=b c
0 1


To reduce this to a single value, we can do an inclusive or by summing and checking for nonzero.

   0!+/a=b c
1
c<6
6
0!+/a=b c
0


So, as the other answers say, the issue is syntax. To some extent, syntax solutions have been found, at the perhaps heavy cost of learning the array paradigm.