Messages from Usenet group comp.lang.idl-pvwave, compiled by Paulo Penteado
Using bitwise OR with non-integers; and using !NULL in expressions
Hello all, I found to my delight that bitwise OR on strings evaluates left-to-right, with empty strings counting as FALSE, which lets me (partially) adapt a useful idiom for default values from some other language: my_value = table_value OR default_value which to my mind is much more readable than (and avoids the repetition of) the equivalent: my_value = table_value ? table_value : default_value or (horror of horrors): IF table_value NE '' THEN BEGIN my_value = table_value ENDIF ELSE BEGIN my_value = default_value ENDELSE It is perhaps strange that it should work, but I was happy to discover this. Trying to see how far this useful idiom could be stretched, I tried a couple of other variants: IDL> print, 0.0 or 42.0 42.0000 IDL> print, 1.2 or 42.0 1.20000 So the idiom carries over to floating-point numbers also. Excellent. IDL> print, 1 or 42.0 1.00000 Huh? Why did my integer become a float? IDL> print, complex(0,0) or 42 ( 42.0000, 0.00000) Okay, so IDL converts both sides to the narrowest type wide enough to accomodate both sides. If you're going to do bitwise OR, this makes sense. If you're going to return one side or the other, it is less useful, IMO. IDL> print, 0 or 'foo' % Type conversion error: Unable to convert given STRING to Long. % Detected at: $MAIN$ 0 Well, for an operator advertised to do bitwise OR on integers, trying to convert string to integer is perhaps not unreasonable. IDL> print, !NULL or 'foo' % Variable is undefined: <UNDEFINED>. % Execution halted at: $MAIN$ But in this case converting the type is a bad idea: !NULL is false, just like the empty string is, and I would have hoped that this should evaluate to 'foo' without error. The same goes for this case: IDL> print, 'foo' or !NULL % Variable is undefined: <UNDEFINED>. % Execution halted at: $MAIN$ What I'd like to see (as a minimal change from today's behaviour) is logic something like this: IF <both sides are integer types> THEN BEGIN RETURN, <bitwise or in widest type necessary> ENDIF ELSE BEGIN RETURN, LHS ? LHS : RHS ENDELSE In this case, type conversion occurs only to match up the width of integer arguments. In all other cases, type conversion is unnecessary and only the truth or falsity of the arguments counts. (This would break >> 0 OR '12' << relative to today's behaviour -- but that is fixable.) On the other hand, the whole behaviour of OR for non-integers has little to do with BITWISE operations, and it makes integers behave very differently from other types for this operator, which violates the principle of least surprise. The consistent and logical behaviour would be to attempt conversion of ANY LHS or RHS to an integral type and do bitwise operations on the results. This would certainly break the idiom for strings and floating-point types. If this were to happen, I would _really_ like to have the logical || work for this idiom, instead. I.e. it would evaluate to its left hand side if it were (logially) true, and its right hand side otherwise. Today, it returns 0 or 1 which is useful only for tests, not for values. This could break existing code if the code relied on || raising exceptions when presented with values without obvious truth or falsity (e.g. arrays) That way, the idiom on the first line could work without regard for the type of the RHS: my_value = compute(arg) || 42 my_value = compute(arg) || 42.0 would both behave the same, i.e. the returned value is used if it is true, and 42 is used otherwise. The operator should short-circuit, i.e. the RHS is evaluated only if the LHS is false: my_value = cheap_approximation(x) || expensive_approximation(x) where expensive_approximation() is called only if cheap_approximation() produced a FALSE value: 0, 0.0, '', or !NULL. Finally, this mind-blowing exercise for the reader (see if you can guess the result before asking IDL): print, indgen(5) or complex(3,1) --T