# [erlang-questions] erlang:max/2 and erlang:min/2

Richard O'Keefe ok@REDACTED
Mon Sep 13 04:43:55 CEST 2010

```On Sep 11, 2010, at 11:53 AM, Nicholas Frechette wrote:

> This is fairly standard as far as I know in languages without strong typing in function arguments (when that is the case, usually coercion happens which hides this behavior from you).
> For example in ruby:
> >> [1, 1.0].min
> => 1
> >> [1.0, 1].min
> => 1.0

The traditional retort to this is "And if all your friends jumped off
a cliff, would you copy that too?"
>
> For these languages (and erlang), order DOES matter.

And all that means is that they are buggy too.

>
> This isn't unlike a naive implementation of min/max in C++:
> #define max(A, B) A >= B ? A : B

Er, that is a couple of steps of beginnerness _below_ "naive".
#define max(A, B) ((A) >= (B) ? (A) : (B))
is normally required, and of course the preferred method in C++
is
template <typename T>
T max(T a, T b) {
return a >= b ? a : b;
}
for obvious reasons.
>
> However, even using c++0x:
> auto SomeResult = max(1, 1.0); // what happens here? what is the type of SomeResult? (float) See note below
> auto SomeResult = max(1.0, 1); // what happens here? what is the type of SomeResult? (float) See note below

What happens here is quite irrelevant to dynamically typed languages.
The if-then-else operator has to return a result of *some* definite type,
so there really are only two choices for it.
Either it demands that both choices be the same type,
or else it has to convert at least one of them.

This has no significance whatever for a language that *doesn't* require
all arms of an if to have the same type and *doesn't* have to convert.
>
> *** Note below (really a side note, you can skip this) ***
> The 'ternary' operator is special (in C/C++). In the case above, both A and B can't be of different types.

I think "can't" was meant to be "can".

> The type will be coerced to a common base type only if possible, otherwise compilation will fail.
> See for details: http://msdn.microsoft.com/en-us/library/e4213hs1%28VS.71%29.aspx (applies to other compilers as well)
> The ternary operator can also be used as an l-value (for fun and profit) :)

NOT IN STANDARD C OR C++ IT CANNOT!

> ((A >= B) ? A : B) = 123; // Don't do this.. otherwise your coworkers will want to kill me for teaching you
> ***

One reason they will be displeased with you is that most compilers reject this.
A typical error message:
"foo.c", line 2: warning: conditional expression is not a valid lvalue

>
> In C++ at least, both types will be converted to a common base type with the ternary operator or you'll traditionally write functions which will coerce the arguments for you in order to use hardware specific instructions to do the selection:
> max(A,B) becomes 2 instructions for floats/doubles (on powerpc, same for min): C = A - B, C >= 0 ? B : A (powerpc has an instruction to compare a float against zero and select the result (fsel))

On a SPARC or a Pentium or an ARM, it would be
[assume A is in register x]
[assume B is in register y]
[assume result is wanted in register x]
compare x with y		one compare instruction
move y to x if x < y		one conditional move

It is not clear to me how this is supposed to be relevant to Erlang,
which has to deal with mixed integer/float comparisons, or to the
question of how you implement max/2 and min/2 so that they satisfy
the laws that a programmer *ought* to be able to take for granted.

C and C++ can get away with (user-provided) definitions that convert
basically because they can't have arrays whose elements are of varying
types, so if you do
auto x = a[0];
for (int i = 1; i < n; i++) x = max(x, a[i]);
there _can't_ be any problems introduced by conversion, because
all the a[i] must be the *same* type.

But in Erlang, the elements of a list CAN be of different types.

Intuitions based on experience with strongly typed languages
should simply be banned.  Any time it is intentional, an explicit
coercion can be provided by the programmer.

Intuitions based on experience with weakly typed languages
(C, C++, Java, C#) would mislead you into thinking that operations
that don't actually obey the mathematical laws they are supposed
to are OK because thanks to the all-elements-of-an-array-are-the-
same-type setup, uses of < and max DO obey the laws in question.
(Sorting a floating-point array is unproblematic in C
*IF* (1) there is at most one -infinity
(2) there is at most one +infinity
(3) there are no NaNs
(4) either you don't care about the order of -0 and +0
or they don't both occur.
Sorting a mixed integer/float array just can't happen.)

```