OperandResolver is your friend. This utility encapsulates most of the logic needed to convert input arguments to concrete types. See the implementation of basic numeric functions in NumericFunction.

A prototype of a UDF that operates on two numbers looks as follows:



   static class H2_ZFactor implements FreeRefFunction {

        @Override
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
            if (args.length != 2) {   // Must be given two arguments.
                return ErrorEval.VALUE_INVALID;
            }

            double var1, var2, result;
            try {
ValueEval v1 = OperandResolver.getSingleValue(args[0], ec.getRowIndex(), ec.getColumnIndex()); ValueEval v2 = OperandResolver.getSingleValue(args[1], ec.getRowIndex(), ec.getColumnIndex());

                var1  = OperandResolver.coerceValueToDouble(v1);
                var2  = OperandResolver.coerceValueToDouble(v2);

                result = calculateH2_ZFactor( var1, var2 ) ;

// Excel's implementation of floating-point numbers does not support the notion
                // of Not-a-Number (NaN) and Positive/Negative Infinities.
// The code must check the result and return ErrorEval.NUM_ERROR.
                checkValue(result);
            } catch (EvaluationException e) {
                return e.getErrorEval();
            }

            return new NumberEval( result ) ;
        }

        /**
* @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
         */
static final void checkValue(double result) throws EvaluationException {
            if (Double.isNaN(result) || Double.isInfinite(result)) {
                throw new EvaluationException(ErrorEval.NUM_ERROR);
            }
        }

        double calculateH2_ZFactor(double var1, double var2){
            return var1*var2;
        }
    }

Regards,
Yegor

On 10/6/2010 8:16 AM, Jon Svede wrote:
I was able to set up my own UDF but I noticed something that I can't explain
clearly, I am hoping someone can help me.  This is again related to documenting
this feature.

In my FreeRefFunction implementation class, for the array of ValueEval objects,
I get a mix of things.  In some cases I get an instance of NumberEval but in
others I've gotten a LazyRefEval.  This confused me for a minute, then I
realized I could cast it to RefEval, call the getInnerType() method which could
then be cast to the NumberEval.

This seems a little confusing, am I doing this right?  Or is there a better
way?  Here is the code that I wrote:

   @Override
   public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) 
{
     if (args.length != 2 ) {
       return ErrorEval.VALUE_INVALID;
     }

     NumberEval numEval1 = getNumberEval( args[0] );
     NumberEval numEval2 = getNumberEval(args[1]) ;

     double var1 = numEval1.getNumberValue() ;
     double var2 = numEval2.getNumberValue() ;

     double result = calculateH2_ZFactor( var1, var2 ) ;

     return new NumberEval( result ) ;
   }

   /**
    * In order to deal with my functions I need two numbers and they
    * get passed differently depending on where they are called from.  This
    * function encapsulates the steps needed to convert the input to the
    * NumberEval object. (this may not even be right)
    *
    * @param vEval
    * @return
    */
   private NumberEval getNumberEval( ValueEval vEval ) {
     if( vEval != null ) {
       if( vEval instanceof RefEval ) {
         RefEval rEval = (RefEval)vEval ;
         return( NumberEval)rEval.getInnerValueEval() ;

       } else if( vEval instanceof NumberEval ) {
         return (NumberEval)vEval ;
       }
     }

     return null ;
   }

It's the getNumberEval() method where all this casting happens and I think that
has to be wrong.

If it's not wrong, is there an explanation I can provide?

Another question is, I assume that the implementation of the evaluate() method
does not throw any exceptions, rather the values from ErrorEval should be used
to express a problem?

Thanks,

Jon




---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]




---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to