1. literals
We should also allow literals that are BigInteger and BigDecimal.
In ASTNumberLiteral , if the "new Integer" statement throws a
NumberFormatException, (which it does on overflow as well as
gobbleygook), then do a "new BigInteger (getFirstToken().image)"
and don't catch it's NumberFormatException.
Likewise for Will's upcoming ASTFloatingPointLiteral.

Now that we have it available, should the number literals also
go through Peter's MathUtils.typeConvert() to get to the 'smallest'
Number? Then they can match setXXX(YYY) better, if e.g. there's
a setXXX(short) and the literal is small like 3.


2. class changing
One gotcha is that the class of a VTL reference can (and often will)
change after doing some math. The compartors are fine since they
always return Boolean, but the operators

$foo.myProperty
#set ($foo = $foo + 3)
$foo.myProperty ## error: setmyProperty etc not found in any Number

then $foo will end up as the 'smallest' Number class holding its value.
This will be quite confusing if $foo originally pointed to
something else entirely which happened to implement TemplateNumber.
The above example is condensed, there would usually be lots of
interleaved code allowing the template writer to forget.

It makes me wonder if references from the context should be immutable.
The reference, not the object, so that the #set above would be the error.

I guess the best/only thing to do is document this behavior well
and encourage the use of #set ($bar = $foo + 3) when $foo is
not a Number.

I don't want to suggest some sort of TemplateMath interface to
signal returning the original class, esp due to the problem of
both sides of the expression being TemplateNumbers - which to
return.

So, should ASTSetDirective log a warning in this case?

  if (left.jjtGetNumChildren() == 0)
  {
      if (! left.getClass().equals( value.getClass() ) ) {
          rsvc.warn("...");
      }
      context.put( leftReference, value);
  }
  else
  {
      left.setValue(context, value);
  }


3. widening
Next I followed the call chain for the else part above (left.setValue),
to see how things worked. This is invoked for something like:

#set ($foo.bar = 3)

If you have Foo.setBar(BigInteger) but don't have Foo.setBar(int)
or similar then the above won't work because the Byte 3 won't widen
to BigInteger (or BigDecimal).
The only widening is among primitive types or their corresponding
classes. In velocity.log you get "$foo.bar is not a valid reference".
Perhaps log a warning here?

If it's an expression of two Integers that overflow into BigInteger,
then the Foo.setBar(int) you expected to work won't because
the result is now BigInteger, not an overflowed Integer.
Perhaps log a warning here?

I don't see any way around this, because for the widening to
work, the formal argument of setBar() must be a primitive type.
(See o.a.v.util.introspection.ClassMap and MethodMap.)
Fine, just pointing it out. We need to document that when someone
writes a setBar(BigInteger) they should also provide setBar(long)
and likewise for BigDecimal/double.


Rambling a bit, but hopefully clear enough.
I'll leave the coding to you all while I'm gone next week.
I'll help with anything leftover or something new when I get back.

John Allison
[EMAIL PROTECTED]

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to