Ever since I started programming properly using good old VB6
and up until present day, I often still get burned (and just have) by this in programming:
if x == something or x == somethingelse
I often end up writing:
if x == something or somethingelse
Just out of pure interest, does any langauge/langu开发者_如何学运维ages out there support this?
Python does, kind of:
if x in [something, somethingelse]:
...
in
simply checks whether an element occurs in a given list. Similarly, in Haskell:
if x `elem` [something, somethingelse] then ...
I suppose that this can be done in most languages that allow for expressions of list type.
SQL has an in
operator: x in (something, somethingelse)
, and there are many languages where you can implement something similar.
In c#, for instance, I use a custom extension method: if (x.In("something", "somethingelse"))...
edit here's the source of my c# extension method:
public static bool In<T>(this T item, params T[] test_values) {
foreach (T test_value in test_values)
{
if (test_value.Equals(item))
{
return true;
}
}
return false;
}
In many programming languages you can do something like this:
myArray[something, somethingElse].Contains(x)
... but my guess is it would perform slightly worse.
The Icon programming language supports this idiom beautifully. Icon was designed by Ralph Griswold, who had already designed SNOBOL, and it's whole evaluation model is built on success or failure. Everything composes, and in principle every expression can produce multiple results. You can write such things as
if x == (something | somethingelse) then write("Goodie!")
Here's the evaluation model:
- First you evaluate the expression in parentheses and get
something
- Then you compare
something
tox
- If they're not equal, the expression fails, and the evaluation engine automatically backtracks.
- During backtracking, evaluation of the parenthesized expression is resumed, and it succeeds again! This time it produces
somethingelse
. - Let's suppose this comparison succeeds. Then the body of the
if
is evaluated and the program writes to standard output.
Here's another interesting scenario: every comparison either succeeds or fails, and if it succeeds, it returns its right-hand argument. So you can do bounds checking with
lo <= x < limit
This expression parenthesizes thusly:
(lo <= x) < limit
And so if lo
is bigger than x
, the parenthesized expression fails, and so the whole thing fails. (An ordinary expression fails if any part of it fails.) But if lo
is at most x
, then lo <= x
succeeds and returns x
. Next of course, the machine compares x < limit
, and if that succeeds, the whole thing succeeds.
Icon was a beautifully consistent language, wonderfully easy to use, and underappreciated. But it was never well integrated with the operating system, and by the time they had a version that played well with Unix, Icon had already lost its chance at getting mindshare. But all language designers could learn a lot by studying it.
R.I.P.
In languages with a "switch" operator, you can do:
switch (x)
{
case 1:
case 2:
{
// do whatever
break;
}
default:
{
// else case
break;
}
}
It's a bit verbose, but in C you could hide it in a macro or in C++ perhaps a template.
MATLAB has a couple ways to handle the second form you list above:
if any(x == [something somethingelse]) ...
%# OR
if ismember(x,[something somethingelse]) ...
Perl: $foo ~~ ['string',$number,qr/regex/]
If
A in [x, y, z]
is considered a valid solution then the function
in(A, x, y, z)
should be considered a valid solution too, especially for a language that allow operator overloading so that cmp(A, x, y, z) could be mapped to
A in x y z
Discussions so far have dwelt on
if (A == x or y or z).
What about the case of
if (A == x and y and z).
Therefore, we would use varargs, a feature found in c, c++, c# and java5.
Let's use java to illustrate.
boolean or(String lhs, String... rhs){
for(String z: rhs){
if (lhs.equals(z) return true;
}
return false;
}
boolean and(String lhs, String... rhs){
for(String z: rhs){
if (!lhs.equals(z) return false;
}
return true;
}
Varargs allow you to define a single function that takes in a variable number of arguments so that you could use the same method to compare
or (A, x)
or (A, x, y)
or (A, x, y, z)
However, the above is defined only for String comparisons, so that we would have to create a pair of methods for each arg type. But then in Java 5 there is generics.
<T extends Comparable<T>>boolean or(T lhs, T... rhs){
for(T z: rhs){
if (lhs.compareTo(z)==0) return true;
}
return false;
}
<T extends Comparable<T>>boolean and(T lhs, T... rhs){
for(T z: rhs){
if (lhs.compareTo(z)!=0) return false;
}
return true;
}
So now you can do comparisons for any type that implements comparable interface.
and(stringA, stringx, stringy)
or(dateA, datex)
Too bad, Java does not allow operator overloading so that we could do
stringA && stringx, stringy
dateA || datex, datey, datez
In c++, I have never attempted operator overloading with varargs to even know if it is possible.
Revisit: However, revisiting this hours later,
We could define a class
public class <T extends Comparable<T>> Comparigator{
public Comparigator(T lhs){
this.lhs = lhs;
}
final private T lhs;
static public <T extends Comparable<T>> Comparigator is(T lhs){
return (T)new Comparigator(lhs);
}
public boolean inAny(T... rhs){
for(T z: rhs){
if (this.lhs.compareTo(z)==0) return true;
}
return false;
}
public boolean inAll(T... rhs){
for(T z: rhs){
if (this.lhs.compareTo(z)!=0) return false;
}
return true;
}
public boolean gtAny(T... rhs){
for(T z: rhs){
if (this.lhs.compareTo(z)>0) return true;
}
return false;
}
public boolean gtAll(T... rhs){
for(T z: rhs){
if (this.lhs.compareTo(z)<=0) return false;
}
return true;
}
}
Now, we don't need operator overloading at all and we can do
import Comparigator;
.....
is(A).inAny(x,y,z); // or
is(A).inAll(w,x,y,z); // and
is(B).gtAny(k,l,m);
is(C).gtAll(j,k);
And we could expand it and we could do inany, inall, gtany, gtall, ltany, ltall, etc by expanding the comparison functionality.
精彩评论