The point of having static typing is the ability to prove statically that your program is correct with regard of types (note: not completely correct in all senses). If you have a static type system throughout, you can detect type errors most of the time.
If you only have partial type information, you can only check the small pieces of a call graph where type info happens to be complete. But you have spent time and effort to specify type information for incomplete parts, where it can't help you but could give a false sense of security.
To express type information, you need a part of language which cannot be excessively simple. Soon you'll find out that info like int
is not enough; you'll want something like List<Pair<Int, String>>
, then parametric types, etc. It can be confusing enough even in the rather simple case of Java.
Then, you'll need to handle this information during translation phase and execution phase, because it's silly to only check for static errors; the user is going to expect that the type constraints always hold if specified at all. Dynamic languages are not too fast as they are, and such checks will slow the performance down even more. A static language can spend serious effort checking types because it only does that once; a dynamic language can't.
Now imagine adding and maintaining all of this just so that people sometimes optionally used these features, only detecting a small fraction of type errors. I don't think it's worth the effort.
The very point of dynamic languages is to have a very small and very malleable framework, within which you can easily do things that are much more involved when done in a static language: various forms of monkey-patching that are used for metaprogramming, mocking and testing, dynamic replacement of code, etc. Smalltalk and Lisp, both very dynamic, took it to such an extreme as to ship environment images instead of building from source. But when you want to ensure that particular data paths are type-safe, add assertions and write more unit tests.
Update from 2020: Some dynamic languages now support partial typing of sorts. Python allows type hints, to be used by external tools like mypy
. TypeScript allows mixing with type-oblivious JavaScript. Still, the points above mostly hold.
The D programming language and DMC's extension to C and C++ did support these operators (all 14 combinations of them), but interestingly, D is going to deprecate these operators, mainly because
- what exactly is
a !< b
? It is a>=b || isNaN(a) || isNaN(b)
. !<
is not the same as >=
, because NaN !< NaN
is true while NaN >= NaN
is false. IEEE 754 is hard to master, so using a !< b
to will just cause confusion over NaN handling — you can search for such operators in Phobos (D's standard library), and quite a number of use has comments beside it to remind the readers NaN is involved,
- therefore, few people will use it, even if such operators exist like in D,
- and one have to define 8 more tokens for these seldomly used operators, which complicates the compiler for little benefit,
- and without those operators, one could still use the equivalent
!(a < b)
, or if one likes to be explicit, a >= b || isNaN(a) || isNaN(b)
, and they are easier to read.
Besides, the relations (≮, ≯, ≰, ≱) are seldomly seen in basic math, unlike !=
(≠) or >=
(≥), so it's hard to understand for many people.
These are probably also the reasons why most languages do not support them.
Best Answer
Operators are just functions under funny names, with some special syntax around.
In many languages, as varied as C++ and Python, you can redefine operators by overriding special methods of your class. Then standard operators (e.g.
+
) work according to the logic you supply (e.g. concatenating strings or adding matrices or whatever).Since such operator-defining functions are just methods, you can pass them around as you would a function:
Other languages allows you to directly define new operators as functions, and use them in infix form.
Unfortunately, I'm not sure if PHP supports anything like that, and if supporting it would be a good thing. Use a plain function, it's more readable than
$foo $operator $bar
.